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

Commit 1d1ed0cd authored by Mihai Popa's avatar Mihai Popa
Browse files

[Magnifier - 14] Follow finger instead of cursor

This CL makes the magnifier follow the finger rather than the cursor in
text editing. Hence, the magnifier's movement becomes horizontally
smooth, rather than only jumping at the same time with the cursor.
Vertically it remains stable relative to the current line.

Bug: 70508649
Test: bit CtsWidgetTestCases:android.widget.cts.MagnifierTest
Change-Id: I7e06a7064f0a413379b30c5e2d11ee85d2ad3720
parent 606c532d
Loading
Loading
Loading
Loading
+9 −8
Original line number Diff line number Diff line
@@ -4632,7 +4632,7 @@ public class Editor {
            return 0;
        }

        protected final void showMagnifier() {
        protected final void showMagnifier(@NonNull final MotionEvent event) {
            if (mMagnifier == null) {
                return;
            }
@@ -4658,9 +4658,10 @@ public class Editor {

            final Layout layout = mTextView.getLayout();
            final int lineNumber = layout.getLineForOffset(offset);
            // Horizontally snap to character offset.
            final float xPosInView = getHorizontal(mTextView.getLayout(), offset)
                    + mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
            // Horizontally move the magnifier smoothly.
            final int[] textViewLocationOnScreen = new int[2];
            mTextView.getLocationOnScreen(textViewLocationOnScreen);
            final float xPosInView = event.getRawX() - textViewLocationOnScreen[0];
            // Vertically snap to middle of current line.
            final float yPosInView = (mTextView.getLayout().getLineTop(lineNumber)
                    + mTextView.getLayout().getLineBottom(lineNumber)) / 2.0f
@@ -4855,11 +4856,11 @@ public class Editor {
                case MotionEvent.ACTION_DOWN:
                    mDownPositionX = ev.getRawX();
                    mDownPositionY = ev.getRawY();
                    showMagnifier();
                    showMagnifier(ev);
                    break;

                case MotionEvent.ACTION_MOVE:
                    showMagnifier();
                    showMagnifier(ev);
                    break;

                case MotionEvent.ACTION_UP:
@@ -5213,11 +5214,11 @@ public class Editor {
                    // re-engages the handle.
                    mTouchWordDelta = 0.0f;
                    mPrevX = UNSET_X_VALUE;
                    showMagnifier();
                    showMagnifier(event);
                    break;

                case MotionEvent.ACTION_MOVE:
                    showMagnifier();
                    showMagnifier(event);
                    break;

                case MotionEvent.ACTION_UP:
+35 −6
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.view.PixelCopy;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewParent;

import com.android.internal.util.Preconditions;

@@ -44,6 +45,8 @@ public final class Magnifier {
    private static final int NONEXISTENT_PREVIOUS_CONFIG_VALUE = -1;
    // The view to which this magnifier is attached.
    private final View mView;
    // The coordinates of the view in the surface.
    private final int[] mViewCoordinatesInSurface;
    // The window containing the magnifier.
    private final PopupWindow mWindow;
    // The center coordinates of the window containing the magnifier.
@@ -87,6 +90,8 @@ public final class Magnifier {
                com.android.internal.R.dimen.magnifier_height);
        mZoomScale = context.getResources().getFloat(
                com.android.internal.R.dimen.magnifier_zoom_scale);
        // The view's surface coordinates will not be updated until the magnifier is first shown.
        mViewCoordinatesInSurface = new int[2];

        mWindow = new PopupWindow(context);
        mWindow.setContentView(content);
@@ -120,9 +125,34 @@ public final class Magnifier {
        configureCoordinates(xPosInView, yPosInView);

        // Clamp startX value to avoid distorting the rendering of the magnifier content.
        final int startX = Math.max(0, Math.min(
        // For this, we compute:
        // - zeroScrollXInSurface: this is the start x of mView, where this is not masked by a
        //                         potential scrolling container. For example, if mView is a
        //                         TextView contained in a HorizontalScrollView,
        //                         mViewCoordinatesInSurface will reflect the surface position of
        //                         the first text character, rather than the position of the first
        //                         visible one. Therefore, we need to add back the amount of
        //                         scrolling from the parent containers.
        // - actualWidth: similarly, the width of a View will be larger than its actually visible
        //                width when it is contained in a scrolling container. We need to use
        //                the minimum width of a scrolling container which contains this view.
        int zeroScrollXInSurface = mViewCoordinatesInSurface[0];
        int actualWidth = mView.getWidth();
        ViewParent viewParent = mView.getParent();
        while (viewParent instanceof View) {
            final View container = (View) viewParent;
            if (container.canScrollHorizontally(-1 /* left scroll */)
                    || container.canScrollHorizontally(1 /* right scroll */)) {
                zeroScrollXInSurface += container.getScrollX();
                actualWidth = Math.min(actualWidth, container.getWidth()
                        - container.getPaddingLeft() - container.getPaddingRight());
            }
            viewParent = viewParent.getParent();
        }

        final int startX = Math.max(zeroScrollXInSurface, Math.min(
                mCenterZoomCoords.x - mBitmap.getWidth() / 2,
                mView.getWidth() - mBitmap.getWidth()));
                zeroScrollXInSurface + actualWidth - mBitmap.getWidth()));
        final int startY = mCenterZoomCoords.y - mBitmap.getHeight() / 2;

        if (xPosInView != mPrevPosInView.x || yPosInView != mPrevPosInView.y) {
@@ -169,10 +199,9 @@ public final class Magnifier {
            posX = xPosInView;
            posY = yPosInView;
        } else {
            final int[] coordinatesInSurface = new int[2];
            mView.getLocationInSurface(coordinatesInSurface);
            posX = xPosInView + coordinatesInSurface[0];
            posY = yPosInView + coordinatesInSurface[1];
            mView.getLocationInSurface(mViewCoordinatesInSurface);
            posX = xPosInView + mViewCoordinatesInSurface[0];
            posY = yPosInView + mViewCoordinatesInSurface[1];
        }

        mCenterZoomCoords.x = Math.round(posX);