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

Commit 269725c9 authored by mincheli's avatar mincheli
Browse files

Transist the controlling magnification mode if needed for AccessibilityService

In go/b200769372 , Magnification mode transition
When the controlling magnifier switches the magnification mode,
MagnificationController should transitions to the config of the
targeting mode.

Bug: 204897462
Test: atest MagnificationProcessorTest,
    atest MagnificationControllerTest
Change-Id: Ife7369e39b9b256ee600e471b66e9869cd04024f
parent 3a5489c6
Loading
Loading
Loading
Loading
+94 −9
Original line number Diff line number Diff line
@@ -20,7 +20,9 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANIMATION_CALLBACK;

import android.accessibilityservice.MagnificationConfig;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -74,6 +76,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
    private final PointF mTempPoint = new PointF();
    private final Object mLock;
    private final Context mContext;
    @GuardedBy("mLock")
    private final SparseArray<DisableMagnificationCallback>
            mMagnificationEndRunnableSparseArray = new SparseArray();

@@ -208,7 +211,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
        final float scale = mScaleProvider.getScale(displayId);
        final DisableMagnificationCallback animationEndCallback =
                new DisableMagnificationCallback(transitionCallBack, displayId, targetMode,
                        scale, magnificationCenter);
                        scale, magnificationCenter, true);
        if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
            screenMagnificationController.reset(displayId, animationEndCallback);
        } else {
@@ -218,6 +221,77 @@ public class MagnificationController implements WindowMagnificationManager.Callb
        setDisableMagnificationCallbackLocked(displayId, animationEndCallback);
    }

    /**
     * Transitions to the targeting magnification config mode with current center of the
     * magnification mode if it is available. It disables the current magnifier immediately then
     * transitions to the targeting magnifier.
     *
     * @param displayId  The logical display id
     * @param config The targeting magnification config
     * @param animate    {@code true} to animate the transition, {@code false}
     *                   to transition immediately
     */
    public void transitionMagnificationConfigMode(int displayId, MagnificationConfig config,
            boolean animate) {
        synchronized (mLock) {
            final int targetMode = config.getMode();
            final PointF currentBoundsCenter = getCurrentMagnificationBoundsCenterLocked(displayId,
                    targetMode);
            final PointF magnificationCenter = new PointF(config.getCenterX(), config.getCenterY());
            if (currentBoundsCenter != null) {
                final float centerX = Float.isNaN(config.getCenterX())
                        ? currentBoundsCenter.x
                        : config.getCenterX();
                final float centerY = Float.isNaN(config.getCenterY())
                        ? currentBoundsCenter.y
                        : config.getCenterY();
                magnificationCenter.set(centerX, centerY);
            }

            final DisableMagnificationCallback animationCallback =
                    getDisableMagnificationEndRunnableLocked(displayId);
            if (animationCallback != null) {
                Slog.w(TAG, "Discard previous animation request");
                animationCallback.setExpiredAndRemoveFromListLocked();
            }

            final FullScreenMagnificationController screenMagnificationController =
                    getFullScreenMagnificationController();
            final WindowMagnificationManager windowMagnificationMgr = getWindowMagnificationMgr();
            final float scale = mScaleProvider.getScale(displayId);
            if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
                screenMagnificationController.reset(displayId, false);
                windowMagnificationMgr.enableWindowMagnification(displayId,
                        scale, magnificationCenter.x, magnificationCenter.y,
                        animate ? STUB_ANIMATION_CALLBACK : null);
            } else if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN) {
                windowMagnificationMgr.disableWindowMagnification(displayId, false, null);
                if (!screenMagnificationController.isRegistered(displayId)) {
                    screenMagnificationController.register(displayId);
                }
                screenMagnificationController.setScaleAndCenter(displayId, scale,
                        magnificationCenter.x, magnificationCenter.y, animate,
                        AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
            }
        }
    }

    /**
     * Return {@code true} if disable magnification animation callback of the display is running.
     *
     * @param displayId The logical display id
     */
    public boolean hasDisableMagnificationCallback(int displayId) {
        synchronized (mLock) {
            final DisableMagnificationCallback animationCallback =
                    getDisableMagnificationEndRunnableLocked(displayId);
            if (animationCallback != null) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void onRequestMagnificationSpec(int displayId, int serviceId) {
        final WindowMagnificationManager windowMagnificationManager;
@@ -267,7 +341,8 @@ public class MagnificationController implements WindowMagnificationManager.Callb
        // Internal request may be for transition, so we just need to check external request.
        final boolean isMagnifyByExternalRequest =
                fullScreenMagnificationController.getIdOfLastServiceToMagnify(displayId) > 0;
        if (isMagnifyByExternalRequest) {
        if (isMagnifyByExternalRequest || isActivated(displayId,
                ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN)) {
            fullScreenMagnificationController.reset(displayId, false);
        }
    }
@@ -518,15 +593,17 @@ public class MagnificationController implements WindowMagnificationManager.Callb
        private final int mCurrentMode;
        private final float mCurrentScale;
        private final PointF mCurrentCenter = new PointF();
        private final boolean mAnimate;

        DisableMagnificationCallback(TransitionCallBack transitionCallBack,
                int displayId, int targetMode, float scale, PointF currentCenter) {
        DisableMagnificationCallback(@Nullable TransitionCallBack transitionCallBack,
                int displayId, int targetMode, float scale, PointF currentCenter, boolean animate) {
            mTransitionCallBack = transitionCallBack;
            mDisplayId = displayId;
            mTargetMode = targetMode;
            mCurrentMode = mTargetMode ^ ACCESSIBILITY_MAGNIFICATION_MODE_ALL;
            mCurrentScale = scale;
            mCurrentCenter.set(currentCenter);
            mAnimate = animate;
        }

        @Override
@@ -544,9 +621,11 @@ public class MagnificationController implements WindowMagnificationManager.Callb
                    applyMagnificationModeLocked(mTargetMode);
                }
                updateMagnificationButton(mDisplayId, mTargetMode);
                if (mTransitionCallBack != null) {
                    mTransitionCallBack.onResult(mDisplayId, success);
                }
            }
        }

        private void adjustCurrentCenterIfNeededLocked() {
            if (mTargetMode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
@@ -569,9 +648,11 @@ public class MagnificationController implements WindowMagnificationManager.Callb
                setExpiredAndRemoveFromListLocked();
                applyMagnificationModeLocked(mCurrentMode);
                updateMagnificationButton(mDisplayId, mCurrentMode);
                if (mTransitionCallBack != null) {
                    mTransitionCallBack.onResult(mDisplayId, true);
                }
            }
        }

        void setExpiredAndRemoveFromListLocked() {
            mExpired = true;
@@ -580,9 +661,13 @@ public class MagnificationController implements WindowMagnificationManager.Callb

        private void applyMagnificationModeLocked(int mode) {
            if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN) {
                getFullScreenMagnificationController().setScaleAndCenter(mDisplayId,
                        mCurrentScale, mCurrentCenter.x,
                        mCurrentCenter.y, true,
                final FullScreenMagnificationController fullScreenMagnificationController =
                        getFullScreenMagnificationController();
                if (!fullScreenMagnificationController.isRegistered(mDisplayId)) {
                    fullScreenMagnificationController.register(mDisplayId);
                }
                fullScreenMagnificationController.setScaleAndCenter(mDisplayId, mCurrentScale,
                        mCurrentCenter.x, mCurrentCenter.y, mAnimate,
                        AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
            } else {
                getWindowMagnificationMgr().enableWindowMagnification(mDisplayId,
+19 −0
Original line number Diff line number Diff line
@@ -98,6 +98,10 @@ public class MagnificationProcessor {
     */
    public boolean setMagnificationConfig(int displayId, @NonNull MagnificationConfig config,
            boolean animate, int id) {
        if (transitionModeIfNeeded(displayId, config, animate)) {
            return true;
        }

        int configMode = config.getMode();
        if (configMode == DEFAULT_MODE) {
            configMode = getControllingMode(displayId);
@@ -113,6 +117,21 @@ public class MagnificationProcessor {
        return false;
    }

    /**
     * Returns {@code true} if transition magnification mode needed. And it is no need to transition
     * mode when the controlling mode is unchanged or the controlling magnifier is not activated.
     */
    private boolean transitionModeIfNeeded(int displayId, MagnificationConfig config,
            boolean animate) {
        int currentMode = getControllingMode(displayId);
        if (currentMode == config.getMode()
                || !mController.hasDisableMagnificationCallback(displayId)) {
            return false;
        }
        mController.transitionMagnificationConfigMode(displayId, config, animate);
        return true;
    }

    /**
     * Returns the magnification scale. If an animation is in progress,
     * this reflects the end state of the animation.
+29 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.accessibilityservice.MagnificationConfig.WINDOW_MODE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
@@ -316,6 +317,34 @@ public class MagnificationProcessorTest {
        assertConfigEquals(config, result);
    }

    @Test
    public void setMagnificationConfig_controllingModeChangeAndAnimating_transitionConfigMode() {
        final int currentActivatedMode = WINDOW_MODE;
        final int targetMode = FULLSCREEN_MODE;
        final MagnificationConfig oldConfig = new MagnificationConfig.Builder()
                .setMode(currentActivatedMode)
                .setScale(TEST_SCALE)
                .setCenterX(TEST_CENTER_X)
                .setCenterY(TEST_CENTER_Y).build();
        setMagnificationActivated(TEST_DISPLAY, oldConfig);
        final MagnificationConfig newConfig = new MagnificationConfig.Builder()
                .setMode(targetMode)
                .setScale(TEST_SCALE)
                .setCenterX(TEST_CENTER_X + 10)
                .setCenterY(TEST_CENTER_Y + 10).build();

        // Has magnification animation running
        when(mMockMagnificationController.hasDisableMagnificationCallback(TEST_DISPLAY)).thenReturn(
                true);
        setMagnificationActivated(TEST_DISPLAY, newConfig);

        final MagnificationConfig result = mMagnificationProcessor.getMagnificationConfig(
                TEST_DISPLAY);
        verify(mMockMagnificationController).transitionMagnificationConfigMode(eq(TEST_DISPLAY),
                eq(newConfig), anyBoolean());
        assertConfigEquals(newConfig, result);
    }

    private void setMagnificationActivated(int displayId, int configMode) {
        setMagnificationActivated(displayId,
                new MagnificationConfig.Builder().setMode(configMode).build());
+78 −1
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.accessibilityservice.MagnificationConfig;
import android.content.Context;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -229,7 +230,7 @@ public class MagnificationControllerTest {
    }

    @Test
    public void transitionToFullScreen_centerNotInTheBounds_magnifyTheCenterOfMagnificationBounds()
    public void transitionToFullScreen_centerNotInTheBounds_magnifyBoundsCenter()
            throws RemoteException {
        final Rect magnificationBounds = MAGNIFICATION_REGION.getBounds();
        final PointF magnifiedCenter = new PointF(magnificationBounds.right + 100,
@@ -288,6 +289,73 @@ public class MagnificationControllerTest {
        verify(mTransitionCallBack).onResult(TEST_DISPLAY, false);
    }

    @Test
    public void configTransitionToWindowMode_fullScreenMagnifying_disableFullScreenAndEnableWindow()
            throws RemoteException {
        activateMagnifier(MODE_FULLSCREEN, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);

        mMagnificationController.transitionMagnificationConfigMode(TEST_DISPLAY,
                obtainMagnificationConfig(MODE_WINDOW),
                false);

        verify(mScreenMagnificationController).reset(eq(TEST_DISPLAY), eq(false));
        mMockConnection.invokeCallbacks();
        assertEquals(MAGNIFIED_CENTER_X, mWindowMagnificationManager.getCenterX(TEST_DISPLAY), 0);
        assertEquals(MAGNIFIED_CENTER_Y, mWindowMagnificationManager.getCenterY(TEST_DISPLAY), 0);
    }

    @Test
    public void configTransitionToFullScreen_windowMagnifying_disableWindowAndEnableFullScreen()
            throws RemoteException {
        final boolean animate = true;
        activateMagnifier(MODE_WINDOW, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
        mMagnificationController.transitionMagnificationConfigMode(TEST_DISPLAY,
                obtainMagnificationConfig(MODE_FULLSCREEN),
                animate);
        mMockConnection.invokeCallbacks();

        assertFalse(mWindowMagnificationManager.isWindowMagnifierEnabled(TEST_DISPLAY));
        verify(mScreenMagnificationController).setScaleAndCenter(TEST_DISPLAY,
                DEFAULT_SCALE, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y,
                animate, MAGNIFICATION_GESTURE_HANDLER_ID);
    }

    @Test
    public void configTransitionToFullScreen_userSettingsDisablingFullScreen_enableFullScreen()
            throws RemoteException {
        activateMagnifier(MODE_FULLSCREEN, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
        // User-setting mode
        mMagnificationController.transitionMagnificationModeLocked(TEST_DISPLAY,
                MODE_WINDOW, mTransitionCallBack);

        // Config-setting mode
        mMagnificationController.transitionMagnificationConfigMode(TEST_DISPLAY,
                obtainMagnificationConfig(MODE_FULLSCREEN),
                true);

        assertEquals(DEFAULT_SCALE, mScreenMagnificationController.getScale(TEST_DISPLAY), 0);
        assertEquals(MAGNIFIED_CENTER_X, mScreenMagnificationController.getCenterX(TEST_DISPLAY),
                0);
        assertEquals(MAGNIFIED_CENTER_Y, mScreenMagnificationController.getCenterY(TEST_DISPLAY),
                0);
    }

    @Test
    public void interruptDuringTransitionToWindow_disablingFullScreen_discardPreviousTransition()
            throws RemoteException {
        activateMagnifier(MODE_FULLSCREEN, MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y);
        // User-setting mode
        mMagnificationController.transitionMagnificationModeLocked(TEST_DISPLAY,
                MODE_WINDOW, mTransitionCallBack);

        // Config-setting mode
        mMagnificationController.transitionMagnificationConfigMode(TEST_DISPLAY,
                obtainMagnificationConfig(MODE_FULLSCREEN),
                true);

        verify(mTransitionCallBack, never()).onResult(TEST_DISPLAY, true);
    }

    @Test
    public void onDisplayRemoved_notifyAllModules() {
        mMagnificationController.onDisplayRemoved(TEST_DISPLAY);
@@ -609,6 +677,10 @@ public class MagnificationControllerTest {
    private void setMagnificationEnabled(int mode, float centerX, float centerY)
            throws RemoteException {
        setMagnificationModeSettings(mode);
        activateMagnifier(mode, centerX, centerY);
    }

    private void activateMagnifier(int mode, float centerX, float centerY) throws RemoteException {
        mScreenMagnificationControllerStubber.resetAndStubMethods();
        final boolean windowMagnifying = mWindowMagnificationManager.isWindowMagnifierEnabled(
                TEST_DISPLAY);
@@ -631,6 +703,11 @@ public class MagnificationControllerTest {
                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, mode, CURRENT_USER_ID);
    }

    private MagnificationConfig obtainMagnificationConfig(int mode) {
        return new MagnificationConfig.Builder().setMode(mode).setScale(DEFAULT_SCALE).setCenterX(
                MAGNIFIED_CENTER_X).setCenterY(MAGNIFIED_CENTER_Y).build();
    }

    /**
     * Stubs public methods to simulate the real beahviours.
     */