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

Commit 856fa0c3 authored by ryanlwlin's avatar ryanlwlin
Browse files

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
parent df5396ea
Loading
Loading
Loading
Loading
+52 −18
Original line number Diff line number Diff line
@@ -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<Float> 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
+24 −0
Original line number Diff line number Diff line
@@ -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");
    }
}