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

Commit 6045db95 authored by ryanlwlin's avatar ryanlwlin
Browse files

Add callback for enabling/disabling window magnification

To support switching magnification mode, we add callback to know
when the animation is finished. We only invoke the newest callback
when the animation is end successfully or the spec didn't change

Bug: 161669184
Test: atest com.android.systemui.accessibility
      atest com.android.server.accessibility.magnification
      Enable window magnification to see if it works normally
Change-Id: I34ce39d133a000964d1089946b7bcf510a618b40
parent 1be64f8a
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.view.accessibility;

import android.graphics.PointF;
import android.graphics.Rect;
import android.os.RemoteCallback;
import android.view.accessibility.IWindowMagnificationConnectionCallback;

/**
@@ -37,8 +38,10 @@ oneway interface IWindowMagnificationConnection {
     *                or {@link Float#NaN} to leave unchanged.
     * @param centerY the screen-relative Y coordinate around which to center,
     *                or {@link Float#NaN} to leave unchanged.
     * @param endCallback The callback called when the animation is completed.
     */
    void enableWindowMagnification(int displayId, float scale, float centerX, float centerY);
    void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
        in RemoteCallback endCallback);

    /**
     * Sets the scale of the window magnifier on specified display.
@@ -52,8 +55,9 @@ oneway interface IWindowMagnificationConnection {
     * Disables window magnification on specified display with animation.
     *
     * @param displayId The logical display id.
     * @param endCallback The callback called when the animation is completed.
     */
    void disableWindowMagnification(int displayId);
    void disableWindowMagnification(int displayId, in RemoteCallback endCallback);

    /**
     * Moves the window magnifier on the specified display. It has no effect while animating.
+14 −8
Original line number Diff line number Diff line
@@ -18,11 +18,13 @@ package com.android.systemui.accessibility;

import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Handler;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.util.Log;
import android.view.SurfaceControl;
@@ -98,9 +100,11 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
    }

    @MainThread
    void enableWindowMagnification(int displayId, float scale, float centerX, float centerY) {
    void enableWindowMagnification(int displayId, float scale, float centerX, float centerY,
            @Nullable RemoteCallback endCallback) {
        //TODO: b/144080869 support multi-display.
        mWindowMagnificationAnimationController.enableWindowMagnification(scale, centerX, centerY);
        mWindowMagnificationAnimationController.enableWindowMagnification(scale, centerX, centerY,
                endCallback != null ? () -> endCallback.sendResult(null) : null);
    }

    @MainThread
@@ -116,9 +120,10 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
    }

    @MainThread
    void disableWindowMagnification(int displayId) {
    void disableWindowMagnification(int displayId, @Nullable RemoteCallback endCallback) {
        //TODO: b/144080869 support multi-display.
        mWindowMagnificationAnimationController.deleteWindowMagnification();
        mWindowMagnificationAnimationController.deleteWindowMagnification(
                endCallback != null ? () -> endCallback.sendResult(null) : null);
    }

    @Override
@@ -177,10 +182,10 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall

        @Override
        public void enableWindowMagnification(int displayId, float scale, float centerX,
                float centerY) {
                float centerY, RemoteCallback remoteCallback) {
            mHandler.post(
                    () -> mWindowMagnification.enableWindowMagnification(displayId, scale, centerX,
                            centerY));
                            centerY, remoteCallback));
        }

        @Override
@@ -189,8 +194,9 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall
        }

        @Override
        public void disableWindowMagnification(int displayId) {
            mHandler.post(() -> mWindowMagnification.disableWindowMagnification(displayId));
        public void disableWindowMagnification(int displayId, RemoteCallback remoteCallback) {
            mHandler.post(() -> mWindowMagnification.disableWindowMagnification(displayId,
                    remoteCallback));
        }

        @Override
+58 −22
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.accessibility;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
import android.util.Log;
@@ -58,7 +59,11 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
    private final AnimationSpec mStartSpec = new AnimationSpec();
    private final AnimationSpec mEndSpec = new AnimationSpec();
    private final Context mContext;

    // Called when the animation is ended successfully without cancelling or mStartSpec and
    // mEndSpec are equal.
    private Runnable mAnimationEndCallback;
    // The flag to ignore the animation end callback.
    private boolean mEndAnimationCanceled = false;
    @MagnificationState
    private int mState = STATE_DISABLED;

@@ -83,26 +88,35 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
     * from 1.0 and the center won't be changed during the animation. If {@link #mState} is
     * {@code STATE_DISABLING}, the animation runs in reverse.
     *
     * @param scale   the target scale, or {@link Float#NaN} to leave unchanged.
     * @param centerX the screen-relative X coordinate around which to center,
     * @param scale   The target scale, or {@link Float#NaN} to leave unchanged.
     * @param centerX The screen-relative X coordinate around which to center,
     *                or {@link Float#NaN} to leave unchanged.
     * @param centerY the screen-relative Y coordinate around which to center,
     * @param centerY The screen-relative Y coordinate around which to center,
     *                or {@link Float#NaN} to leave unchanged.
     * @param animationEndCallback Called when the transition is complete or the given arguments
     *                      are as same as current values.
     *
     * @see #onAnimationUpdate(ValueAnimator)
     */
    void enableWindowMagnification(float scale, float centerX, float centerY) {
        if (mState == STATE_ENABLING) {
            mValueAnimator.cancel();
        }
    void enableWindowMagnification(float scale, float centerX, float centerY,
            @Nullable Runnable animationEndCallback) {
        mAnimationEndCallback = animationEndCallback;
        setupEnableAnimationSpecs(scale, centerX, centerY);

        if (mEndSpec.equals(mStartSpec)) {
            if (mState == STATE_DISABLED) {
                mController.enableWindowMagnification(scale, centerX, centerY);
            } else if (mState == STATE_ENABLING || mState == STATE_DISABLING) {
                mValueAnimator.cancel();
            }
            sendCallbackIfNeeded();
            setState(STATE_ENABLED);
        } else {
            if (mState == STATE_DISABLING) {
                mValueAnimator.reverse();
            } else {
                if (mState == STATE_ENABLING) {
                    mValueAnimator.cancel();
                }
                mValueAnimator.start();
            }
            setState(STATE_ENABLING);
@@ -145,9 +159,16 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
    /**
     * Wraps {@link WindowMagnificationController#deleteWindowMagnification()}} with transition
     * animation. If the window magnification is enabling, it runs the animation in reverse.
     *
     * @param animationEndCallback Called when the transition is complete or the window
     *                    magnification is disabled already.
     */
    void deleteWindowMagnification() {
    void deleteWindowMagnification(@Nullable Runnable animationEndCallback) {
        mAnimationEndCallback = animationEndCallback;
        if (mState == STATE_DISABLED || mState == STATE_DISABLING) {
            if (mState == STATE_DISABLED) {
                sendCallbackIfNeeded();
            }
            return;
        }
        mStartSpec.set(/* scale*/ 1.0f, Float.NaN, Float.NaN);
@@ -160,9 +181,9 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp
    /**
     * Wraps {@link WindowMagnificationController#moveWindowMagnifier(float, float)}. If the
     * animation is running, it has no effect.
     * @param offsetX the amount in pixels to offset the window magnifier in the X direction, in
     * @param offsetX The amount in pixels to offset the window magnifier in the X direction, in
     *                current screen pixels.
     * @param offsetY the amount in pixels to offset the window magnifier in the Y direction, in
     * @param offsetY The amount in pixels to offset the window magnifier in the Y direction, in
     *                current screen pixels.
     */
    void moveWindowMagnifier(float offsetX, float offsetY) {
@@ -185,28 +206,43 @@ class WindowMagnificationAnimationController implements ValueAnimator.AnimatorUp

    @Override
    public void onAnimationStart(Animator animation) {
        mEndAnimationCanceled = false;
    }

    @Override
    public void onAnimationEnd(Animator animation) {
        if (mState == STATE_DISABLING) {
    public void onAnimationEnd(Animator animation, boolean isReverse) {
        if (mEndAnimationCanceled) {
            return;
        }
        if (isReverse) {
            mController.deleteWindowMagnification();
            setState(STATE_DISABLED);
        } else if (mState == STATE_ENABLING) {
            setState(STATE_ENABLED);
        } else {
            Log.w(TAG, "onAnimationEnd unexpected state:" + mState);
            setState(STATE_ENABLED);
        }
        sendCallbackIfNeeded();
    }

    @Override
    public void onAnimationEnd(Animator animation) {
    }

    @Override
    public void onAnimationCancel(Animator animation) {
        mEndAnimationCanceled = true;
    }

    @Override
    public void onAnimationRepeat(Animator animation) {
    }

    private void sendCallbackIfNeeded() {
        if (mAnimationEndCallback != null) {
            mAnimationEndCallback.run();
            mAnimationEndCallback = null;
        }
    }

    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        final float fract = animation.getAnimatedFraction();
+20 −10
Original line number Diff line number Diff line
@@ -18,10 +18,12 @@ package com.android.systemui.accessibility;

import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;

import android.content.Context;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.provider.Settings;
import android.testing.AndroidTestingRunner;
@@ -39,6 +41,7 @@ import com.android.systemui.statusbar.CommandQueue;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

@@ -62,6 +65,9 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
    private WindowMagnificationAnimationController mWindowMagnificationAnimationController;
    @Mock
    private ModeSwitchesController mModeSwitchesController;
    @Mock
    private RemoteCallback mRemoteCallback;
    private ArgumentCaptor<Runnable> mRunnableCaptor = ArgumentCaptor.forClass(Runnable.class);
    private IWindowMagnificationConnection mIWindowMagnificationConnection;
    private WindowMagnification mWindowMagnification;

@@ -84,25 +90,24 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {
    }

    @Test
    public void enableWindowMagnification() throws RemoteException {
    public void enableWindowMagnification_passThrough() throws RemoteException {
        mIWindowMagnificationConnection.enableWindowMagnification(TEST_DISPLAY, 3.0f, Float.NaN,
                Float.NaN);
                Float.NaN, mRemoteCallback);
        waitForIdleSync();

        verify(mWindowMagnificationAnimationController).enableWindowMagnification(3.0f, Float.NaN,
                Float.NaN);
        verify(mWindowMagnificationAnimationController).enableWindowMagnification(eq(3.0f),
                eq(Float.NaN), eq(Float.NaN), mRunnableCaptor.capture());
        verifyRunnableWrapsRemoteCallback(mRunnableCaptor.getValue());
    }

    @Test
    public void disableWindowMagnification_deleteWindowMagnification() throws RemoteException {
        mIWindowMagnificationConnection.enableWindowMagnification(TEST_DISPLAY, 3.0f, Float.NaN,
                Float.NaN);
        waitForIdleSync();

        mIWindowMagnificationConnection.disableWindowMagnification(TEST_DISPLAY);
        mIWindowMagnificationConnection.disableWindowMagnification(TEST_DISPLAY, mRemoteCallback);
        waitForIdleSync();

        verify(mWindowMagnificationAnimationController).deleteWindowMagnification();
        verify(mWindowMagnificationAnimationController).deleteWindowMagnification(
                mRunnableCaptor.capture());
        verifyRunnableWrapsRemoteCallback(mRunnableCaptor.getValue());
    }

    @Test
@@ -138,5 +143,10 @@ public class IWindowMagnificationConnectionTest extends SysuiTestCase {

        verify(mModeSwitchesController).removeButton(TEST_DISPLAY);
    }

    private void verifyRunnableWrapsRemoteCallback(Runnable runnable) {
        runnable.run();
        verify(mRemoteCallback).sendResult(null);
    }
}
+138 −31

File changed.

Preview size limit exceeded, changes collapsed.

Loading