From 856fa0c30aacd667d6e6e2fde204067c0256ee44 Mon Sep 17 00:00:00 2001 From: ryanlwlin Date: Fri, 11 Dec 2020 15:29:41 +0800 Subject: [PATCH] Animate bounce effect when tapping To make users aware that the border of the window is draggable, we bounce the window when tapping it. Bug: 173159759 Test: WindowMagnificationControllerTest manually test Change-Id: I4d5ce07d711389f760dd2a26b6e661068a685440 --- .../WindowMagnificationController.java | 70 ++++++++++++++----- .../WindowMagnificationControllerTest.java | 24 +++++++ 2 files changed, 76 insertions(+), 18 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java index 87dc6a53a9e27..3f7d2d837e2d6 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java @@ -20,6 +20,8 @@ import static android.view.WindowManager.LayoutParams; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_2BUTTON; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; @@ -28,7 +30,6 @@ import android.content.res.Resources; import android.graphics.Matrix; import android.graphics.PixelFormat; import android.graphics.Point; -import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; @@ -66,7 +67,7 @@ import java.util.Locale; * Class to handle adding and removing a window magnification. */ class WindowMagnificationController implements View.OnTouchListener, SurfaceHolder.Callback, - MirrorWindowControl.MirrorWindowDelegate { + MirrorWindowControl.MirrorWindowDelegate, MagnificationGestureDetector.OnGestureListener { private static final String TAG = "WindowMagnificationController"; // Delay to avoid updating state description too frequently. @@ -74,6 +75,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold // It should be consistent with the value defined in WindowMagnificationGestureHandler. private static final Range A11Y_ACTION_SCALE_RANGE = new Range<>(2.0f, 8.0f); private static final float A11Y_CHANGE_SCALE_DIFFERENCE = 1.0f; + private static final float ANIMATION_BOUNCE_EFFECT_SCALE = 1.05f; private final Context mContext; private final Resources mResources; private final Handler mHandler; @@ -102,7 +104,6 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold private View mRightDrag; private View mBottomDrag; - private final PointF mLastDrag = new PointF(); @NonNull private final WindowMagnifierCallback mWindowMagnifierCallback; @@ -123,9 +124,12 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold private int mNavGestureHeight; private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider; + private final MagnificationGestureDetector mGestureDetector; + private final int mBounceEffectDuration; private Choreographer.FrameCallback mMirrorViewGeometryVsyncCallback; private Locale mLocale; private NumberFormat mPercentFormat; + private float mBounceEffectAnimationScale; @Nullable private MirrorWindowControl mMirrorWindowControl; @@ -147,14 +151,19 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold mResources = mContext.getResources(); mScale = mResources.getInteger(R.integer.magnification_default_scale); + mBounceEffectDuration = mResources.getInteger( + com.android.internal.R.integer.config_shortAnimTime); updateDimensions(); + setInitialStartBounds(); + computeBounceAnimationScale(); mMirrorWindowControl = mirrorWindowControl; if (mMirrorWindowControl != null) { mMirrorWindowControl.setWindowDelegate(this); } mTransaction = transaction; - setInitialStartBounds(); + mGestureDetector = + new MagnificationGestureDetector(mContext, handler, this); // Initialize listeners. mMirrorViewRunnable = () -> { @@ -203,6 +212,13 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold updateNavigationBarDimensions(); } + private void computeBounceAnimationScale() { + final float windowWidth = mMagnificationFrame.width() + 2 * mMirrorSurfaceMargin; + final float visibleWindowWidth = windowWidth - 2 * mOuterBorderSize; + final float animationScaleMax = windowWidth / visibleWindowWidth; + mBounceEffectAnimationScale = Math.min(animationScaleMax, ANIMATION_BOUNCE_EFFECT_SCALE); + } + private void updateNavigationBarDimensions() { if (!supportsSwipeUpGesture()) { mNavGestureHeight = 0; @@ -248,6 +264,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold void onConfigurationChanged(int configDiff) { if ((configDiff & ActivityInfo.CONFIG_DENSITY) != 0) { updateDimensions(); + computeBounceAnimationScale(); if (isWindowVisible()) { deleteWindowMagnification(); enableWindowMagnification(Float.NaN, Float.NaN, Float.NaN); @@ -483,20 +500,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold public boolean onTouch(View v, MotionEvent event) { if (v == mDragView || v == mLeftDrag || v == mTopDrag || v == mRightDrag || v == mBottomDrag) { - return handleDragTouchEvent(event); - } - return false; - } - - private boolean handleDragTouchEvent(MotionEvent event) { - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - mLastDrag.set(event.getRawX(), event.getRawY()); - return true; - case MotionEvent.ACTION_MOVE: - moveWindowMagnifier(event.getRawX() - mLastDrag.x, event.getRawY() - mLastDrag.y); - mLastDrag.set(event.getRawX(), event.getRawY()); - return true; + return mGestureDetector.onTouch(event); } return false; } @@ -685,6 +689,36 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold return mPercentFormat.format(scale); } + @Override + public boolean onSingleTap() { + animateBounceEffect(); + return true; + } + + @Override + public boolean onDrag(float offsetX, float offsetY) { + moveWindowMagnifier(offsetX, offsetY); + return true; + } + + @Override + public boolean onStart(float x, float y) { + return true; + } + + @Override + public boolean onFinish(float x, float y) { + return false; + } + + private void animateBounceEffect() { + final ObjectAnimator scaleAnimator = ObjectAnimator.ofPropertyValuesHolder(mMirrorView, + PropertyValuesHolder.ofFloat(View.SCALE_X, 1, mBounceEffectAnimationScale, 1), + PropertyValuesHolder.ofFloat(View.SCALE_Y, 1, mBounceEffectAnimationScale, 1)); + scaleAnimator.setDuration(mBounceEffectDuration); + scaleAnimator.start(); + } + private class MirrorWindowA11yDelegate extends View.AccessibilityDelegate { @Override 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 f28322f4d5bb0..9659610e71150 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java @@ -26,6 +26,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; @@ -40,6 +41,7 @@ import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.Resources; import android.os.Handler; +import android.os.SystemClock; import android.testing.AndroidTestingRunner; import android.testing.TestableResources; import android.view.Display; @@ -347,4 +349,26 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { verify(mWindowManager).updateViewLayout(eq(mMirrorView), paramsArgumentCaptor.capture()); assertEquals(newA11yWindowTitle, paramsArgumentCaptor.getValue().accessibilityTitle); } + + @Test + public void onSingleTap_enabled_scaleIsChanged() { + mInstrumentation.runOnMainSync(() -> { + mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN, + Float.NaN); + }); + + mInstrumentation.runOnMainSync(() -> { + mWindowMagnificationController.onSingleTap(); + }); + + final long timeout = SystemClock.uptimeMillis() + 1000; + while (SystemClock.uptimeMillis() < timeout) { + SystemClock.sleep(10); + + if (Float.compare(1.0f, mMirrorView.getScaleX()) < 0) { + return; + } + } + fail("mMirrorView scale is not changed"); + } }