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

Commit 1eb19a3b authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[Magnifier - 5] Auto invalidate and misc"

parents f390fd62 ca189fe0
Loading
Loading
Loading
Loading
+5 −18
Original line number Diff line number Diff line
@@ -476,17 +476,6 @@ public class Editor {
        stopTextActionModeWithPreservingSelection();
    }

    void invalidateMagnifier() {
        final DisplayMetrics dm = mTextView.getResources().getDisplayMetrics();
        invalidateMagnifier(0, 0, dm.widthPixels, dm.heightPixels);
    }

    void invalidateMagnifier(final float l, final float t, final float r, final float b) {
        if (mMagnifier != null) {
            mTextView.post(() -> mMagnifier.invalidate(new RectF(l, t, r, b)));
        }
    }

    private void discardTextDisplayLists() {
        if (mTextRenderNodes != null) {
            for (int i = 0; i < mTextRenderNodes.length; i++) {
@@ -4550,17 +4539,15 @@ 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);
            final float xPosInView = getHorizontal(mTextView.getLayout(), offset)
                    + mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
            // Vertically snap to middle of current line.
            final float yPosInView = (mTextView.getLayout().getLineTop(lineNumber)
                    + mTextView.getLayout().getLineBottom(lineNumber)) / 2.0f;
            final int[] coordinatesOnScreen = new int[2];
            mTextView.getLocationOnScreen(coordinatesOnScreen);
            final float centerXOnScreen = mTextView.convertViewToScreenCoord(xPosInView, true);
            final float centerYOnScreen = mTextView.convertViewToScreenCoord(yPosInView, false);
                    + mTextView.getLayout().getLineBottom(lineNumber)) / 2.0f
                    + mTextView.getTotalPaddingTop() - mTextView.getScrollY();

            suspendBlink();
            mMagnifier.show(centerXOnScreen, centerYOnScreen, MAGNIFIER_ZOOM);
            mMagnifier.show(xPosInView, yPosInView, MAGNIFIER_ZOOM);
        }

        protected final void dismissMagnifier() {
+0 −30
Original line number Diff line number Diff line
@@ -9219,36 +9219,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        }
    }

    @Override
    public void invalidate() {
        super.invalidate();

        if (mEditor != null) {
            mEditor.invalidateMagnifier();
        }
    }

    @Override
    public void invalidate(int l, int t, int r, int b) {
        super.invalidate(l, t, r, b);

        if (mEditor != null) {
            mEditor.invalidateMagnifier(
                    convertViewToScreenCoord(l, true /* isHorizontal */),
                    convertViewToScreenCoord(t, false /* isHorizontal */),
                    convertViewToScreenCoord(r, true /* isHorizontal */),
                    convertViewToScreenCoord(b, false /* isHorizontal */));
        }
    }

    float convertViewToScreenCoord(float viewCoord, boolean isHorizontal) {
        final int[] coordinatesOnScreen = new int[2];
        getLocationOnScreen(coordinatesOnScreen);
        return isHorizontal
                ? viewCoord + getTotalPaddingLeft() - getScrollX() + coordinatesOnScreen[0]
                : viewCoord + getTotalPaddingTop() - getScrollY() + coordinatesOnScreen[1];
    }

    /**
     * @return whether or not the cursor is visible (assuming this TextView is editable)
     *
+44 −81
Original line number Diff line number Diff line
@@ -22,9 +22,7 @@ import android.annotation.UiThread;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
import android.util.Log;
import android.view.Gravity;
@@ -38,13 +36,15 @@ import android.widget.PopupWindow;
import com.android.internal.R;
import com.android.internal.util.Preconditions;

import java.util.Timer;
import java.util.TimerTask;

/**
 * Android magnifier widget. Can be used by any view which is attached to window.
 */
public final class Magnifier {
    private static final String LOG_TAG = "magnifier";
    // Use this to specify that a previous configuration value does not exist.
    private static final int INEXISTENT_PREVIOUS_CONFIG_VALUE = -1;
    private static final int MAGNIFIER_REFRESH_RATE_MS = 33; // ~30fps
    // The view for which this magnifier is attached.
    private final View mView;
    // The window containing the magnifier.
@@ -62,15 +62,10 @@ public final class Magnifier {
    // The callback of the pixel copy request will be invoked on this Handler when
    // the copy is finished.
    private final Handler mPixelCopyHandler = Handler.getMain();

    private RectF mTmpRectF;

    // Variables holding previous states, used for detecting redundant calls and invalidation.
    private Point mPrevStartCoordsOnScreen = new Point(
            INEXISTENT_PREVIOUS_CONFIG_VALUE, INEXISTENT_PREVIOUS_CONFIG_VALUE);
    private PointF mPrevCenterCoordsOnScreen = new PointF(
            INEXISTENT_PREVIOUS_CONFIG_VALUE, INEXISTENT_PREVIOUS_CONFIG_VALUE);
    private float mPrevScale = INEXISTENT_PREVIOUS_CONFIG_VALUE;
    // Current magnification scale.
    private float mScale;
    // Timer used to schedule the copy task.
    private Timer mTimer;

    /**
     * Initializes a magnifier.
@@ -82,6 +77,7 @@ public final class Magnifier {
        mView = Preconditions.checkNotNull(view);
        final Context context = mView.getContext();
        final View content = LayoutInflater.from(context).inflate(R.layout.magnifier, null);
        content.findViewById(R.id.magnifier_inner).setClipToOutline(true);
        mWindowWidth = context.getResources().getDimensionPixelSize(R.dimen.magnifier_width);
        mWindowHeight = context.getResources().getDimensionPixelSize(R.dimen.magnifier_height);
        final float elevation = context.getResources().getDimension(R.dimen.magnifier_elevation);
@@ -101,15 +97,15 @@ public final class Magnifier {
    /**
     * Shows the magnifier on the screen.
     *
     * @param centerXOnScreen horizontal coordinate of the center point of the magnifier source. The
     *        lower end is clamped to 0
     * @param centerYOnScreen vertical coordinate of the center point of the magnifier source. The
     *        lower end is clamped to 0
     * @param xPosInView horizontal coordinate of the center point of the magnifier source relative
     *        to the view. The lower end is clamped to 0
     * @param yPosInView vertical coordinate of the center point of the magnifier source
     *        relative to the view. The lower end is clamped to 0
     * @param scale the scale at which the magnifier zooms on the source content. The
     *        lower end is clamped to 1 and the higher end to 4
     */
    public void show(@FloatRange(from=0) float centerXOnScreen,
            @FloatRange(from=0) float centerYOnScreen,
    public void show(@FloatRange(from=0) float xPosInView,
            @FloatRange(from=0) float yPosInView,
            @FloatRange(from=1, to=4) float scale) {
        if (scale > 4) {
            scale = 4;
@@ -119,27 +115,29 @@ public final class Magnifier {
            scale = 1;
        }

        if (centerXOnScreen < 0) {
            centerXOnScreen = 0;
        if (xPosInView < 0) {
            xPosInView = 0;
        }

        if (centerYOnScreen < 0) {
            centerYOnScreen = 0;
        if (yPosInView < 0) {
            yPosInView = 0;
        }

        showInternal(centerXOnScreen, centerYOnScreen, scale, false);
        if (mScale != scale) {
            resizeBitmap(scale);
        }
        mScale = scale;
        configureCoordinates(xPosInView, yPosInView);

    private void showInternal(@FloatRange(from=0) float centerXOnScreen,
            @FloatRange(from=0) float centerYOnScreen,
            @FloatRange(from=1, to=4) float scale,
            boolean forceShow) {
        if (mPrevScale != scale) {
            resizeBitmap(scale);
            mPrevScale = scale;
        if (mTimer == null) {
            mTimer = new Timer();
            mTimer.schedule(new TimerTask() {
                @Override
                public void run() {
                    performPixelCopy();
                }
            }, 0 /* delay */, MAGNIFIER_REFRESH_RATE_MS);
        }
        configureCoordinates(centerXOnScreen, centerYOnScreen);
        maybePerformPixelCopy(scale, forceShow);

        if (mWindow.isShowing()) {
            mWindow.update(mWindowCoords.x, mWindowCoords.y, mWindow.getWidth(),
@@ -148,9 +146,6 @@ public final class Magnifier {
            mWindow.showAtLocation(mView.getRootView(), Gravity.NO_GRAVITY,
                    mWindowCoords.x, mWindowCoords.y);
        }

        mPrevCenterCoordsOnScreen.x = centerXOnScreen;
        mPrevCenterCoordsOnScreen.y = centerYOnScreen;
    }

    /**
@@ -159,36 +154,10 @@ public final class Magnifier {
    public void dismiss() {
        mWindow.dismiss();

        mPrevStartCoordsOnScreen.x = INEXISTENT_PREVIOUS_CONFIG_VALUE;
        mPrevStartCoordsOnScreen.y = INEXISTENT_PREVIOUS_CONFIG_VALUE;
        mPrevCenterCoordsOnScreen.x = INEXISTENT_PREVIOUS_CONFIG_VALUE;
        mPrevCenterCoordsOnScreen.y = INEXISTENT_PREVIOUS_CONFIG_VALUE;
        mPrevScale = INEXISTENT_PREVIOUS_CONFIG_VALUE;
    }

    /**
     * Forces the magnifier to update content by taking and showing a new snapshot using the
     * previous coordinates. It does this only if the magnifier is showing and the dirty rectangle
     * intersects the rectangle which holds the content to be magnified.
     *
     * @param dirtyRectOnScreen the rectangle representing the screen bounds of the dirty region
     */
    public void invalidate(RectF dirtyRectOnScreen) {
        if (mWindow.isShowing() && mPrevCenterCoordsOnScreen.x != INEXISTENT_PREVIOUS_CONFIG_VALUE
                && mPrevCenterCoordsOnScreen.y != INEXISTENT_PREVIOUS_CONFIG_VALUE
                && mPrevScale != INEXISTENT_PREVIOUS_CONFIG_VALUE) {
            // Update the current showing RectF.
            mTmpRectF = new RectF(mPrevStartCoordsOnScreen.x,
                    mPrevStartCoordsOnScreen.y,
                    mPrevStartCoordsOnScreen.x + mBitmap.getWidth(),
                    mPrevStartCoordsOnScreen.y + mBitmap.getHeight());

            // Update only if we are currently showing content that has been declared as invalid.
            if (RectF.intersects(dirtyRectOnScreen, mTmpRectF)) {
                // Update the contents shown in the magnifier.
                showInternal(mPrevCenterCoordsOnScreen.x, mPrevCenterCoordsOnScreen.y, mPrevScale,
                        true /* forceShow */);
            }
        if (mTimer != null) {
            mTimer.cancel();
            mTimer.purge();
            mTimer = null;
        }
    }

@@ -213,7 +182,12 @@ public final class Magnifier {
        getImageView().setImageBitmap(mBitmap);
    }

    private void configureCoordinates(float posXOnScreen, float posYOnScreen) {
    private void configureCoordinates(float xPosInView, float yPosInView) {
        final int[] coordinatesOnScreen = new int[2];
        mView.getLocationOnScreen(coordinatesOnScreen);
        final float posXOnScreen = xPosInView + coordinatesOnScreen[0];
        final float posYOnScreen = yPosInView + coordinatesOnScreen[1];

        mCenterZoomCoords.x = (int) posXOnScreen;
        mCenterZoomCoords.y = (int) posYOnScreen;

@@ -223,7 +197,7 @@ public final class Magnifier {
        mWindowCoords.y = mCenterZoomCoords.y - mWindowHeight / 2 - verticalMagnifierOffset;
    }

    private void maybePerformPixelCopy(final float scale, final boolean forceShow) {
    private void performPixelCopy() {
        final int startY = mCenterZoomCoords.y - mBitmap.getHeight() / 2;
        int rawStartX = mCenterZoomCoords.x - mBitmap.getWidth() / 2;

@@ -234,13 +208,6 @@ public final class Magnifier {
            rawStartX = mView.getWidth() - mBitmap.getWidth();
        }

        if (!forceShow && rawStartX == mPrevStartCoordsOnScreen.x
                && startY == mPrevStartCoordsOnScreen.y
                && scale == mPrevScale) {
            // Skip, we are already showing the desired content.
            return;
        }

        final int startX = rawStartX;
        final ViewRootImpl viewRootImpl = mView.getViewRootImpl();

@@ -251,11 +218,7 @@ public final class Magnifier {
                    new Rect(startX, startY, startX + mBitmap.getWidth(),
                            startY + mBitmap.getHeight()),
                    mBitmap,
                    result -> {
                        getImageView().invalidate();
                        mPrevStartCoordsOnScreen.x = startX;
                        mPrevStartCoordsOnScreen.y = startY;
                    },
                    result -> getImageView().invalidate(),
                    mPixelCopyHandler);
        } else {
            Log.d(LOG_TAG, "Could not perform PixelCopy request");
+13 −6
Original line number Diff line number Diff line
@@ -18,10 +18,17 @@
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/magnifier_inner"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
    android:background="?android:attr/floatingToolbarPopupBackgroundDrawable">
        android:background="?android:attr/floatingToolbarPopupBackgroundDrawable"
        android:elevation="@android:dimen/magnifier_elevation">
        <ImageView
            android:id="@+id/magnifier_image"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>
</LinearLayout>
+1 −1
Original line number Diff line number Diff line
@@ -521,7 +521,7 @@
    <dimen name="content_rect_bottom_clip_allowance">20dp</dimen>

    <!-- Magnifier dimensions -->
    <dimen name="magnifier_width">200dp</dimen>
    <dimen name="magnifier_width">164dp</dimen>
    <dimen name="magnifier_height">48dp</dimen>
    <dimen name="magnifier_elevation">2dp</dimen>
    <dimen name="magnifier_offset">42dp</dimen>
Loading