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

This commit is contained in:
Minche Li
2020-10-11 04:57:23 +00:00
committed by Android (Google) Code Review
2 changed files with 86 additions and 53 deletions

View File

@@ -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;
}
mImageView.animate().cancel();
mWindowManager.removeView(mImageView);
// Reset button status.
mImageView.removeCallbacks(mFadeInAnimationTask);
mImageView.removeCallbacks(mFadeOutAnimationTask);
mImageView.animate().cancel();
mIsFadeOutAnimating = false;
mImageView.setAlpha(0f);
mWindowManager.removeView(mImageView);
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.
mImageView.animate().cancel();
mImageView.removeCallbacks(mAnimationTask);
mImageView.postDelayed(mAnimationTask, START_DELAY_MS);
if (mIsFadeOutAnimating) {
mImageView.animate().cancel();
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;
}

View File

@@ -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();
}
/**