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

Commit 9a7f0771 authored by Roy Chou's avatar Roy Chou
Browse files

feat(#AlwaysOnMagnifier)!: Supports magnification zooming to 100% [2/2]

There are 2 parts in this feature.
1. support fullscreen magnifier zooming to 100%.
2. support window magnifier zooming to 100%.

This CL is for the 2nd part.

We change the minimum magnifiable scale to 100% in window magnifier, and prevent persistedScale from being 100%.

In WindowMagnificationAnimationController, we add function updateState(). It would be triggered after magnifier enable/disable actions, and update mState by checking the current scale in manager. Therefore, we could assure the controller is in the correct state.

In WindowMagnificationGestureHandler, We add flag mEnabledBeforeDrag to cache whether the magnifier is enabled before entering viewport dragging mode by triple tap and hold gesture. Accordingly, we can decide whether to disable magnifier after dragging end by the flag. Therefore, we can keep magnifier enabled after dragging end if the magnifier is already enabled before dragging start by triple tap and hold gesture.

Besides, we modify some test cases on WindowMagnificationAnimationControllerTest and run atest. Due to Bug/176890994, we remains the @ignore tag.

Bug: 146504199
Test: manually
	atest WindowMagnificationControllerTest
	atest WindowMagnificationAnimationControllerTest
	atest WindowMagnificationGestureHandlerTest
	atest WindowMagnificationManagerTest
Change-Id: Iccdbb42efc34da0dd39b468926259a25c90baf95
parent 741394ab
Loading
Loading
Loading
Loading
+21 −9
Original line number Diff line number Diff line
@@ -50,9 +50,9 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
    @interface MagnificationState {}

    // The window magnification is disabled.
    private static final int STATE_DISABLED = 0;
    @VisibleForTesting static final int STATE_DISABLED = 0;
    // The window magnification is enabled.
    private static final int STATE_ENABLED = 1;
    @VisibleForTesting static final int STATE_ENABLED = 1;
    // The window magnification is going to be disabled when the animation is end.
    private static final int STATE_DISABLING = 2;
    // The animation is running for enabling the window magnification.
@@ -151,7 +151,7 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
            }
            mController.enableWindowMagnificationInternal(scale, centerX, centerY,
                    mMagnificationFrameOffsetRatioX, mMagnificationFrameOffsetRatioY);
            setState(STATE_ENABLED);
            updateState();
            return;
        }
        mAnimationCallback = animationCallback;
@@ -165,7 +165,7 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
                mValueAnimator.cancel();
            }
            sendAnimationCallback(true);
            setState(STATE_ENABLED);
            updateState();
        } else {
            if (mState == STATE_DISABLING) {
                mValueAnimator.reverse();
@@ -254,7 +254,7 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
                mValueAnimator.cancel();
            }
            mController.deleteWindowMagnification();
            setState(STATE_DISABLED);
            updateState();
            return;
        }

@@ -272,6 +272,14 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
        setState(STATE_DISABLING);
    }

    private void updateState() {
        if (Float.isNaN(mController.getScale())) {
            setState(STATE_DISABLED);
        } else {
            setState(STATE_ENABLED);
        }
    }

    private void setState(@MagnificationState int state) {
        if (DEBUG) {
            Log.d(TAG, "setState from " + mState + " to " + state);
@@ -279,6 +287,11 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
        mState = state;
    }

    @VisibleForTesting
    @MagnificationState int getState() {
        return mState;
    }

    @Override
    public void onAnimationStart(Animator animation) {
        mEndAnimationCanceled = false;
@@ -289,11 +302,10 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
        if (mEndAnimationCanceled || mController == null) {
            return;
        }
        if (Float.isNaN(mController.getScale())) {
            setState(STATE_DISABLED);
        } else {
            setState(STATE_ENABLED);
        if (mState == STATE_DISABLING) {
            mController.deleteWindowMagnification();
        }
        updateState();
        sendAnimationCallback(true);
        // We reset the duration to config_longAnimTime
        mValueAnimator.setDuration(mContext.getResources()
+11 −4
Original line number Diff line number Diff line
@@ -97,7 +97,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
    // Delay to avoid updating state description too frequently.
    private static final int UPDATE_STATE_DESCRIPTION_DELAY_MS = 100;
    // 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 Range<Float> A11Y_ACTION_SCALE_RANGE = new Range<>(1.0f, 8.0f);
    private static final float A11Y_CHANGE_SCALE_DIFFERENCE = 1.0f;
    private static final float ANIMATION_BOUNCE_EFFECT_SCALE = 1.05f;
    private static final float[] MAGNIFICATION_SCALE_OPTIONS = {1.0f, 1.4f, 1.8f, 2.5f};
@@ -213,7 +213,9 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
    private static final int MAX_HORIZONTAL_MOVE_ANGLE = 50;
    private static final int HORIZONTAL = 1;
    private static final int VERTICAL = 0;
    private static final double HORIZONTAL_LOCK_BASE =

    @VisibleForTesting
    static final double HORIZONTAL_LOCK_BASE =
            Math.tan(Math.toRadians(MAX_HORIZONTAL_MOVE_ANGLE));

    private boolean mAllowDiagonalScrolling = false;
@@ -704,6 +706,11 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
        }
    }

    @VisibleForTesting
    WindowMagnificationSettings getMagnificationSettings() {
        return mWindowMagnificationSettings;
    }

    /**
     * Sets the window size with given width and height in pixels without changing the
     * window center. The width or the height will be clamped in the range
@@ -1075,7 +1082,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold

    /**
     * Enables window magnification with specified parameters. If the given scale is <strong>less
     * than or equal to 1.0f<strong>, then
     * than 1.0f<strong>, then
     * {@link WindowMagnificationController#deleteWindowMagnification()} will be called instead to
     * be consistent with the behavior of display magnification.
     *
@@ -1093,7 +1100,7 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
     */
    void enableWindowMagnificationInternal(float scale, float centerX, float centerY,
                float magnificationFrameOffsetRatioX, float magnificationFrameOffsetRatioY) {
        if (Float.compare(scale, 1.0f)  <= 0) {
        if (Float.compare(scale, 1.0f) < 0) {
            deleteWindowMagnification();
            return;
        }
+14 −7
Original line number Diff line number Diff line
@@ -92,7 +92,7 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
    private ImageButton mChangeModeButton;
    private boolean mAllowDiagonalScrolling = false;
    private static final float A11Y_CHANGE_SCALE_DIFFERENCE = 1.0f;
    private static final float A11Y_SCALE_MIN_VALUE = 2.0f;
    private static final float A11Y_SCALE_MIN_VALUE = 1.0f;
    private WindowMagnificationSettingsCallback mCallback;

    @Retention(RetentionPolicy.SOURCE)
@@ -136,9 +136,12 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            float scale = progress * A11Y_CHANGE_SCALE_DIFFERENCE + A11Y_SCALE_MIN_VALUE;
            mSecureSettings.putFloatForUser(
            // update persisted scale only when scale >= 2.0
            if (scale >= 2.0f) {
                Settings.Secure.putFloatForUser(mContext.getContentResolver(),
                        Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, scale,
                        UserHandle.USER_CURRENT);
            }
            mCallback.onMagnifierScale(scale);
        }

@@ -516,12 +519,16 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest
        boolean enabled = mSecureSettings.getIntForUser(
                Settings.Secure.ACCESSIBILITY_ALLOW_DIAGONAL_SCROLLING, 0,
                UserHandle.USER_CURRENT) == 1;
        setDiagonalScrolling(!enabled);
    }

        mSecureSettings.putIntForUser(
                Settings.Secure.ACCESSIBILITY_ALLOW_DIAGONAL_SCROLLING, enabled ? 0 : 1,
    @VisibleForTesting
    void setDiagonalScrolling(boolean enabled) {
        Settings.Secure.putIntForUser(mContext.getContentResolver(),
                Settings.Secure.ACCESSIBILITY_ALLOW_DIAGONAL_SCROLLING, enabled ? 1 : 0,
                UserHandle.USER_CURRENT);

        mCallback.onSetDiagonalScrolling(!enabled);
        mCallback.onSetDiagonalScrolling(enabled);
    }

    private void setEditMagnifierSizeMode(boolean enable) {
+111 −7
Original line number Diff line number Diff line
@@ -251,10 +251,51 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
            throws RemoteException {
        enableWindowMagnificationWithoutAnimation();

        final float targetScale = 1.0f;
        final float targetCenterX = DEFAULT_CENTER_X + 100;
        final float targetCenterY = DEFAULT_CENTER_Y + 100;

        mInstrumentation.runOnMainSync(() -> {
            Mockito.reset(mSpyController);
            mWindowMagnificationAnimationController.enableWindowMagnification(1.0f,
                    DEFAULT_CENTER_X + 100, DEFAULT_CENTER_Y + 100, mAnimationCallback);
            mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
                    targetCenterX, targetCenterY, mAnimationCallback);
            mCurrentScale.set(mController.getScale());
            mCurrentCenterX.set(mController.getCenterX());
            mCurrentCenterY.set(mController.getCenterY());
        });

        SystemClock.sleep(mWaitingAnimationPeriod);

        verify(mSpyController, atLeast(2)).enableWindowMagnificationInternal(
                mScaleCaptor.capture(),
                mCenterXCaptor.capture(), mCenterYCaptor.capture(),
                mOffsetXCaptor.capture(), mOffsetYCaptor.capture());
        verifyStartValue(mScaleCaptor, mCurrentScale.get());
        verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
        verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
        verifyStartValue(mOffsetXCaptor, 0f);
        verifyStartValue(mOffsetYCaptor, 0f);

        verifyFinalSpec(targetScale, targetCenterX, targetCenterY);

        verify(mAnimationCallback).onResult(true);
        assertEquals(WindowMagnificationAnimationController.STATE_ENABLED,
                mWindowMagnificationAnimationController.getState());
    }

    @Test
    public void enableWindowMagnificationWithScaleLessThanOne_enabled_AnimationAndInvokeCallback()
            throws RemoteException {
        enableWindowMagnificationWithoutAnimation();

        final float targetScale = 0.99f;
        final float targetCenterX = DEFAULT_CENTER_X + 100;
        final float targetCenterY = DEFAULT_CENTER_Y + 100;

        mInstrumentation.runOnMainSync(() -> {
            Mockito.reset(mSpyController);
            mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
                    targetCenterX, targetCenterY, mAnimationCallback);
            mCurrentScale.set(mController.getScale());
            mCurrentCenterX.set(mController.getCenterX());
            mCurrentCenterY.set(mController.getCenterY());
@@ -275,6 +316,29 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
        verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);

        verify(mAnimationCallback).onResult(true);
        assertEquals(WindowMagnificationAnimationController.STATE_DISABLED,
                mWindowMagnificationAnimationController.getState());
    }

    @Test
    public void
            enableWindowMagnificationWithScaleLessThanOneAndWithoutCallBack_enabled_expectedValues()
            throws RemoteException {
        enableWindowMagnificationWithoutAnimation();

        final float targetScale = 0.99f;
        final float targetCenterX = DEFAULT_CENTER_X + 100;
        final float targetCenterY = DEFAULT_CENTER_Y + 100;

        mInstrumentation.runOnMainSync(() -> {
            Mockito.reset(mSpyController);
            mWindowMagnificationAnimationController.enableWindowMagnification(targetScale,
                    targetCenterX, targetCenterY, null);
        });

        verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
        assertEquals(WindowMagnificationAnimationController.STATE_DISABLED,
                mWindowMagnificationAnimationController.getState());
    }

    @Test
@@ -684,14 +748,54 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
    }

    @Test
    public void moveWindowMagnifier_enabled() {
    public void moveWindowMagnifier_enabled_vertical_only_expectedValue() {
        enableWindowMagnificationWithoutAnimation();

        // should move vertically since offsetY/offsetX > HORIZONTAL_LOCK_BASE
        final float offsetX = 50.0f;
        final float offsetY =
                (float) Math.ceil(offsetX * WindowMagnificationController.HORIZONTAL_LOCK_BASE)
                + 1.0f;
        mInstrumentation.runOnMainSync(
                () -> mController.moveWindowMagnifier(100f, 200f));
                () -> mController.moveWindowMagnifier(offsetX, offsetY));

        verify(mSpyController).moveWindowMagnifier(offsetX, offsetY);
        verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y + offsetY);
    }

    @Test
    public void moveWindowMagnifier_enabled_horinzontal_only_expectedValue() {
        enableWindowMagnificationWithoutAnimation();

        // should move vertically since offsetY/offsetX <= HORIZONTAL_LOCK_BASE
        final float offsetX = 50.0f;
        final float offsetY =
                (float) Math.floor(offsetX * WindowMagnificationController.HORIZONTAL_LOCK_BASE)
                        - 1.0f;
        mInstrumentation.runOnMainSync(
                () -> mController.moveWindowMagnifier(offsetX, offsetY));

        verify(mSpyController).moveWindowMagnifier(offsetX, offsetY);
        verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + offsetX, DEFAULT_CENTER_Y);
    }

    @Test
    public void moveWindowMagnifier_enabled_setDiagonalEnabled_expectedValues() {
        enableWindowMagnificationWithoutAnimation();

        final float offsetX = 50.0f;
        final float offsetY =
                (float) Math.ceil(offsetX * WindowMagnificationController.HORIZONTAL_LOCK_BASE);
        // while diagonal scrolling enabled,
        //  should move with both offsetX and offsetY without regrading offsetY/offsetX
        mInstrumentation.runOnMainSync(
                () -> {
                    mController.getMagnificationSettings().setDiagonalScrolling(true);
                    mController.moveWindowMagnifier(offsetX, offsetY);
                });

        verify(mSpyController).moveWindowMagnifier(100f, 200f);
        verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + 100f, DEFAULT_CENTER_Y + 100f);
        verify(mSpyController).moveWindowMagnifier(offsetX, offsetY);
        verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X + offsetX, DEFAULT_CENTER_Y + offsetY);
    }

    @Test
@@ -807,7 +911,7 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {

        @Override
        void moveWindowMagnifier(float offsetX, float offsetY) {
            super.moveWindowMagnifier(offsetX, offsetX);
            super.moveWindowMagnifier(offsetX, offsetY);
            mSpyController.moveWindowMagnifier(offsetX, offsetY);
        }

+4 −4
Original line number Diff line number Diff line
@@ -618,18 +618,18 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
    public void performA11yActions_visible_expectedResults() {
        final int displayId = mContext.getDisplayId();
        mInstrumentation.runOnMainSync(() -> {
            mWindowMagnificationController.enableWindowMagnificationInternal(2.5f, Float.NaN,
            mWindowMagnificationController.enableWindowMagnificationInternal(1.5f, Float.NaN,
                    Float.NaN);
        });

        final View mirrorView = mWindowManager.getAttachedView();
        assertTrue(
                mirrorView.performAccessibilityAction(R.id.accessibility_action_zoom_out, null));
        // Minimum scale is 2.0.
        verify(mWindowMagnifierCallback).onPerformScaleAction(eq(displayId), eq(2.0f));
        // Minimum scale is 1.0.
        verify(mWindowMagnifierCallback).onPerformScaleAction(eq(displayId), eq(1.0f));

        assertTrue(mirrorView.performAccessibilityAction(R.id.accessibility_action_zoom_in, null));
        verify(mWindowMagnifierCallback).onPerformScaleAction(eq(displayId), eq(3.5f));
        verify(mWindowMagnifierCallback).onPerformScaleAction(eq(displayId), eq(2.5f));

        // TODO: Verify the final state when the mirror surface is visible.
        assertTrue(mirrorView.performAccessibilityAction(R.id.accessibility_action_move_up, null));
Loading