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

Commit 8d1f52a2 authored by Mihai Popa's avatar Mihai Popa Committed by Android (Google) Code Review
Browse files

Merge changes from topic "magnifier_improve_pixelcopy_failure_handling"

* changes:
  [Magnifier-84] Improve PixelCopy failures handling
  [Magnifier-86] Fix deadlock causing ANR
parents 0c1425af 3aa46b2d
Loading
Loading
Loading
Loading
+29 −7
Original line number Diff line number Diff line
@@ -136,6 +136,8 @@ public final class Magnifier {
    // Lock to synchronize between the UI thread and the thread that handles pixel copy results.
    // Only sync mWindow writes from UI thread with mWindow reads from sPixelCopyHandlerThread.
    private final Object mLock = new Object();
    // The lock used to synchronize the UI and render threads when a #dismiss is performed.
    private final Object mDestroyLock = new Object();

    /**
     * Initializes a magnifier.
@@ -275,7 +277,7 @@ public final class Magnifier {
                            mWindowElevation, mWindowCornerRadius,
                            mOverlay != null ? mOverlay : new ColorDrawable(Color.TRANSPARENT),
                            Handler.getMain() /* draw the magnifier on the UI thread */, mLock,
                            mCallback);
                            mDestroyLock, mCallback);
                }
            }
            performPixelCopy(startX, startY, true /* update window position */);
@@ -304,10 +306,12 @@ public final class Magnifier {
     */
    public void dismiss() {
        if (mWindow != null) {
            synchronized (mDestroyLock) {
                synchronized (mLock) {
                    mWindow.destroy();
                    mWindow = null;
                }
            }
            mPrevShowSourceCoords.x = NONEXISTENT_PREVIOUS_CONFIG_VALUE;
            mPrevShowSourceCoords.y = NONEXISTENT_PREVIOUS_CONFIG_VALUE;
            mPrevShowWindowCoords.x = NONEXISTENT_PREVIOUS_CONFIG_VALUE;
@@ -625,7 +629,7 @@ public final class Magnifier {
        resolvedTop = Math.min(resolvedTop, mContentCopySurface.mHeight - mSourceHeight);
        if (resolvedLeft < 0 || resolvedTop < 0) {
            Log.e(TAG, "Magnifier's content is copied from a surface smaller than"
                    + "the content requested size. This will probably lead to distorted content.");
                    + "the content requested size. The magnifier will be dismissed.");
        }
        resolvedRight = Math.max(resolvedRight, resolvedLeft + mSourceWidth);
        resolvedBottom = Math.max(resolvedBottom, resolvedTop + mSourceHeight);
@@ -664,6 +668,7 @@ public final class Magnifier {
    private void performPixelCopy(final int startXInSurface, final int startYInSurface,
            final boolean updateWindowPosition) {
        if (mContentCopySurface.mSurface == null || !mContentCopySurface.mSurface.isValid()) {
            onPixelCopyFailed();
            return;
        }

@@ -681,6 +686,10 @@ public final class Magnifier {
                Bitmap.createBitmap(mSourceWidth, mSourceHeight, Bitmap.Config.ARGB_8888);
        PixelCopy.request(mContentCopySurface.mSurface, mPixelCopyRequestRect, bitmap,
                result -> {
                    if (result != PixelCopy.SUCCESS) {
                        onPixelCopyFailed();
                        return;
                    }
                    synchronized (mLock) {
                        if (mWindow != currentWindowInstance) {
                            // The magnifier was dismissed (and maybe shown again) in the meantime.
@@ -699,6 +708,17 @@ public final class Magnifier {
        mDirtyState = false;
    }

    private void onPixelCopyFailed() {
        Log.e(TAG, "Magnifier failed to copy content from the view Surface. It will be dismissed.");
        // Post to make sure #dismiss is done on the main thread.
        Handler.getMain().postAtFrontOfQueue(() -> {
            dismiss();
            if (mCallback != null) {
                mCallback.onOperationComplete();
            }
        });
    }

    /**
     * Clamp window coordinates inside the surface the magnifier is attached to, to avoid
     * displaying the magnifier out of screen or overlapping with system insets.
@@ -819,7 +839,7 @@ public final class Magnifier {
        // is performed on the UI thread and a frame callback on the render thread.
        // When both mLock and mDestroyLock need to be held at the same time,
        // mDestroyLock should be acquired before mLock in order to avoid deadlocks.
        private final Object mDestroyLock = new Object();
        private final Object mDestroyLock;

        // The current content of the magnifier. It is mBitmap + mOverlay, only used for testing.
        private Bitmap mCurrentContent;
@@ -827,10 +847,12 @@ public final class Magnifier {
        InternalPopupWindow(final Context context, final Display display,
                final SurfaceControl parentSurfaceControl, final int width, final int height,
                final float elevation, final float cornerRadius, final Drawable overlay,
                final Handler handler, final Object lock, final Callback callback) {
                final Handler handler, final Object lock, final Object destroyLock,
                final Callback callback) {
            mDisplay = display;
            mOverlay = overlay;
            mLock = lock;
            mDestroyLock = destroyLock;
            mCallback = callback;

            mContentWidth = width;