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

Commit 855260af authored by ryanlwlin's avatar ryanlwlin
Browse files

Support enable window magnification without animation

To extend the magnification API to window magnification mode,
we support enabling the window magnification without animation.
Besides, we also disable the window magnification if the given scale
is less than or equal to 1.0f.

For the screen off scenario, we change to disable the window
magnification without animation.

Bug: 204844820
Test: atest com.android.systemui.accessibility
      atest com.android.server.accessibility.magnification
Change-Id: I8a35492776f08ecee353f035a94a16fec8e61218
parent 4d021782
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -21,6 +21,9 @@ package android.view.accessibility;
 * @hide
 */
public interface MagnificationAnimationCallback {
    MagnificationAnimationCallback STUB_ANIMATION_CALLBACK = success -> {
    };

    /**
     * Called when the animation is finished or interrupted during animating.
     *
+20 −2
Original line number Diff line number Diff line
@@ -106,6 +106,15 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
    void enableWindowMagnification(float scale, float centerX, float centerY,
            @Nullable IRemoteMagnificationAnimationCallback animationCallback) {
        sendAnimationCallback(false);
        // Enable window magnification without animation immediately.
        if (animationCallback == null) {
            if (mState == STATE_ENABLING || mState == STATE_DISABLING) {
                mValueAnimator.cancel();
            }
            mController.enableWindowMagnification(scale, centerX, centerY);
            setState(STATE_ENABLED);
            return;
        }
        mAnimationCallback = animationCallback;
        setupEnableAnimationSpecs(scale, centerX, centerY);
        if (mEndSpec.equals(mStartSpec)) {
@@ -173,6 +182,16 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
    void deleteWindowMagnification(
            @Nullable IRemoteMagnificationAnimationCallback animationCallback) {
        sendAnimationCallback(false);
        // Delete window magnification without animation.
        if (animationCallback == null) {
            if (mState == STATE_ENABLING || mState == STATE_DISABLING) {
                mValueAnimator.cancel();
            }
            mController.deleteWindowMagnification();
            setState(STATE_DISABLED);
            return;
        }

        mAnimationCallback = animationCallback;
        if (mState == STATE_DISABLED || mState == STATE_DISABLING) {
            if (mState == STATE_DISABLED) {
@@ -223,8 +242,7 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
        if (mEndAnimationCanceled) {
            return;
        }
        if (isReverse) {
            mController.deleteWindowMagnification();
        if (Float.isNaN(mController.getScale())) {
            setState(STATE_DISABLED);
        } else {
            setState(STATE_ENABLED);
+12 −1
Original line number Diff line number Diff line
@@ -262,6 +262,9 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
     * Deletes the magnification window.
     */
    void deleteWindowMagnification() {
        if (!isWindowVisible()) {
            return;
        }
        if (mMirrorSurface != null) {
            mTransaction.remove(mMirrorSurface).apply();
            mMirrorSurface = null;
@@ -690,7 +693,10 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
    }

    /**
     * Enables window magnification with specified parameters.
     * Enables window magnification with specified parameters. If the given scale is <strong>less
     * than or equal to 1.0f<strong>, then
     * {@link WindowMagnificationController#deleteWindowMagnification()} will be called instead to
     * be consistent with the behavior of display magnification.
     *
     * @param scale   the target scale, or {@link Float#NaN} to leave unchanged
     * @param centerX the screen-relative X coordinate around which to center,
@@ -699,6 +705,11 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold
     *                or {@link Float#NaN} to leave unchanged.
     */
    void enableWindowMagnification(float scale, float centerX, float centerY) {
        if (Float.compare(scale, 1.0f)  <= 0) {
            deleteWindowMagnification();
            return;
        }

        final float offsetX = Float.isNaN(centerX) ? 0
                : centerX - mMagnificationFrame.exactCenterX();
        final float offsetY = Float.isNaN(centerY) ? 0
+152 −14
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
@@ -61,11 +62,11 @@ import java.util.concurrent.atomic.AtomicReference;
@RunWith(AndroidTestingRunner.class)
public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {

    private static final float DEFAULT_SCALE = 3.0f;
    private static final float DEFAULT_SCALE = 4.0f;
    private static final float DEFAULT_CENTER_X = 400.0f;
    private static final float DEFAULT_CENTER_Y = 500.0f;
    // The duration couldn't too short, otherwise the ValueAnimator won't work in expectation.
    private static final long ANIMATION_DURATION_MS = 200;
    private static final long ANIMATION_DURATION_MS = 300;

    private AtomicReference<Float> mCurrentScale = new AtomicReference<>((float) 0);
    private AtomicReference<Float> mCurrentCenterX = new AtomicReference<>((float) 0);
@@ -84,7 +85,7 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
    IRemoteMagnificationAnimationCallback mAnimationCallback;
    @Mock
    IRemoteMagnificationAnimationCallback mAnimationCallback2;
    @Mock
    @Mock(answer = Answers.RETURNS_SELF)
    SysUiState mSysUiState;
    private SpyWindowMagnificationController mController;
    private WindowMagnificationController mSpyController;
@@ -127,6 +128,28 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
        verify(mAnimationCallback).onResult(true);
    }

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

        verifyFinalSpec(DEFAULT_SCALE, DEFAULT_CENTER_X, DEFAULT_CENTER_Y);
    }

    @Test
    public void enableWindowMagnificationWithoutCallback_enabled_expectedValues() {
        enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);
        final float targetScale = DEFAULT_SCALE + 1.0f;
        final float targetCenterX = DEFAULT_CENTER_X + 100;
        final float targetCenterY = DEFAULT_CENTER_Y + 100;

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

        verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
    }

    @Test
    public void enableWindowMagnificationWithScaleOne_disabled_NoAnimationAndInvokeCallback()
@@ -173,6 +196,52 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
        verify(mAnimationCallback2).onResult(true);
    }

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

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

        SystemClock.sleep(mWaitingAnimationPeriod);

        verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
                mCenterXCaptor.capture(), mCenterYCaptor.capture());
        verifyStartValue(mScaleCaptor, mCurrentScale.get());
        verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
        verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
        // It presents the window magnification is disabled.
        verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);

        verify(mAnimationCallback).onResult(true);
    }

    @Test
    public void
            enableMagnificationWithoutCallback_enabling_expectedValuesAndInvokeFormerCallback()
            throws RemoteException {
        enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
                mAnimationCallback);
        final float targetScale = DEFAULT_SCALE - 1.0f;
        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(targetScale, targetCenterX, targetCenterY);
        verify(mAnimationCallback).onResult(false);
    }

    @Test
    public void enableWindowMagnificationWithSameSpec_enabling_NoAnimationAndInvokeCallback()
            throws RemoteException {
@@ -230,6 +299,28 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
        verify(mAnimationCallback2).onResult(true);
    }

    @Test
    public void
            enableMagnificationWithoutCallback_disabling_expectedValuesAndInvokeFormerCallback()
            throws RemoteException {
        enableWindowMagnificationWithoutAnimation();
        deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
                mAnimationCallback);
        final float targetScale = DEFAULT_SCALE + 1.0f;
        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);
                });

        verify(mAnimationCallback).onResult(false);
        verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
    }

    @Test
    public void enableWindowMagnificationWithSameSpec_disabling_NoAnimationAndInvokeCallback()
            throws RemoteException {
@@ -254,8 +345,7 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
    @Test
    public void enableWindowMagnification_enabled_expectedValuesAndInvokeCallback()
            throws RemoteException {
        enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
                mAnimationCallback);
        enableWindowMagnificationWithoutAnimation();
        final float targetScale = DEFAULT_SCALE + 1.0f;
        final float targetCenterX = DEFAULT_CENTER_X + 100;
        final float targetCenterY = DEFAULT_CENTER_Y + 100;
@@ -277,7 +367,6 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
        verifyStartValue(mCenterXCaptor, mCurrentCenterX.get());
        verifyStartValue(mCenterYCaptor, mCurrentCenterY.get());
        verifyFinalSpec(targetScale, targetCenterX, targetCenterY);
        verify(mAnimationCallback).onResult(false);
        verify(mAnimationCallback2).onResult(true);
    }

@@ -295,7 +384,7 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {

    @Test
    public void setScale_enabled_expectedScale() {
        enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
        enableWindowMagnificationWithoutAnimation();

        mInstrumentation.runOnMainSync(
                () -> mWindowMagnificationAnimationController.setScale(DEFAULT_SCALE + 1));
@@ -307,13 +396,12 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
    @Test
    public void deleteWindowMagnification_enabled_expectedValuesAndInvokeCallback()
            throws RemoteException {
        enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
        enableWindowMagnificationWithoutAnimation();

        deleteWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, mAnimationCallback);

        verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
                mCenterXCaptor.capture(), mCenterYCaptor.capture());
        verify(mSpyController).deleteWindowMagnification();
        verifyStartValue(mScaleCaptor, DEFAULT_SCALE);
        verifyStartValue(mCenterXCaptor, Float.NaN);
        verifyStartValue(mCenterYCaptor, Float.NaN);
@@ -321,6 +409,15 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
        verify(mAnimationCallback).onResult(true);
    }

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

        deleteWindowMagnificationAndWaitAnimating(0, null);

        verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
    }

    @Test
    public void deleteWindowMagnification_disabled_doNothingAndInvokeCallback()
            throws RemoteException {
@@ -346,10 +443,8 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
                    mCurrentCenterY.set(mController.getCenterY());
                });
        SystemClock.sleep(mWaitingAnimationPeriod);

        verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
                mCenterXCaptor.capture(), mCenterYCaptor.capture());
        verify(mSpyController).deleteWindowMagnification();

        //The animation is in verse, so we only check the start values should no be greater than
        // the current one.
@@ -362,6 +457,22 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
        verify(mAnimationCallback2).onResult(true);
    }

    @Test
    public void deleteWindowMagnificationWithoutCallback_enabling_expectedValuesAndInvokeCallback()
            throws RemoteException {
        enableWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
                mAnimationCallback);

        mInstrumentation.runOnMainSync(
                () -> {
                    Mockito.reset(mSpyController);
                    mWindowMagnificationAnimationController.deleteWindowMagnification(null);
                });

        verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
        verify(mAnimationCallback).onResult(false);
    }

    @Test
    public void deleteWindowMagnification_disabling_checkStartAndValues() throws RemoteException {
        enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
@@ -372,7 +483,6 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {

        verify(mSpyController, atLeast(2)).enableWindowMagnification(mScaleCaptor.capture(),
                mCenterXCaptor.capture(), mCenterYCaptor.capture());
        verify(mSpyController).deleteWindowMagnification();
        assertEquals(1.0f, mScaleCaptor.getValue(), 0f);
        verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
        verify(mAnimationCallback).onResult(false);
@@ -380,8 +490,22 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
    }

    @Test
    public void moveWindowMagnifier_enabled() {
    public void deleteWindowMagnificationWithoutCallback_disabling_checkStartAndValues()
            throws RemoteException {
        enableWindowMagnificationAndWaitAnimating(mWaitingAnimationPeriod, null);
        deleteWindowMagnificationAndWaitAnimating(mWaitIntermediateAnimationPeriod,
                mAnimationCallback);

        deleteWindowMagnificationAndWaitAnimating(0, null);

        verify(mSpyController).deleteWindowMagnification();
        verifyFinalSpec(Float.NaN, Float.NaN, Float.NaN);
        verify(mAnimationCallback).onResult(false);
    }

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

        mInstrumentation.runOnMainSync(
                () -> mWindowMagnificationAnimationController.moveWindowMagnifier(100f, 200f));
@@ -411,6 +535,15 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
        assertEquals(expectedCenterY, mController.getCenterY(), 0f);
    }

    private void enableWindowMagnificationWithoutAnimation() {
        mInstrumentation.runOnMainSync(
                () -> {
                    Mockito.reset(mSpyController);
                    mWindowMagnificationAnimationController.enableWindowMagnification(DEFAULT_SCALE,
                            DEFAULT_CENTER_X, DEFAULT_CENTER_Y, null);
                });
    }

    private void enableWindowMagnificationAndWaitAnimating(long duration,
            @Nullable IRemoteMagnificationAnimationCallback callback) {
        mInstrumentation.runOnMainSync(
@@ -484,12 +617,17 @@ public class WindowMagnificationAnimationControllerTest extends SysuiTestCase {
            mSpyController.setScale(scale);
        }

        @Override
        public void updateSysUIStateFlag() {
            super.updateSysUIStateFlag();
            mSpyController.updateSysUIStateFlag();
        }

        @Override
        void onConfigurationChanged(int configDiff) {
            super.onConfigurationChanged(configDiff);
            mSpyController.onConfigurationChanged(configDiff);
        }

    }

    private static ValueAnimator newValueAnimator() {
+15 −0
Original line number Diff line number Diff line
@@ -468,6 +468,21 @@ public class WindowMagnificationControllerTest extends SysuiTestCase {
                com.android.internal.R.string.android_system_label), getAccessibilityWindowTitle());
    }

    @Test
    public void enableWindowMagnificationWithScaleLessThanOne_enabled_disabled() {
        mInstrumentation.runOnMainSync(() -> {
            mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
                    Float.NaN);
        });

        mInstrumentation.runOnMainSync(() -> {
            mWindowMagnificationController.enableWindowMagnification(0.9f, Float.NaN,
                    Float.NaN);
        });

        assertEquals(Float.NaN, mWindowMagnificationController.getScale(), 0);
    }

    @Test
    public void onLocaleChanged_enabled_updateA11yWindowTitle() {
        final String newA11yWindowTitle = "new a11y window title";
Loading