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

Commit db026034 authored by ryanlwlin's avatar ryanlwlin
Browse files

Fix inconsistent scale when setting magnificaotion config

We used to use MagnificationScaleProvider to retrive the
scale when transitioning the mode, which is incorrect
because the provider only persists the scale changed by users.
If the scale is changed by public api, then the scale will
become inconsistent.

To fix it we choose the scale based on the target  mode.
We also fix that mode transition without animation should be
considered as a transition case.

We also add more log for flaky CTS debugging.

Bug: 218792845
Test: atest MagnificationProcessorTest
      atest com.android.server.accessibility.magnification
Change-Id: I47f49345ce46f726d6e06e203110ef793f35c76e
parent 6cba6c1b
Loading
Loading
Loading
Loading
+31 −17
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb

    private static final boolean DEBUG = false;
    private static final String TAG = "MagnificationController";

    private final AccessibilityManagerService mAms;
    private final PointF mTempPoint = new PointF();
    private final Object mLock;
@@ -194,11 +195,10 @@ public class MagnificationController implements WindowMagnificationManager.Callb
     */
    public void transitionMagnificationModeLocked(int displayId, int targetMode,
            @NonNull TransitionCallBack transitionCallBack) {
        final PointF magnificationCenter = getCurrentMagnificationBoundsCenterLocked(displayId,
                targetMode);
        final PointF currentCenter = getCurrentMagnificationCenterLocked(displayId, targetMode);
        final DisableMagnificationCallback animationCallback =
                getDisableMagnificationEndRunnableLocked(displayId);
        if (magnificationCenter == null && animationCallback == null) {
        if (currentCenter == null && animationCallback == null) {
            transitionCallBack.onResult(displayId, true);
            return;
        }
@@ -213,7 +213,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
            }
        }

        if (magnificationCenter == null) {
        if (currentCenter == null) {
            Slog.w(TAG, "Invalid center, ignore it");
            transitionCallBack.onResult(displayId, true);
            return;
@@ -221,10 +221,10 @@ public class MagnificationController implements WindowMagnificationManager.Callb
        final FullScreenMagnificationController screenMagnificationController =
                getFullScreenMagnificationController();
        final WindowMagnificationManager windowMagnificationMgr = getWindowMagnificationMgr();
        final float scale = mScaleProvider.getScale(displayId);
        final float scale = getTargetModeScaleFromCurrentMagnification(displayId, targetMode);
        final DisableMagnificationCallback animationEndCallback =
                new DisableMagnificationCallback(transitionCallBack, displayId, targetMode,
                        scale, magnificationCenter, true);
                        scale, currentCenter, true);
        if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
            screenMagnificationController.reset(displayId, animationEndCallback);
        } else {
@@ -247,17 +247,20 @@ public class MagnificationController implements WindowMagnificationManager.Callb
     */
    public void transitionMagnificationConfigMode(int displayId, MagnificationConfig config,
            boolean animate, int id) {
        if (DEBUG) {
            Slog.d(TAG, "transitionMagnificationConfigMode displayId = " + displayId
                    + ", config = " + config);
        }
        synchronized (mLock) {
            final int targetMode = config.getMode();
            final PointF currentBoundsCenter = getCurrentMagnificationBoundsCenterLocked(displayId,
                    targetMode);
            final PointF currentCenter = getCurrentMagnificationCenterLocked(displayId, targetMode);
            final PointF magnificationCenter = new PointF(config.getCenterX(), config.getCenterY());
            if (currentBoundsCenter != null) {
            if (currentCenter != null) {
                final float centerX = Float.isNaN(config.getCenterX())
                        ? currentBoundsCenter.x
                        ? currentCenter.x
                        : config.getCenterX();
                final float centerY = Float.isNaN(config.getCenterY())
                        ? currentBoundsCenter.y
                        ? currentCenter.y
                        : config.getCenterY();
                magnificationCenter.set(centerX, centerY);
            }
@@ -272,24 +275,36 @@ public class MagnificationController implements WindowMagnificationManager.Callb
            final FullScreenMagnificationController screenMagnificationController =
                    getFullScreenMagnificationController();
            final WindowMagnificationManager windowMagnificationMgr = getWindowMagnificationMgr();
            final float scale = mScaleProvider.getScale(displayId);
            final float targetScale = Float.isNaN(config.getScale())
                    ? getTargetModeScaleFromCurrentMagnification(displayId, targetMode)
                    : config.getScale();
            if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
                screenMagnificationController.reset(displayId, false);
                windowMagnificationMgr.enableWindowMagnification(displayId,
                        scale, magnificationCenter.x, magnificationCenter.y,
                        targetScale, magnificationCenter.x, magnificationCenter.y,
                        animate ? STUB_ANIMATION_CALLBACK : null, id);
            } else if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN) {
                windowMagnificationMgr.disableWindowMagnification(displayId, false, null);
                if (!screenMagnificationController.isRegistered(displayId)) {
                    screenMagnificationController.register(displayId);
                }
                screenMagnificationController.setScaleAndCenter(displayId, scale,
                screenMagnificationController.setScaleAndCenter(displayId, targetScale,
                        magnificationCenter.x, magnificationCenter.y, animate,
                        id);
            }
        }
    }

    // We assume the target mode is different from the current mode, and there is only
    // two modes, so we get the target scale from another mode.
    private float getTargetModeScaleFromCurrentMagnification(int displayId, int targetMode) {
        if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
            return getFullScreenMagnificationController().getScale(displayId);
        } else {
            return getWindowMagnificationMgr().getScale(displayId);
        }
    }

    /**
     * Return {@code true} if disable magnification animation callback of the display is running.
     *
@@ -384,7 +399,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
    public void onSourceBoundsChanged(int displayId, Rect bounds) {
        final MagnificationConfig config = new MagnificationConfig.Builder()
                .setMode(MAGNIFICATION_MODE_WINDOW)
                .setScale(mScaleProvider.getScale(displayId))
                .setScale(getWindowMagnificationMgr().getScale(displayId))
                .setCenterX(bounds.exactCenterX())
                .setCenterY(bounds.exactCenterY()).build();
        mAms.notifyMagnificationChanged(displayId, new Region(bounds), config);
@@ -607,8 +622,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
        }
    }

    private @Nullable
            PointF getCurrentMagnificationBoundsCenterLocked(int displayId, int targetMode) {
    private @Nullable PointF getCurrentMagnificationCenterLocked(int displayId, int targetMode) {
        if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN) {
            if (mWindowMagnificationMgr == null
                    || !mWindowMagnificationMgr.isWindowMagnifierEnabled(displayId)) {
+16 −7
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static android.view.accessibility.MagnificationAnimationCallback.STUB_ANI
import android.accessibilityservice.MagnificationConfig;
import android.annotation.NonNull;
import android.graphics.Region;
import android.util.Slog;
import android.view.Display;

import java.io.PrintWriter;
@@ -56,6 +57,9 @@ import java.util.ArrayList;
 */
public class MagnificationProcessor {

    private static final String TAG = "MagnificationProcessor";
    private static final boolean DEBUG = false;

    private final MagnificationController mController;

    public MagnificationProcessor(MagnificationController controller) {
@@ -103,6 +107,9 @@ public class MagnificationProcessor {
     */
    public boolean setMagnificationConfig(int displayId, @NonNull MagnificationConfig config,
            boolean animate, int id) {
        if (DEBUG) {
            Slog.d(TAG, "setMagnificationConfig config=" + config);
        }
        if (transitionModeIfNeeded(displayId, config, animate, id)) {
            return true;
        }
@@ -125,15 +132,13 @@ public class MagnificationProcessor {
    }

    private boolean setScaleAndCenterForFullScreenMagnification(int displayId, float scale,
            float centerX, float centerY,
            boolean animate, int id) {
            float centerX, float centerY, boolean animate, int id) {

        if (!isRegistered(displayId)) {
            register(displayId);
        }
        return mController.getFullScreenMagnificationController().setScaleAndCenter(
                displayId,
                scale,
                centerX, centerY, animate, id);
                displayId, scale, centerX, centerY, animate, id);
    }

    /**
@@ -143,8 +148,12 @@ public class MagnificationProcessor {
    private boolean transitionModeIfNeeded(int displayId, MagnificationConfig config,
            boolean animate, int id) {
        int currentMode = getControllingMode(displayId);
        if (currentMode == config.getMode()
                || !mController.hasDisableMagnificationCallback(displayId)) {
        if (config.getMode() == MagnificationConfig.MAGNIFICATION_MODE_DEFAULT) {
            return false;
        }
        // Target mode is as same as current mode and is not transitioning.
        if (currentMode == config.getMode() && !mController.hasDisableMagnificationCallback(
                displayId)) {
            return false;
        }
        mController.transitionMagnificationConfigMode(displayId, config, animate, id);
+22 −12
Original line number Diff line number Diff line
@@ -177,6 +177,9 @@ public class WindowMagnificationManager implements
     * @param connection {@link IWindowMagnificationConnection}
     */
    public void setConnection(@Nullable IWindowMagnificationConnection connection) {
        if (DBG) {
            Slog.d(TAG, "setConnection :" + connection);
        }
        synchronized (mLock) {
            // Reset connectionWrapper.
            if (mConnectionWrapper != null) {
@@ -223,6 +226,9 @@ public class WindowMagnificationManager implements
     * @return {@code true} if {@link IWindowMagnificationConnection} state is going to change.
     */
    public boolean requestConnection(boolean connect) {
        if (DBG) {
            Slog.d(TAG, "requestConnection :" + connect);
        }
        synchronized (mLock) {
            if (connect == isConnected()) {
                return false;
@@ -485,10 +491,6 @@ public class WindowMagnificationManager implements
        final boolean enabled;
        boolean previousEnabled;
        synchronized (mLock) {
            if (mConnectionWrapper == null) {
                Slog.w(TAG, "enableWindowMagnification failed: connection null");
                return false;
            }
            WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
            if (magnifier == null) {
                magnifier = createWindowMagnifier(displayId);
@@ -528,10 +530,10 @@ public class WindowMagnificationManager implements
        final boolean disabled;
        synchronized (mLock) {
            WindowMagnifier magnifier = mWindowMagnifiers.get(displayId);
            if (magnifier == null || mConnectionWrapper == null) {
                Slog.w(TAG, "disableWindowMagnification failed: connection " + mConnectionWrapper);
            if (magnifier == null) {
                return false;
            }

            disabled = magnifier.disableWindowMagnificationInternal(animationCallback);
            if (clear) {
                mWindowMagnifiers.delete(displayId);
@@ -1018,25 +1020,33 @@ public class WindowMagnificationManager implements
        }
    }

    @GuardedBy("mLock")
    private boolean enableWindowMagnificationInternal(int displayId, float scale, float centerX,
            float centerY, float magnificationFrameOffsetRatioX,
            float magnificationFrameOffsetRatioY,
            MagnificationAnimationCallback animationCallback) {
        synchronized (mLock) {
            return mConnectionWrapper != null && mConnectionWrapper.enableWindowMagnification(
        if (mConnectionWrapper == null) {
            Slog.w(TAG, "enableWindowMagnificationInternal mConnectionWrapper is null");
            return false;
        }
        return  mConnectionWrapper.enableWindowMagnification(
                displayId, scale, centerX, centerY,
                magnificationFrameOffsetRatioX, magnificationFrameOffsetRatioY,
                animationCallback);
    }
    }

    private boolean setScaleInternal(int displayId, float scale) {
        return mConnectionWrapper != null && mConnectionWrapper.setScale(displayId, scale);
    }

    @GuardedBy("mLock")
    private boolean disableWindowMagnificationInternal(int displayId,
            MagnificationAnimationCallback animationCallback) {
        return mConnectionWrapper != null && mConnectionWrapper.disableWindowMagnification(
        if (mConnectionWrapper == null) {
            Slog.w(TAG, "mConnectionWrapper is null");
            return false;
        }
        return mConnectionWrapper.disableWindowMagnification(
                displayId, animationCallback);
    }

+58 −9
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@@ -342,9 +343,58 @@ public class MagnificationProcessorTest {
    }

    @Test
    public void setMagnificationConfig_controllingModeChangeAndAnimating_transitionConfigMode() {
    public void setWindowModeConfig_fullScreenMode_transitionConfigMode() {
        final int currentActivatedMode = MAGNIFICATION_MODE_FULLSCREEN;
        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 targetConfig = new MagnificationConfig.Builder()
                .setMode(MAGNIFICATION_MODE_WINDOW)
                .setScale(TEST_SCALE)
                .setCenterX(TEST_CENTER_X + 10)
                .setCenterY(TEST_CENTER_Y + 10).build();

        mMagnificationProcessor.setMagnificationConfig(TEST_DISPLAY, targetConfig, false,
                SERVICE_ID);

        verify(mMockMagnificationController).transitionMagnificationConfigMode(eq(TEST_DISPLAY),
                eq(targetConfig), eq(false), eq(SERVICE_ID));
    }

    @Test
    public void setConfigWithDefaultMode_fullScreenMode_expectedConfig() {
        final MagnificationConfig oldConfig = new MagnificationConfig.Builder()
                .setMode(MAGNIFICATION_MODE_FULLSCREEN)
                .setScale(TEST_SCALE)
                .setCenterX(TEST_CENTER_X)
                .setCenterY(TEST_CENTER_Y).build();
        setMagnificationActivated(TEST_DISPLAY, oldConfig);
        final MagnificationConfig targetConfig = new MagnificationConfig.Builder()
                .setScale(TEST_SCALE + 1)
                .setCenterX(TEST_CENTER_X + 10)
                .setCenterY(TEST_CENTER_Y + 10).build();

        mMagnificationProcessor.setMagnificationConfig(TEST_DISPLAY, targetConfig, false,
                SERVICE_ID);

        verify(mMockMagnificationController, never()).transitionMagnificationConfigMode(
                eq(TEST_DISPLAY), any(MagnificationConfig.class), eq(false), eq(SERVICE_ID));
        final MagnificationConfig expectedConfig = new MagnificationConfig.Builder()
                .setMode(MAGNIFICATION_MODE_FULLSCREEN)
                .setScale(TEST_SCALE + 1)
                .setCenterX(TEST_CENTER_X + 10)
                .setCenterY(TEST_CENTER_Y + 10).build();
        assertConfigEquals(expectedConfig,
                mMagnificationProcessor.getMagnificationConfig(TEST_DISPLAY));
    }

    @Test
    public void setWindowModeConfig_transitionToFullScreenModeWithAnimation_transitionConfigMode() {
        final int currentActivatedMode = MAGNIFICATION_MODE_WINDOW;
        final int targetMode = MAGNIFICATION_MODE_FULLSCREEN;
        final int targetMode = MAGNIFICATION_MODE_WINDOW;
        final MagnificationConfig oldConfig = new MagnificationConfig.Builder()
                .setMode(currentActivatedMode)
                .setScale(TEST_SCALE)
@@ -356,17 +406,14 @@ public class MagnificationProcessorTest {
                .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);
        mMagnificationProcessor.setMagnificationConfig(TEST_DISPLAY, newConfig, false, SERVICE_ID);

        verify(mMockMagnificationController).transitionMagnificationConfigMode(eq(TEST_DISPLAY),
                eq(newConfig), anyBoolean(), anyInt());
        assertConfigEquals(newConfig, result);
    }

    private void setMagnificationActivated(int displayId, int configMode) {
@@ -383,7 +430,7 @@ public class MagnificationProcessorTest {
                    MAGNIFICATION_MODE_WINDOW)).thenReturn(false);
            mFullScreenMagnificationControllerStub.resetAndStubMethods();
            mMockFullScreenMagnificationController.setScaleAndCenter(displayId, config.getScale(),
                    config.getCenterX(), config.getCenterY(), true, SERVICE_ID);
                    config.getCenterX(), config.getCenterY(), false, SERVICE_ID);
        } else if (config.getMode() == MAGNIFICATION_MODE_WINDOW) {
            when(mMockMagnificationController.isActivated(displayId,
                    MAGNIFICATION_MODE_FULLSCREEN)).thenReturn(false);
@@ -429,7 +476,7 @@ public class MagnificationProcessorTest {
            };
            doAnswer(enableMagnificationStubAnswer).when(
                    mScreenMagnificationController).setScaleAndCenter(eq(TEST_DISPLAY), anyFloat(),
                    anyFloat(), anyFloat(), eq(true), eq(SERVICE_ID));
                    anyFloat(), anyFloat(), anyBoolean(), eq(SERVICE_ID));

            Answer registerStubAnswer = invocation -> {
                mIsRegistered = true;
@@ -444,6 +491,8 @@ public class MagnificationProcessorTest {
            };
            doAnswer(unregisterStubAnswer).when(
                    mScreenMagnificationController).unregister(eq(TEST_DISPLAY));
            doAnswer(unregisterStubAnswer).when(
                    mScreenMagnificationController).reset(eq(TEST_DISPLAY), anyBoolean());
        }

        public void resetAndStubMethods() {
+113 −63

File changed.

Preview size limit exceeded, changes collapsed.

Loading