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

Commit 29f12866 authored by Minche Li's avatar Minche Li Committed by Android (Google) Code Review
Browse files

Merge "Magnification button applies fade-in and fade-out animation"

parents 8aced1f6 5d7e9fab
Loading
Loading
Loading
Loading
+32 −14
Original line number Diff line number Diff line
@@ -46,9 +46,15 @@ import com.android.systemui.R;
 */
class MagnificationModeSwitch {

    private static final int DURATION_MS = 5000;
    private static final int START_DELAY_MS = 3000;
    private final Runnable mAnimationTask;
    @VisibleForTesting
    static final long FADING_ANIMATION_DURATION_MS = 300;
    private static final int DEFAULT_FADE_OUT_ANIMATION_DELAY_MS = 3000;
    // The button visible duration starting from the last showButton() called.
    private int mVisibleDuration = DEFAULT_FADE_OUT_ANIMATION_DELAY_MS;
    private final Runnable mFadeInAnimationTask;
    private final Runnable mFadeOutAnimationTask;
    @VisibleForTesting
    boolean mIsFadeOutAnimating = false;

    private final Context mContext;
    private final WindowManager mWindowManager;
@@ -100,12 +106,19 @@ class MagnificationModeSwitch {
            }
        });

        mAnimationTask = () -> {
        mFadeInAnimationTask = () -> {
            mImageView.animate()
                    .alpha(1f)
                    .setDuration(FADING_ANIMATION_DURATION_MS)
                    .start();
        };
        mFadeOutAnimationTask = () -> {
            mImageView.animate()
                    .alpha(0f)
                    .setDuration(DURATION_MS)
                    .setDuration(FADING_ANIMATION_DURATION_MS)
                    .withEndAction(() -> removeButton())
                    .start();
            mIsFadeOutAnimating = true;
        };
    }

@@ -128,7 +141,6 @@ class MagnificationModeSwitch {
        }
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mImageView.setAlpha(1.0f);
                mImageView.animate().cancel();
                mLastDown.set(event.getRawX(), event.getRawY());
                mLastDrag.set(event.getRawX(), event.getRawY());
@@ -169,9 +181,13 @@ class MagnificationModeSwitch {
        if (!mIsVisible) {
            return;
        }
        // Reset button status.
        mImageView.removeCallbacks(mFadeInAnimationTask);
        mImageView.removeCallbacks(mFadeOutAnimationTask);
        mImageView.animate().cancel();
        mIsFadeOutAnimating = false;
        mImageView.setAlpha(0f);
        mWindowManager.removeView(mImageView);
        // Reset button status.
        mIsVisible = false;
        mParams.x = 0;
        mParams.y = 0;
@@ -185,14 +201,15 @@ class MagnificationModeSwitch {
        if (!mIsVisible) {
            mWindowManager.addView(mImageView, mParams);
            mIsVisible = true;
            mImageView.postOnAnimation(mFadeInAnimationTask);
        }
        mImageView.setAlpha(1.0f);
        // TODO(b/143852371): use accessibility timeout as a delay.
        // Dismiss the magnification switch button after the button is displayed for a period of
        // time.
        if (mIsFadeOutAnimating) {
            mImageView.animate().cancel();
        mImageView.removeCallbacks(mAnimationTask);
        mImageView.postDelayed(mAnimationTask, START_DELAY_MS);
            mImageView.setAlpha(1f);
        }
        // Refresh the time slot of the fade-out task whenever this method is called.
        mImageView.removeCallbacks(mFadeOutAnimationTask);
        mImageView.postOnAnimationDelayed(mFadeOutAnimationTask, mVisibleDuration);
    }

    void onConfigurationChanged(int configDiff) {
@@ -222,6 +239,7 @@ class MagnificationModeSwitch {
        imageView.setClickable(true);
        imageView.setFocusable(true);
        imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
        imageView.setAlpha(0f);
        return imageView;
    }

+53 −38
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK;

import static com.android.systemui.accessibility.MagnificationModeSwitch.FADING_ANIMATION_DURATION_MS;
import static com.android.systemui.accessibility.MagnificationModeSwitch.getIconResId;

import static junit.framework.Assert.assertEquals;
@@ -35,7 +36,6 @@ import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@@ -69,6 +69,9 @@ import org.mockito.MockitoAnnotations;
@RunWith(AndroidTestingRunner.class)
public class MagnificationModeSwitchTest extends SysuiTestCase {

    private static final float FADE_IN_ALPHA = 1f;
    private static final float FADE_OUT_ALPHA = 0f;

    private ImageView mSpyImageView;
    @Mock
    private WindowManager mWindowManager;
@@ -87,49 +90,47 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
        ).when(mWindowManager).getMaximumWindowMetrics();
        mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
        mSpyImageView = Mockito.spy(new ImageView(mContext));
        doAnswer(invocation -> null).when(mSpyImageView).setOnTouchListener(
                mTouchListenerCaptor.capture());
        initMockImageViewAndAnimator();
        resetMockImageViewAndAnimator();

        mMagnificationModeSwitch = new MagnificationModeSwitch(mContext, mSpyImageView);
    }

    @Test
    public void removeButton_removeView() {
    public void removeButton_buttonIsShowing_removeView() {
        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);

        mMagnificationModeSwitch.removeButton();

        verify(mWindowManager).removeView(mSpyImageView);
        // First invocation is in showButton.
        verify(mViewPropertyAnimator, times(2)).cancel();
        verify(mViewPropertyAnimator).cancel();
    }

    @Test
    public void showWindowModeButton_fullscreenMode_addViewAndSetImageResource() {
        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);

        verify(mSpyImageView).setAlpha(1.0f);
        verify(mSpyImageView).setImageResource(
                getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW));
        assertShowButtonAnimation();
        assertShowFadingAnimation(FADE_IN_ALPHA);
        assertShowFadingAnimation(FADE_OUT_ALPHA);

        ArgumentCaptor<Runnable> captor = ArgumentCaptor.forClass(Runnable.class);
        verify(mViewPropertyAnimator).withEndAction(captor.capture());
        verify(mWindowManager).addView(eq(mSpyImageView), any(WindowManager.LayoutParams.class));

        captor.getValue().run();

        // First invocation is in showButton.
        verify(mViewPropertyAnimator, times(2)).cancel();
        verify(mViewPropertyAnimator).cancel();
        verify(mWindowManager).removeView(mSpyImageView);
    }

    @Test
    public void onConfigurationChanged_setImageResource() {
    public void onConfigurationChanged_buttonIsShowing_setImageResource() {
        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
        resetMockImageViewAndAnimator();

        mMagnificationModeSwitch.onConfigurationChanged(ActivityInfo.CONFIG_DENSITY);

        verify(mSpyImageView, times(2)).setImageResource(
        verify(mSpyImageView).setImageResource(
                getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN));
    }

@@ -162,7 +163,6 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
        listener.onTouch(mSpyImageView, MotionEvent.obtain(
                0, 0, ACTION_DOWN, 100, 100, 0));
        verify(mSpyImageView).setAlpha(1.0f);
        verify(mViewPropertyAnimator).cancel();

        listener.onTouch(mSpyImageView, MotionEvent.obtain(
@@ -173,9 +173,8 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
        resetMockImageViewAndAnimator();
        listener.onTouch(mSpyImageView, MotionEvent.obtain(
                0, ViewConfiguration.getTapTimeout() + 10, ACTION_UP, 100 + offset, 100, 0));
        verify(mSpyImageView).setAlpha(1.0f);
        assertModeUnchanged(previousMode);
        assertShowButtonAnimation();
        assertShowFadingAnimation(FADE_OUT_ALPHA);
    }

    @Test
@@ -193,9 +192,8 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
        resetMockImageViewAndAnimator();
        listener.onTouch(mSpyImageView, MotionEvent.obtain(
                0, ViewConfiguration.getTapTimeout(), ACTION_CANCEL, 100, 100, 0));
        verify(mSpyImageView).setAlpha(1.0f);
        assertModeUnchanged(previousMode);
        assertShowButtonAnimation();
        assertShowFadingAnimation(FADE_OUT_ALPHA);
    }

    @Test
@@ -216,9 +214,8 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
        resetMockImageViewAndAnimator();
        listener.onTouch(mSpyImageView, MotionEvent.obtain(
                0, ViewConfiguration.getTapTimeout(), ACTION_CANCEL, 100 + offset, 100, 0));
        verify(mSpyImageView).setAlpha(1.0f);
        assertModeUnchanged(previousMode);
        assertShowButtonAnimation();
        assertShowFadingAnimation(FADE_OUT_ALPHA);
    }

    @Test
@@ -249,37 +246,55 @@ public class MagnificationModeSwitchTest extends SysuiTestCase {
        verifyTapAction(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
    }

    @Test
    public void showButton_showFadeOutAnimation_fadeOutAnimationCanceled() {
        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
        assertShowFadingAnimation(FADE_OUT_ALPHA);
        resetMockImageViewAndAnimator();

        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);

        verify(mViewPropertyAnimator).cancel();
        assertEquals(1f, mSpyImageView.getAlpha());
        assertShowFadingAnimation(FADE_OUT_ALPHA);
    }

    private void assertModeUnchanged(int expectedMode) {
        final int actualMode = Settings.Secure.getInt(mContext.getContentResolver(),
                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, 0);
        assertEquals(expectedMode, actualMode);
    }

    private void assertShowButtonAnimation() {
        verify(mViewPropertyAnimator).cancel();
        verify(mViewPropertyAnimator).setDuration(anyLong());
        verify(mViewPropertyAnimator).alpha(anyFloat());
    private void assertShowFadingAnimation(float alpha) {
        ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
        if (alpha == FADE_IN_ALPHA) { // Fade-in
            verify(mSpyImageView).postOnAnimation(runnableCaptor.capture());
        } else { // Fade-out
            verify(mSpyImageView).postOnAnimationDelayed(runnableCaptor.capture(), anyLong());
        }
        resetMockAnimator();

        runnableCaptor.getValue().run();

        verify(mViewPropertyAnimator).setDuration(eq(FADING_ANIMATION_DURATION_MS));
        verify(mViewPropertyAnimator).alpha(alpha);
        verify(mViewPropertyAnimator).start();
    }

    private void initMockImageViewAndAnimator() {
    private void resetMockImageViewAndAnimator() {
        Mockito.reset(mSpyImageView);
        doAnswer(invocation -> null).when(mSpyImageView).setOnTouchListener(
                mTouchListenerCaptor.capture());
        resetMockAnimator();
    }

    private void resetMockAnimator() {
        Mockito.reset(mViewPropertyAnimator);
        when(mViewPropertyAnimator.setDuration(anyLong())).thenReturn(mViewPropertyAnimator);
        when(mViewPropertyAnimator.alpha(anyFloat())).thenReturn(mViewPropertyAnimator);
        when(mViewPropertyAnimator.withEndAction(any(Runnable.class))).thenReturn(
                mViewPropertyAnimator);

        when(mSpyImageView.animate()).thenReturn(mViewPropertyAnimator);
        doAnswer(invocation -> {
            Runnable run = invocation.getArgument(0);
            run.run();
            return null;
        }).when(mSpyImageView).postDelayed(any(), anyLong());
    }

    private void resetMockImageViewAndAnimator() {
        Mockito.reset(mViewPropertyAnimator);
        Mockito.reset(mSpyImageView);
        initMockImageViewAndAnimator();
    }

    /**