From 8a0ffff1bf54def20970b03fa66b529efff25174 Mon Sep 17 00:00:00 2001 From: mincheli Date: Wed, 10 Jun 2020 10:32:39 +0800 Subject: [PATCH] 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 --- .../accessibility/WindowMagnification.java | 5 ++++- .../WindowMagnificationController.java | 20 ++++++++++++----- .../WindowMagnificationControllerTest.java | 22 ++++++++++++++----- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java index 2d28b143796cd..426e400c9fb93 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java @@ -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); diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java index 18e7778383918..7e9faff8c2964 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java @@ -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(); } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java index bfb95b0db3e38..a898c3ce27730 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java @@ -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()); + } }