From 636aa9b3595530d89ef0eb7bdc4f2961109c32f5 Mon Sep 17 00:00:00 2001 From: mincheli Date: Fri, 18 Sep 2020 16:33:57 +0800 Subject: [PATCH] Applies Accessibility UI timeout for showing duration of magnification button Users can change Time to take action (Accessibility timeout) settings to make the magnification button showing duration aligned with recommended a11y UI timeout. Settings Page: Settings > Accessibility settings > Time to take action. Demo video: b/167977099#comment2 Bug: 167977099 Test: atest MagnificationModeSwitchTest Change-Id: I428b9d8221854edc476fcd455f3b9114b6b97ae9 --- .../MagnificationModeSwitch.java | 15 +++++--- .../accessibility/WindowMagnification.java | 3 +- .../MagnificationModeSwitchTest.java | 35 ++++++++++++++++--- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java index 69a0d65a69636..c6e5f09af5722 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java @@ -31,6 +31,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.view.WindowManager; +import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.widget.ImageView; @@ -48,15 +49,16 @@ class MagnificationModeSwitch { @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; + @VisibleForTesting + static final int DEFAULT_FADE_OUT_ANIMATION_DELAY_MS = 3000; + private int mUiTimeout; private final Runnable mFadeInAnimationTask; private final Runnable mFadeOutAnimationTask; @VisibleForTesting boolean mIsFadeOutAnimating = false; private final Context mContext; + private final AccessibilityManager mAccessibilityManager; private final WindowManager mWindowManager; private final ImageView mImageView; private final PointF mLastDown = new PointF(); @@ -74,6 +76,7 @@ class MagnificationModeSwitch { @VisibleForTesting MagnificationModeSwitch(Context context, @NonNull ImageView imageView) { mContext = context; + mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class); mWindowManager = (WindowManager) mContext.getSystemService( Context.WINDOW_SERVICE); mParams = createLayoutParams(); @@ -202,6 +205,10 @@ class MagnificationModeSwitch { mWindowManager.addView(mImageView, mParams); mIsVisible = true; mImageView.postOnAnimation(mFadeInAnimationTask); + mUiTimeout = mAccessibilityManager.getRecommendedTimeoutMillis( + DEFAULT_FADE_OUT_ANIMATION_DELAY_MS, + AccessibilityManager.FLAG_CONTENT_ICONS + | AccessibilityManager.FLAG_CONTENT_CONTROLS); } if (mIsFadeOutAnimating) { mImageView.animate().cancel(); @@ -209,7 +216,7 @@ class MagnificationModeSwitch { } // Refresh the time slot of the fade-out task whenever this method is called. mImageView.removeCallbacks(mFadeOutAnimationTask); - mImageView.postOnAnimationDelayed(mFadeOutAnimationTask, mVisibleDuration); + mImageView.postOnAnimationDelayed(mFadeOutAnimationTask, mUiTimeout); } void onConfigurationChanged(int configDiff) { diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java index a705ec784c9a1..e9e453b3d981e 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnification.java @@ -72,8 +72,7 @@ public class WindowMagnification extends SystemUI implements WindowMagnifierCall super(context); mHandler = mainHandler; mLastConfiguration = new Configuration(context.getResources().getConfiguration()); - mAccessibilityManager = (AccessibilityManager) mContext.getSystemService( - Context.ACCESSIBILITY_SERVICE); + mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class); mCommandQueue = commandQueue; mModeSwitchesController = modeSwitchesController; final WindowMagnificationController controller = new WindowMagnificationController(mContext, diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java index 3c248c73ab718..3da1f297dfe9f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java @@ -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.DEFAULT_FADE_OUT_ANIMATION_DELAY_MS; import static com.android.systemui.accessibility.MagnificationModeSwitch.FADING_ANIMATION_DURATION_MS; import static com.android.systemui.accessibility.MagnificationModeSwitch.getIconResId; @@ -33,6 +34,7 @@ import static org.hamcrest.CoreMatchers.hasItems; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyFloat; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; @@ -48,6 +50,7 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.ViewPropertyAnimator; import android.view.WindowManager; +import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.ImageView; @@ -74,6 +77,8 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { private ImageView mSpyImageView; @Mock + private AccessibilityManager mAccessibilityManager; + @Mock private WindowManager mWindowManager; @Mock private ViewPropertyAnimator mViewPropertyAnimator; @@ -89,6 +94,7 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { wm.getMaximumWindowMetrics() ).when(mWindowManager).getMaximumWindowMetrics(); mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager); + mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager); mSpyImageView = Mockito.spy(new ImageView(mContext)); resetMockImageViewAndAnimator(); @@ -108,16 +114,37 @@ public class MagnificationModeSwitchTest extends SysuiTestCase { @Test public void showWindowModeButton_fullscreenMode_addViewAndSetImageResource() { mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW); + verify(mSpyImageView).setImageResource( getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW)); + verify(mWindowManager).addView(eq(mSpyImageView), any(WindowManager.LayoutParams.class)); assertShowFadingAnimation(FADE_IN_ALPHA); assertShowFadingAnimation(FADE_OUT_ALPHA); + } - ArgumentCaptor captor = ArgumentCaptor.forClass(Runnable.class); - verify(mViewPropertyAnimator).withEndAction(captor.capture()); - verify(mWindowManager).addView(eq(mSpyImageView), any(WindowManager.LayoutParams.class)); + @Test + public void showMagnificationButton_a11yTimeout_autoFadeOut() { + final int a11yTimeout = 12345; + when(mAccessibilityManager.getRecommendedTimeoutMillis(anyInt(), anyInt())).thenReturn( + a11yTimeout); - captor.getValue().run(); + mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW); + + verify(mAccessibilityManager).getRecommendedTimeoutMillis( + DEFAULT_FADE_OUT_ANIMATION_DELAY_MS, AccessibilityManager.FLAG_CONTENT_ICONS + | AccessibilityManager.FLAG_CONTENT_CONTROLS); + final ArgumentCaptor fadeOutCaptor = ArgumentCaptor.forClass(Runnable.class); + final ArgumentCaptor fadeOutDelay = ArgumentCaptor.forClass(Long.class); + verify(mSpyImageView).postOnAnimationDelayed(fadeOutCaptor.capture(), + fadeOutDelay.capture()); + assertEquals(a11yTimeout, (long) fadeOutDelay.getValue()); + + // Verify the end action after fade-out. + fadeOutCaptor.getValue().run(); + final ArgumentCaptor endActionCaptor = ArgumentCaptor.forClass(Runnable.class); + verify(mViewPropertyAnimator).withEndAction(endActionCaptor.capture()); + + endActionCaptor.getValue().run(); verify(mViewPropertyAnimator).cancel(); verify(mWindowManager).removeView(mSpyImageView);