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

Commit 8a0ffff1 authored by mincheli's avatar mincheli
Browse files

Makes dragging window magnification smoother on low-medium device

It takes some time to update the geometry of the mirror window of
window magnification. If the peformance of the device is not so
good, the dragging of window magnification would looks sluggish.
To improve this, we use Choreographer to update the mirror view
geometry. It make the refresh rate sync with display frame
rendering.

Bug: 158264842
Test: atest WindowMagnificationControllerTest
Change-Id: Ia2eaca85ccec90b735dab9114c58a94108cdbed1
parent 3c89ea16
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.view.accessibility.IWindowMagnificationConnection;
import android.view.accessibility.IWindowMagnificationConnectionCallback;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.statusbar.CommandQueue;
@@ -94,7 +95,9 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
        //TODO: b/144080869 support multi-display.
        if (mWindowMagnificationController == null) {
            mWindowMagnificationController = new WindowMagnificationController(mContext,
                    mHandler, null,
                    mHandler,
                    new SfVsyncFrameCallbackProvider(),
                    null,
                    this);
        }
        mWindowMagnificationController.enableWindowMagnification(scale, centerX, centerY);
+15 −5
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.graphics.Region;
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.view.Choreographer;
import android.view.Display;
import android.view.Gravity;
import android.view.IWindow;
@@ -47,6 +48,7 @@ import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;

import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.R;
import com.android.systemui.shared.system.WindowManagerWrapper;

@@ -98,15 +100,27 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
    // The boundary of magnification frame.
    private final Rect mMagnificationFrameBoundary = new Rect();

    private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
    private final Choreographer.FrameCallback mMirrorViewGeometryVsyncCallback =
            l -> {
                if (mMirrorView != null) {
                    final Rect sourceBounds = getSourceBounds(mMagnificationFrame, mScale);
                    mTransaction.setGeometry(mMirrorSurface, sourceBounds, mTmpRect,
                            Surface.ROTATION_0).apply();
                }
            };

    @Nullable
    private MirrorWindowControl mMirrorWindowControl;

    WindowMagnificationController(Context context,
            @NonNull Handler handler,
            SfVsyncFrameCallbackProvider sfVsyncFrameProvider,
            MirrorWindowControl mirrorWindowControl,
            @NonNull WindowMagnifierCallback callback) {
        mContext = context;
        mHandler = handler;
        mSfVsyncFrameProvider = sfVsyncFrameProvider;
        mWindowMagnifierCallback = callback;
        Display display = mContext.getDisplay();
        display.getRealSize(mDisplaySize);
@@ -316,7 +330,6 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
                .reparent(mMirrorSurface, mMirrorSurfaceView.getSurfaceControl());

        modifyWindowMagnification(mTransaction);
        mTransaction.apply();
    }

    private void addDragTouchListeners() {
@@ -337,14 +350,13 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
     * Modifies the placement of the mirrored content when the position of mMirrorView is updated.
     */
    private void modifyWindowMagnification(SurfaceControl.Transaction t) {
        Rect sourceBounds = getSourceBounds(mMagnificationFrame, mScale);
        // The final destination for the magnification surface should be at 0,0 since the
        // ViewRootImpl's position will change
        mTmpRect.set(0, 0, mMagnificationFrame.width(), mMagnificationFrame.height());

        updateMirrorViewLayout();

        t.setGeometry(mMirrorSurface, sourceBounds, mTmpRect, Surface.ROTATION_0);
        mSfVsyncFrameProvider.postFrameCallback(mMirrorViewGeometryVsyncCallback);
    }

    /**
@@ -505,7 +517,6 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
            showControls();
        } else {
            modifyWindowMagnification(mTransaction);
            mTransaction.apply();
        }
    }

@@ -535,7 +546,6 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
        }
        if (updateMagnificationFramePosition((int) offsetX, (int) offsetY)) {
            modifyWindowMagnification(mTransaction);
            mTransaction.apply();
        }
    }
}
+16 −6
Original line number Diff line number Diff line
@@ -16,8 +16,8 @@

package com.android.systemui.accessibility;


import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;

import android.app.Instrumentation;
@@ -27,6 +27,7 @@ import android.testing.AndroidTestingRunner;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;

import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.SysuiTestCase;

import org.junit.After;
@@ -43,6 +44,8 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
    @Mock
    Handler mHandler;
    @Mock
    SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
    @Mock
    MirrorWindowControl mMirrorWindowControl;
    @Mock
    WindowMagnifierCallback mWindowMagnifierCallback;
@@ -54,7 +57,7 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
        MockitoAnnotations.initMocks(this);
        mInstrumentation = InstrumentationRegistry.getInstrumentation();
        mWindowMagnificationController = new WindowMagnificationController(getContext(),
                mHandler,
                mHandler, mSfVsyncFrameProvider,
                mMirrorWindowControl, mWindowMagnifierCallback);
        verify(mMirrorWindowControl).setWindowDelegate(
                any(MirrorWindowControl.MirrorWindowDelegate.class));
@@ -65,7 +68,6 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
        mInstrumentation.runOnMainSync(() -> {
            mWindowMagnificationController.deleteWindowMagnification();
        });
        mInstrumentation.waitForIdleSync();
    }

    @Test
@@ -74,7 +76,6 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
                    Float.NaN);
        });
        mInstrumentation.waitForIdleSync();
        verify(mMirrorWindowControl).showControl();
    }

@@ -84,13 +85,22 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
                    Float.NaN);
        });
        mInstrumentation.waitForIdleSync();

        mInstrumentation.runOnMainSync(() -> {
            mWindowMagnificationController.deleteWindowMagnification();
        });
        mInstrumentation.waitForIdleSync();

        verify(mMirrorWindowControl).destroyControl();
    }

    @Test
    public void moveMagnifier_schedulesFrame() {
        mInstrumentation.runOnMainSync(() -> {
            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
                    Float.NaN);
            mWindowMagnificationController.moveWindowMagnifier(100f, 100f);
        });

        verify(mSfVsyncFrameProvider, atLeastOnce()).postFrameCallback(any());
    }
}