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

Commit d931a476 authored by Shu Chen's avatar Shu Chen
Browse files

Supports dynamic height for the new magnifier.

And also limits the pre-magnified line height:
 - If the text line height is too big, don't show the magnifier.
 - If the text line height is too small, enlarges the zoom factor so
   that the magnified text can be seen clearly.

Bug: 77791703, 148181186
Test: locally verified.
Change-Id: I4cf56e0a54fda6b23dafe153040fe5ba206f5f1f
parent 8a48bc0b
Loading
Loading
Loading
Loading
+38 −6
Original line number Diff line number Diff line
@@ -83,6 +83,7 @@ import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.ActionMode.Callback;
import android.view.ContextMenu;
@@ -394,6 +395,19 @@ public class Editor {
    // Specifies whether the new magnifier (with fish-eye effect) is enabled.
    private final boolean mNewMagnifierEnabled;

    // Line height range in DP for the new magnifier.
    static private final int MIN_LINE_HEIGHT_FOR_MAGNIFIER = 20;
    static private final int MAX_LINE_HEIGHT_FOR_MAGNIFIER = 32;
    // Line height range in pixels for the new magnifier.
    //  - If the line height is bigger than the max, magnifier should be dismissed.
    //  - If the line height is smaller than the min, magnifier should apply a bigger zoom factor
    //    to make sure the text can be seen clearly.
    private int mMinLineHeightForMagnifier;
    private int mMaxLineHeightForMagnifier;
    // The zoom factor initially configured.
    // The actual zoom value may changes based on this initial zoom value.
    private float mInitialZoom = 1f;

    Editor(TextView textView) {
        mTextView = textView;
        // Synchronize the filter list, which places the undo input filter at the end.
@@ -440,8 +454,6 @@ public class Editor {
    private Magnifier.Builder createBuilderWithInlineMagnifierDefaults() {
        final Magnifier.Builder params = new Magnifier.Builder(mTextView);

        // TODO: supports changing the height/width dynamically because the text height can be
        // dynamically changed.
        float zoom = AppGlobals.getFloatCoreSetting(
                WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, 1.5f);
        float aspectRatio = AppGlobals.getFloatCoreSetting(
@@ -454,13 +466,20 @@ public class Editor {
            aspectRatio = 5.5f;
        }

        mInitialZoom = zoom;
        mMinLineHeightForMagnifier = (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, MIN_LINE_HEIGHT_FOR_MAGNIFIER,
                mTextView.getContext().getResources().getDisplayMetrics());
        mMaxLineHeightForMagnifier = (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, MAX_LINE_HEIGHT_FOR_MAGNIFIER,
                mTextView.getContext().getResources().getDisplayMetrics());

        final Layout layout = mTextView.getLayout();
        final int line = layout.getLineForOffset(mTextView.getSelectionStart());
        final int sourceHeight =
            layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line);
        // Slightly increase the height to avoid tooLargeTextForMagnifier() returns true.
        int height = (int)(sourceHeight * zoom) + 2;
        int width = (int)(aspectRatio * height);
        final int height = (int)(sourceHeight * zoom);
        final int width = (int)(aspectRatio * Math.max(sourceHeight, mMinLineHeightForMagnifier));

        params.setFishEyeStyle()
                .setSize(width, height)
@@ -4902,6 +4921,12 @@ public class Editor {
        }

        private boolean tooLargeTextForMagnifier() {
            if (mNewMagnifierEnabled) {
                Layout layout = mTextView.getLayout();
                final int line = layout.getLineForOffset(getCurrentCursorOffset());
                return layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line)
                        >= mMaxLineHeightForMagnifier;
            }
            final float magnifierContentHeight = Math.round(
                    mMagnifierAnimator.mMagnifier.getHeight()
                            / mMagnifierAnimator.mMagnifier.getZoom());
@@ -5111,6 +5136,13 @@ public class Editor {
                    int lineRight = (int) layout.getLineRight(line);
                    lineRight += mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
                    mMagnifierAnimator.mMagnifier.setSourceHorizontalBounds(lineLeft, lineRight);
                    final int lineHeight =
                            layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line);
                    float zoom = mInitialZoom;
                    if (lineHeight < mMinLineHeightForMagnifier) {
                        zoom = zoom * mMinLineHeightForMagnifier / lineHeight;
                    }
                    mMagnifierAnimator.mMagnifier.updateSourceFactors(lineHeight, zoom);
                    mMagnifierAnimator.mMagnifier.show(showPosInView.x, showPosInView.y);
                } else {
                    mMagnifierAnimator.show(showPosInView.x, showPosInView.y);
+75 −8
Original line number Diff line number Diff line
@@ -89,7 +89,7 @@ public final class Magnifier {
    // The width of the window containing the magnifier.
    private final int mWindowWidth;
    // The height of the window containing the magnifier.
    private final int mWindowHeight;
    private int mWindowHeight;
    // The zoom applied to the view region copied to the magnifier view.
    private float mZoom;
    // The width of the content that will be copied to the magnifier.
@@ -484,6 +484,21 @@ public final class Magnifier {
        mDirtyState = true;
    }

    /**
     * Updates the factors of source which may impact the magnifier's size.
     * This can be called while the magnifier is showing and moving.
     * @param sourceHeight the new source height.
     * @param zoom the new zoom factor.
     */
    void updateSourceFactors(final int sourceHeight, final float zoom) {
        mZoom = zoom;
        mSourceHeight = sourceHeight;
        mWindowHeight = (int) (sourceHeight * zoom);
        if (mWindow != null) {
            mWindow.updateContentFactors(mWindowHeight, zoom);
        }
    }

    /**
     * Returns the zoom to be applied to the magnified view region copied to the magnifier.
     * If the zoom is x and the magnifier window size is (width, height), the original size
@@ -904,7 +919,7 @@ public final class Magnifier {
        private final Display mDisplay;
        // The size of the content of the magnifier.
        private final int mContentWidth;
        private final int mContentHeight;
        private int mContentHeight;
        // The insets of the content inside the allocated surface.
        private final int mOffsetX;
        private final int mOffsetY;
@@ -947,7 +962,7 @@ public final class Magnifier {
        // The current content of the magnifier. It is mBitmap + mOverlay, only used for testing.
        private Bitmap mCurrentContent;

        private final float mZoom;
        private float mZoom;
        // The width of the ramp region in pixels on the left & right sides of the fish-eye effect.
        private final int mRamp;
        // Whether is in the new magnifier style.
@@ -1009,11 +1024,11 @@ public final class Magnifier {

            final RecordingCanvas canvas = mRenderer.getRootNode().beginRecording(width, height);
            try {
                canvas.insertReorderBarrier();
                canvas.enableZ();
                canvas.drawRenderNode(mBitmapRenderNode);
                canvas.insertInorderBarrier();
                canvas.disableZ();
                canvas.drawRenderNode(mOverlayRenderNode);
                canvas.insertInorderBarrier();
                canvas.disableZ();
            } finally {
                mRenderer.getRootNode().endRecording();
            }
@@ -1034,15 +1049,66 @@ public final class Magnifier {
            }
        }

        /**
         * Updates the factors of content which may resize the window.
         * @param contentHeight the new height of content.
         * @param zoom the new zoom factor.
         */
        private void updateContentFactors(final int contentHeight, final float zoom) {
            if (mContentHeight == contentHeight && mZoom == zoom) {
              return;
            }
            if (mContentHeight < contentHeight) {
                // Grows the surface height as necessary.
                new SurfaceControl.Transaction().setBufferSize(
                        mSurfaceControl, mContentWidth, contentHeight).apply();
                mSurface.copyFrom(mSurfaceControl);
                mRenderer.setSurface(mSurface);

                final Outline outline = new Outline();
                outline.setRoundRect(0, 0, mContentWidth, contentHeight, 0);
                outline.setAlpha(1.0f);

                mBitmapRenderNode.setLeftTopRightBottom(mOffsetX, mOffsetY,
                        mOffsetX + mContentWidth, mOffsetY + contentHeight);
                mBitmapRenderNode.setOutline(outline);

                mOverlayRenderNode.setLeftTopRightBottom(mOffsetX, mOffsetY,
                        mOffsetX + mContentWidth, mOffsetY + contentHeight);
                mOverlayRenderNode.setOutline(outline);

                final RecordingCanvas canvas =
                        mRenderer.getRootNode().beginRecording(mContentWidth, contentHeight);
                try {
                    canvas.enableZ();
                    canvas.drawRenderNode(mBitmapRenderNode);
                    canvas.disableZ();
                    canvas.drawRenderNode(mOverlayRenderNode);
                    canvas.disableZ();
                } finally {
                    mRenderer.getRootNode().endRecording();
                }
            }
            mContentHeight = contentHeight;
            mZoom = zoom;
            fillMeshMatrix();
        }

        private void createMeshMatrixForFishEyeEffect() {
            mMeshWidth = 1;
            mMeshHeight = 6;
            mMeshLeft = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)];
            mMeshRight = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)];
            fillMeshMatrix();
        }

        private void fillMeshMatrix() {
            mMeshWidth = 1;
            mMeshHeight = 6;
            final float w = mContentWidth;
            final float h = mContentHeight;
            final float h0 = h / mZoom;
            final float dh = h - h0;
            mMeshLeft = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)];
            mMeshRight = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)];
            for (int i = 0; i < 2 * (mMeshWidth + 1) * (mMeshHeight + 1); i += 2) {
                // Calculates X value.
                final int colIndex = i % (2 * (mMeshWidth + 1)) / 2;
@@ -1197,6 +1263,7 @@ public final class Magnifier {
            if (mBitmap != null) {
                mBitmap.recycle();
            }
            mOverlay.setCallback(null);
        }

        private void doDraw() {