From 84c898de460812dde80f1954e7ddff37c2b7a3ee Mon Sep 17 00:00:00 2001 From: Roy Chou Date: Fri, 9 Jun 2023 14:59:43 +0000 Subject: [PATCH 1/2] fix(#WindowMagnification): adjust Settings getter def to true for key ACCESSIBILITY_ALLOW_DIAGONAL_SCROLLING As b/279397954, the allow diagonal scrolling default should be true by default. Therefore, we adjust the Settings getter to return true if Settings.Secure.ACCESSIBILITY_ALLOW_DIAGONAL_SCROLLING value is UN_ASSIGNED. Bug: 279397954 Test: manually atest WindowMagnificationControllerTest atest WindowMagnificationSettingsTest Change-Id: I244903a3fbf11a73998f440941b82c57f8ac4ef3 --- .../WindowMagnificationController.java | 9 ++++++++ .../WindowMagnificationSettings.java | 11 ++++++++-- .../WindowMagnificationControllerTest.java | 9 ++++++++ .../WindowMagnificationSettingsTest.java | 22 ++++++++++++++++++- 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java index 602f817f826b1..6c8f8f39646e1 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java @@ -262,6 +262,9 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, mResources.getInteger(R.integer.magnification_default_scale), UserHandle.USER_CURRENT); + mAllowDiagonalScrolling = secureSettings.getIntForUser( + Settings.Secure.ACCESSIBILITY_ALLOW_DIAGONAL_SCROLLING, 1, + UserHandle.USER_CURRENT) == 1; setupMagnificationSizeScaleOptions(); @@ -1225,6 +1228,12 @@ class WindowMagnificationController implements View.OnTouchListener, SurfaceHold return isActivated() ? mMagnificationFrame.exactCenterY() : Float.NaN; } + + @VisibleForTesting + boolean isDiagonalScrollingEnabled() { + return mAllowDiagonalScrolling; + } + private CharSequence formatStateDescription(float scale) { // Cache the locale-appropriate NumberFormat. Configuration locale is guaranteed // non-null, so the first time this is called we will always get the appropriate diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java index bb29d52cf160c..7c11311373abd 100644 --- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java +++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationSettings.java @@ -101,7 +101,9 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest private Button mEditButton; private ImageButton mFullScreenButton; private int mLastSelectedButtonIndex = MagnificationSize.NONE; + private boolean mAllowDiagonalScrolling = false; + /** * Amount by which magnification scale changes compared to seekbar in settings. * magnitude = 10 means, for every 1 scale increase, 10 progress increase in seekbar. @@ -141,7 +143,7 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest mSecureSettings = secureSettings; mAllowDiagonalScrolling = mSecureSettings.getIntForUser( - Settings.Secure.ACCESSIBILITY_ALLOW_DIAGONAL_SCROLLING, 0, + Settings.Secure.ACCESSIBILITY_ALLOW_DIAGONAL_SCROLLING, 1, UserHandle.USER_CURRENT) == 1; mParams = createLayoutParams(context); @@ -420,6 +422,11 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest UserHandle.USER_CURRENT); } + @VisibleForTesting + boolean isDiagonalScrollingEnabled() { + return mAllowDiagonalScrolling; + } + /** * Only called from outside to notify the controlling magnifier scale changed * @@ -632,7 +639,7 @@ class WindowMagnificationSettings implements MagnificationGestureDetector.OnGest private void toggleDiagonalScrolling() { boolean enabled = mSecureSettings.getIntForUser( - Settings.Secure.ACCESSIBILITY_ALLOW_DIAGONAL_SCROLLING, 0, + Settings.Secure.ACCESSIBILITY_ALLOW_DIAGONAL_SCROLLING, 1, UserHandle.USER_CURRENT) == 1; setDiagonalScrolling(!enabled); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java index 56f81606a2826..36cdfe642874f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java @@ -66,6 +66,7 @@ import android.graphics.RegionIterator; import android.os.Handler; import android.os.RemoteException; import android.os.SystemClock; +import android.provider.Settings; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableResources; @@ -223,6 +224,14 @@ public class WindowMagnificationControllerTest extends SysuiTestCase { mValueAnimator.cancel(); } + @Test + public void initWindowMagnificationController_checkAllowDiagonalScrollingWithSecureSettings() { + verify(mSecureSettings).getIntForUser( + eq(Settings.Secure.ACCESSIBILITY_ALLOW_DIAGONAL_SCROLLING), + /* def */ eq(1), /* userHandle= */ anyInt()); + assertTrue(mWindowMagnificationController.isDiagonalScrollingEnabled()); + } + @Test public void enableWindowMagnification_showControlAndNotifyBoundsChanged() { mInstrumentation.runOnMainSync(() -> { diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java index eddb8d186d737..91c47480ae456 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationSettingsTest.java @@ -26,10 +26,12 @@ import static com.google.common.truth.Truth.assertThat; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; +import static org.mockito.AdditionalAnswers.returnsSecondArg; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -109,6 +111,11 @@ public class WindowMagnificationSettingsTest extends SysuiTestCase { mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager); mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, mAccessibilityManager); + when(mSecureSettings.getIntForUser(anyString(), anyInt(), anyInt())).then( + returnsSecondArg()); + when(mSecureSettings.getFloatForUser(anyString(), anyFloat(), anyInt())).then( + returnsSecondArg()); + mWindowMagnificationSettings = new WindowMagnificationSettings(mContext, mWindowMagnificationSettingsCallback, mSfVsyncFrameProvider, mSecureSettings); @@ -127,6 +134,14 @@ public class WindowMagnificationSettingsTest extends SysuiTestCase { mWindowMagnificationSettings.hideSettingPanel(); } + @Test + public void initSettingPanel_checkAllowDiagonalScrollingWithSecureSettings() { + verify(mSecureSettings).getIntForUser( + eq(Settings.Secure.ACCESSIBILITY_ALLOW_DIAGONAL_SCROLLING), + /* def */ eq(1), /* userHandle= */ anyInt()); + assertThat(mWindowMagnificationSettings.isDiagonalScrollingEnabled()).isTrue(); + } + @Test public void showSettingPanel_hasAccessibilityWindowTitle() { setupMagnificationCapabilityAndMode( @@ -273,7 +288,12 @@ public class WindowMagnificationSettingsTest extends SysuiTestCase { // Perform click diagonalScrollingSwitch.performClick(); - verify(mWindowMagnificationSettingsCallback).onSetDiagonalScrolling(!currentCheckedState); + final boolean isAllowed = !currentCheckedState; + verify(mSecureSettings).putIntForUser( + eq(Settings.Secure.ACCESSIBILITY_ALLOW_DIAGONAL_SCROLLING), + /* value= */ eq(isAllowed ? 1 : 0), + /* userHandle= */ anyInt()); + verify(mWindowMagnificationSettingsCallback).onSetDiagonalScrolling(isAllowed); } @Test From 1736e28e1161d8f9d9941090d917e0f8c06909d9 Mon Sep 17 00:00:00 2001 From: Roy Chou Date: Wed, 5 Jul 2023 09:35:06 +0000 Subject: [PATCH 2/2] chore(#Magnification): use persisted scale if zoom-in-temporary when magnifier is zoomed out by service Originally when the fullscreen magnifier is activated, using triple-tap-and-hold to temporarily zoom in would use (current scale + 1) as the furthur zoom in scale. We add two cases that would zoom in with persisted scale. 1. User just tap the shortcut to activate the magnifier. 2. The magnifier just zooms out due to user context changed such as transitions or rotations. For these two cases we conclude the expected bahaviour should be zooming in with persisted scale. Bug: 289131167 Test: manually atest FullScreenMagnificationControllerTest atest FullScreenMagnificationGestureHandlerTest Change-Id: I0a48e1465763c5387bbac537471de82efff7caf5 --- .../FullScreenMagnificationController.java | 57 +++- ...FullScreenMagnificationGestureHandler.java | 12 +- ...FullScreenMagnificationControllerTest.java | 15 ++ ...ScreenMagnificationGestureHandlerTest.java | 255 +++++++++++------- 4 files changed, 231 insertions(+), 108 deletions(-) diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java index 3f3fa3419117c..d33d224cb2d26 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java @@ -142,6 +142,8 @@ public class FullScreenMagnificationController implements private int mIdOfLastServiceToMagnify = INVALID_SERVICE_ID; private boolean mMagnificationActivated = false; + private boolean mZoomedOutFromService = false; + @GuardedBy("mLock") @Nullable private MagnificationThumbnail mMagnificationThumbnail; DisplayMagnification(int displayId) { @@ -545,6 +547,24 @@ public class FullScreenMagnificationController implements return changed; } + /** + * Directly Zooms out the scale to 1f with animating the transition. This method is + * triggered only by service automatically, such as when user context changed. + */ + void zoomOutFromService() { + setScaleAndCenter(1.0f, Float.NaN, Float.NaN, + transformToStubCallback(true), + AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); + mZoomedOutFromService = true; + } + + /** + * Whether the zooming out is triggered by {@link #zoomOutFromService}. + */ + boolean isZoomedOutFromService() { + return mZoomedOutFromService; + } + @GuardedBy("mLock") boolean reset(boolean animate) { return reset(transformToStubCallback(animate)); @@ -619,6 +639,8 @@ public class FullScreenMagnificationController implements mIdOfLastServiceToMagnify); }); } + // the zoom scale would be changed so we reset the flag + mZoomedOutFromService = false; return changed; } @@ -944,9 +966,7 @@ public class FullScreenMagnificationController implements } if (isAlwaysOnMagnificationEnabled()) { - setScaleAndCenter(displayId, 1.0f, Float.NaN, Float.NaN, - true, - AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); + zoomOutFromService(displayId); } else { reset(displayId, true); } @@ -1427,6 +1447,37 @@ public class FullScreenMagnificationController implements MagnificationScaleProvider.MAX_SCALE); } + /** + * Directly Zooms out the scale to 1f with animating the transition. This method is + * triggered only by service automatically, such as when user context changed. + * + * @param displayId The logical display id. + */ + private void zoomOutFromService(int displayId) { + synchronized (mLock) { + final DisplayMagnification display = mDisplays.get(displayId); + if (display == null || !display.isActivated()) { + return; + } + display.zoomOutFromService(); + } + } + + /** + * Whether the magnification is zoomed out by {@link #zoomOutFromService(int)}. + * + * @param displayId The logical display id. + */ + public boolean isZoomedOutFromService(int displayId) { + synchronized (mLock) { + final DisplayMagnification display = mDisplays.get(displayId); + if (display == null || !display.isActivated()) { + return false; + } + return display.isZoomedOutFromService(); + } + } + /** * Resets all displays' magnification if last magnifying service is disabled. * diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java index 4aebbf11c7afc..03ba29519d732 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java @@ -1093,7 +1093,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH mViewportDraggingState.prepareForZoomInTemporary(shortcutTriggered); - zoomInTemporary(down.getX(), down.getY()); + zoomInTemporary(down.getX(), down.getY(), shortcutTriggered); transitionTo(mViewportDraggingState); } @@ -1150,14 +1150,20 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH } } - private void zoomInTemporary(float centerX, float centerY) { + private void zoomInTemporary(float centerX, float centerY, boolean shortcutTriggered) { final float currentScale = mFullScreenMagnificationController.getScale(mDisplayId); final float persistedScale = MathUtils.constrain( mFullScreenMagnificationController.getPersistedScale(mDisplayId), MIN_SCALE, MAX_SCALE); final boolean isActivated = mFullScreenMagnificationController.isActivated(mDisplayId); - final float scale = isActivated ? (currentScale + 1.0f) : persistedScale; + final boolean isShortcutTriggered = shortcutTriggered; + final boolean isZoomedOutFromService = + mFullScreenMagnificationController.isZoomedOutFromService(mDisplayId); + + boolean zoomInWithPersistedScale = + !isActivated || isShortcutTriggered || isZoomedOutFromService; + final float scale = zoomInWithPersistedScale ? persistedScale : (currentScale + 1.0f); zoomToScale(scale, centerX, centerY); } diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java index 5b5c8d415f84f..1b024982c41f9 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java @@ -130,6 +130,8 @@ public class FullScreenMagnificationControllerTest { public DisplayManagerInternal mDisplayManagerInternalMock = mock(DisplayManagerInternal.class); + private float mOriginalMagnificationPersistedScale; + @Before public void setUp() { Looper looper = InstrumentationRegistry.getContext().getMainLooper(); @@ -143,6 +145,9 @@ public class FullScreenMagnificationControllerTest { mResolver = new MockContentResolver(); mResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); when(mMockContext.getContentResolver()).thenReturn(mResolver); + mOriginalMagnificationPersistedScale = Settings.Secure.getFloatForUser(mResolver, + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, 2.0f, + CURRENT_USER_ID); Settings.Secure.putFloatForUser(mResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, 2.0f, CURRENT_USER_ID); @@ -169,6 +174,10 @@ public class FullScreenMagnificationControllerTest { @After public void tearDown() { mMessageCapturingHandler.removeAllMessages(); + Settings.Secure.putFloatForUser(mResolver, + Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, + mOriginalMagnificationPersistedScale, + CURRENT_USER_ID); } @@ -1311,7 +1320,10 @@ public class FullScreenMagnificationControllerTest { mFullScreenMagnificationController.setAlwaysOnMagnificationEnabled(false); mFullScreenMagnificationController.onUserContextChanged(DISPLAY_0); + // the magnifier should be deactivated. verify(mRequestObserver).onFullScreenMagnificationActivationState(eq(DISPLAY_0), eq(false)); + assertFalse(mFullScreenMagnificationController.isZoomedOutFromService(DISPLAY_0)); + verify(mMockThumbnail).setThumbnailBounds( /* currentBounds= */ any(), /* scale= */ anyFloat(), @@ -1330,8 +1342,11 @@ public class FullScreenMagnificationControllerTest { mFullScreenMagnificationController.setAlwaysOnMagnificationEnabled(true); mFullScreenMagnificationController.onUserContextChanged(DISPLAY_0); + // the magnifier should be zoomed out and keep activated by service action. assertEquals(1.0f, mFullScreenMagnificationController.getScale(DISPLAY_0), 0); assertTrue(mFullScreenMagnificationController.isActivated(DISPLAY_0)); + assertTrue(mFullScreenMagnificationController.isZoomedOutFromService(DISPLAY_0)); + verify(mMockThumbnail).setThumbnailBounds( /* currentBounds= */ any(), /* scale= */ anyFloat(), diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java index 989aee06a1df8..9304b32ec2c0e 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java @@ -96,19 +96,29 @@ import java.util.function.IntConsumer; * NON_ACTIVATED_ZOOMED_TMP -> IDLE [label="release"] * SHORTCUT_TRIGGERED -> IDLE [label="a11y\nbtn"] * SHORTCUT_TRIGGERED -> ACTIVATED [label="tap"] - * SHORTCUT_TRIGGERED -> SHORTCUT_TRIGGERED_ZOOMED_TMP [label="hold"] - * SHORTCUT_TRIGGERED -> PANNING [label="2hold] + * SHORTCUT_TRIGGERED -> ZOOMED_WITH_PERSISTED_SCALE_TMP [label="hold"] + * SHORTCUT_TRIGGERED -> PANNING [label="2hold"] + * ZOOMED_OUT_FROM_SERVICE -> IDLE [label="a11y\nbtn"] + * ZOOMED_OUT_FROM_SERVICE -> ZOOMED_OUT_FROM_SERVICE_DOUBLE_TAP [label="2tap"] + * ZOOMED_OUT_FROM_SERVICE -> PANNING [label="2hold"] + * ZOOMED_OUT_FROM_SERVICE_DOUBLE_TAP -> IDLE [label="tap"] + * ZOOMED_OUT_FROM_SERVICE_DOUBLE_TAP -> ZOOMED_OUT_FROM_SERVICE [label="timeout"] + * ZOOMED_OUT_FROM_SERVICE_DOUBLE_TAP -> ZOOMED_WITH_PERSISTED_SCALE_TMP [label="hold"] * if always-on enabled: - * SHORTCUT_TRIGGERED_ZOOMED_TMP -> ACTIVATED [label="release"] + * ZOOMED_WITH_PERSISTED_SCALE_TMP -> ACTIVATED [label="release"] * else: - * SHORTCUT_TRIGGERED_ZOOMED_TMP -> IDLE [label="release"] + * ZOOMED_WITH_PERSISTED_SCALE_TMP -> IDLE [label="release"] * ACTIVATED -> ACTIVATED_DOUBLE_TAP [label="2tap"] * ACTIVATED -> IDLE [label="a11y\nbtn"] * ACTIVATED -> PANNING [label="2hold"] + * if always-on enabled: + * ACTIVATED -> ZOOMED_OUT_FROM_SERVICE [label="contextChanged"] + * else: + * ACTIVATED -> IDLE [label="contextChanged"] * ACTIVATED_DOUBLE_TAP -> ACTIVATED [label="timeout"] - * ACTIVATED_DOUBLE_TAP -> ACTIVATED_ZOOMED_TMP [label="hold"] + * ACTIVATED_DOUBLE_TAP -> ZOOMED_FURTHER_TMP [label="hold"] * ACTIVATED_DOUBLE_TAP -> IDLE [label="tap"] - * ACTIVATED_ZOOMED_TMP -> ACTIVATED [label="release"] + * ZOOMED_FURTHER_TMP -> ACTIVATED [label="release"] * PANNING -> ACTIVATED [label="release"] * PANNING -> PANNING_SCALING [label="pinch"] * PANNING_SCALING -> ACTIVATED [label="release"] @@ -120,15 +130,20 @@ public class FullScreenMagnificationGestureHandlerTest { public static final int STATE_IDLE = 1; public static final int STATE_ACTIVATED = 2; - public static final int STATE_2TAPS = 3; - public static final int STATE_ACTIVATED_2TAPS = 4; - public static final int STATE_SHORTCUT_TRIGGERED = 5; - public static final int STATE_NON_ACTIVATED_ZOOMED_TMP = 6; - public static final int STATE_ACTIVATED_ZOOMED_TMP = 7; - public static final int STATE_SHORTCUT_TRIGGERED_ZOOMED_TMP = 8; - public static final int STATE_PANNING = 9; - public static final int STATE_SCALING_AND_PANNING = 10; - public static final int STATE_SINGLE_PANNING = 11; + public static final int STATE_SHORTCUT_TRIGGERED = 3; + public static final int STATE_ZOOMED_OUT_FROM_SERVICE = 4; + + public static final int STATE_2TAPS = 5; + public static final int STATE_ACTIVATED_2TAPS = 6; + public static final int STATE_ZOOMED_OUT_FROM_SERVICE_2TAPS = 7; + + public static final int STATE_NON_ACTIVATED_ZOOMED_TMP = 8; + public static final int STATE_ZOOMED_FURTHER_TMP = 9; + public static final int STATE_ZOOMED_WITH_PERSISTED_SCALE_TMP = 10; + + public static final int STATE_PANNING = 11; + public static final int STATE_SCALING_AND_PANNING = 12; + public static final int STATE_SINGLE_PANNING = 13; public static final int FIRST_STATE = STATE_IDLE; public static final int LAST_STATE = STATE_SINGLE_PANNING; @@ -313,7 +328,7 @@ public class FullScreenMagnificationGestureHandlerTest { assertTransition(STATE_SHORTCUT_TRIGGERED, () -> { send(downEvent()); fastForward1sec(); - }, STATE_SHORTCUT_TRIGGERED_ZOOMED_TMP); + }, STATE_ZOOMED_WITH_PERSISTED_SCALE_TMP); // A11y button followed by a tap turns magnifier on assertTransition(STATE_SHORTCUT_TRIGGERED, () -> tap(), STATE_ACTIVATED); @@ -337,22 +352,22 @@ public class FullScreenMagnificationGestureHandlerTest { assertTransition(STATE_2TAPS, () -> swipeAndHold(), STATE_NON_ACTIVATED_ZOOMED_TMP); // release when activated temporary zoom in back to activated - assertTransition(STATE_ACTIVATED_ZOOMED_TMP, () -> send(upEvent()), STATE_ACTIVATED); + assertTransition(STATE_ZOOMED_FURTHER_TMP, () -> send(upEvent()), STATE_ACTIVATED); } @Test - public void testRelease_shortcutTriggeredZoomedTmp_alwaysOnNotEnabled_shouldInIdle() { + public void testRelease_zoomedWithPersistedScaleTmpAndAlwaysOnNotEnabled_shouldInIdle() { mFullScreenMagnificationController.setAlwaysOnMagnificationEnabled(false); - goFromStateIdleTo(STATE_SHORTCUT_TRIGGERED_ZOOMED_TMP); + goFromStateIdleTo(STATE_ZOOMED_WITH_PERSISTED_SCALE_TMP); send(upEvent()); assertIn(STATE_IDLE); } @Test - public void testRelease_shortcutTriggeredZoomedTmp_alwaysOnEnabled_shouldInActivated() { + public void testRelease_zoomedWithPersistedScaleTmpAndAlwaysOnEnabled_shouldInActivated() { mFullScreenMagnificationController.setAlwaysOnMagnificationEnabled(true); - goFromStateIdleTo(STATE_SHORTCUT_TRIGGERED_ZOOMED_TMP); + goFromStateIdleTo(STATE_ZOOMED_WITH_PERSISTED_SCALE_TMP); send(upEvent()); assertIn(STATE_ACTIVATED); @@ -404,9 +419,11 @@ public class FullScreenMagnificationGestureHandlerTest { @Test public void testTripleTapAndHold_zoomsImmediately() { assertZoomsImmediatelyOnSwipeFrom(STATE_2TAPS, STATE_NON_ACTIVATED_ZOOMED_TMP); + assertZoomsImmediatelyOnSwipeFrom(STATE_ACTIVATED_2TAPS, STATE_ZOOMED_FURTHER_TMP); assertZoomsImmediatelyOnSwipeFrom(STATE_SHORTCUT_TRIGGERED, - STATE_SHORTCUT_TRIGGERED_ZOOMED_TMP); - assertZoomsImmediatelyOnSwipeFrom(STATE_ACTIVATED_2TAPS, STATE_ACTIVATED_ZOOMED_TMP); + STATE_ZOOMED_WITH_PERSISTED_SCALE_TMP); + assertZoomsImmediatelyOnSwipeFrom(STATE_ZOOMED_OUT_FROM_SERVICE_2TAPS, + STATE_ZOOMED_WITH_PERSISTED_SCALE_TMP); } @Test @@ -755,6 +772,10 @@ public class FullScreenMagnificationGestureHandlerTest { mHandler.timeAdvance(); } + private void triggerContextChanged() { + mFullScreenMagnificationController.onUserContextChanged(DISPLAY_0); + } + /** * Asserts that {@link #mMgh the handler} is in the given {@code state} */ @@ -763,43 +784,63 @@ public class FullScreenMagnificationGestureHandlerTest { // Asserts on separate lines for accurate stack traces - case STATE_IDLE: { + case STATE_IDLE: check(tapCount() < 2, state); check(!mMgh.mDetectingState.mShortcutTriggered, state); check(!isActivated(), state); check(!isZoomed(), state); - } break; - case STATE_ACTIVATED: { + break; + case STATE_ACTIVATED: check(isActivated(), state); check(tapCount() < 2, state); - } break; - case STATE_2TAPS: { + break; + case STATE_SHORTCUT_TRIGGERED: + check(mMgh.mDetectingState.mShortcutTriggered, state); + check(isActivated(), state); + check(!isZoomed(), state); + break; + case STATE_ZOOMED_OUT_FROM_SERVICE: + // the always-on feature must be enabled then this state is reachable. + assertTrue(mFullScreenMagnificationController.isAlwaysOnMagnificationEnabled()); + check(isActivated(), state); + check(!isZoomed(), state); + check(mMgh.mFullScreenMagnificationController.isZoomedOutFromService(DISPLAY_0), + state); + break; + case STATE_2TAPS: check(!isActivated(), state); check(!isZoomed(), state); check(tapCount() == 2, state); - } break; - case STATE_ACTIVATED_2TAPS: { + break; + case STATE_ACTIVATED_2TAPS: check(isActivated(), state); check(isZoomed(), state); check(tapCount() == 2, state); - } break; - case STATE_NON_ACTIVATED_ZOOMED_TMP: { + break; + case STATE_ZOOMED_OUT_FROM_SERVICE_2TAPS: + check(isActivated(), state); + check(!isZoomed(), state); + check(mMgh.mFullScreenMagnificationController.isZoomedOutFromService(DISPLAY_0), + state); + check(tapCount() == 2, state); + break; + case STATE_NON_ACTIVATED_ZOOMED_TMP: check(isActivated(), state); check(isZoomed(), state); check(mMgh.mCurrentState == mMgh.mViewportDraggingState, state); check(Float.isNaN(mMgh.mViewportDraggingState.mScaleToRecoverAfterDraggingEnd), state); - } break; - case STATE_ACTIVATED_ZOOMED_TMP: { + break; + case STATE_ZOOMED_FURTHER_TMP: check(isActivated(), state); check(isZoomed(), state); check(mMgh.mCurrentState == mMgh.mViewportDraggingState, state); check(mMgh.mViewportDraggingState.mScaleToRecoverAfterDraggingEnd >= 1.0f, state); - } break; - case STATE_SHORTCUT_TRIGGERED_ZOOMED_TMP: { + break; + case STATE_ZOOMED_WITH_PERSISTED_SCALE_TMP: check(isActivated(), state); check(isZoomed(), state); check(mMgh.mCurrentState == mMgh.mViewportDraggingState, @@ -811,29 +852,25 @@ public class FullScreenMagnificationGestureHandlerTest { check(Float.isNaN(mMgh.mViewportDraggingState.mScaleToRecoverAfterDraggingEnd), state); } - } break; - case STATE_SHORTCUT_TRIGGERED: { - check(mMgh.mDetectingState.mShortcutTriggered, state); - check(isActivated(), state); - check(!isZoomed(), state); - } break; - case STATE_PANNING: { + break; + case STATE_PANNING: check(isActivated(), state); check(mMgh.mCurrentState == mMgh.mPanningScalingState, state); check(!mMgh.mPanningScalingState.mScaling, state); - } break; - case STATE_SCALING_AND_PANNING: { + break; + case STATE_SCALING_AND_PANNING: check(isActivated(), state); check(mMgh.mCurrentState == mMgh.mPanningScalingState, state); check(mMgh.mPanningScalingState.mScaling, state); - } break; - case STATE_SINGLE_PANNING: { + break; + case STATE_SINGLE_PANNING: check(isZoomed(), state); check(mMgh.mCurrentState == mMgh.mSinglePanningState, state); - } break; - default: throw new IllegalArgumentException("Illegal state: " + state); + break; + default: + throw new IllegalArgumentException("Illegal state: " + state); } } @@ -843,15 +880,10 @@ public class FullScreenMagnificationGestureHandlerTest { private void goFromStateIdleTo(int state) { try { switch (state) { - case STATE_IDLE: { + case STATE_IDLE: mMgh.clearAndTransitionToStateDetecting(); - } break; - case STATE_2TAPS: { - goFromStateIdleTo(STATE_IDLE); - tap(); - tap(); - } break; - case STATE_ACTIVATED: { + break; + case STATE_ACTIVATED: if (mMgh.mDetectTripleTap) { goFromStateIdleTo(STATE_2TAPS); tap(); @@ -859,47 +891,63 @@ public class FullScreenMagnificationGestureHandlerTest { goFromStateIdleTo(STATE_SHORTCUT_TRIGGERED); tap(); } - } break; - case STATE_ACTIVATED_2TAPS: { + break; + case STATE_SHORTCUT_TRIGGERED: + goFromStateIdleTo(STATE_IDLE); + triggerShortcut(); + break; + case STATE_ZOOMED_OUT_FROM_SERVICE: + // the always-on feature must be enabled then this state is reachable. + assertTrue(mFullScreenMagnificationController.isAlwaysOnMagnificationEnabled()); + goFromStateIdleTo(STATE_ACTIVATED); + triggerContextChanged(); + break; + case STATE_2TAPS: + goFromStateIdleTo(STATE_IDLE); + tap(); + tap(); + break; + case STATE_ACTIVATED_2TAPS: goFromStateIdleTo(STATE_ACTIVATED); tap(); tap(); - } break; - case STATE_NON_ACTIVATED_ZOOMED_TMP: { + break; + case STATE_ZOOMED_OUT_FROM_SERVICE_2TAPS: + goFromStateIdleTo(STATE_ZOOMED_OUT_FROM_SERVICE); + tap(); + tap(); + break; + case STATE_NON_ACTIVATED_ZOOMED_TMP: goFromStateIdleTo(STATE_2TAPS); send(downEvent()); fastForward1sec(); - } break; - case STATE_ACTIVATED_ZOOMED_TMP: { + break; + case STATE_ZOOMED_FURTHER_TMP: goFromStateIdleTo(STATE_ACTIVATED_2TAPS); send(downEvent()); fastForward1sec(); - } break; - case STATE_SHORTCUT_TRIGGERED_ZOOMED_TMP: { + break; + case STATE_ZOOMED_WITH_PERSISTED_SCALE_TMP: goFromStateIdleTo(STATE_SHORTCUT_TRIGGERED); send(downEvent()); fastForward1sec(); - } break; - case STATE_SHORTCUT_TRIGGERED: { - goFromStateIdleTo(STATE_IDLE); - triggerShortcut(); - } break; - case STATE_PANNING: { + break; + case STATE_PANNING: goFromStateIdleTo(STATE_ACTIVATED); send(downEvent()); send(pointerEvent(ACTION_POINTER_DOWN, DEFAULT_X * 2, DEFAULT_Y)); fastForward(ViewConfiguration.getTapTimeout()); - } break; - case STATE_SCALING_AND_PANNING: { + break; + case STATE_SCALING_AND_PANNING: goFromStateIdleTo(STATE_PANNING); send(pointerEvent(ACTION_MOVE, DEFAULT_X * 2, DEFAULT_Y * 3)); send(pointerEvent(ACTION_MOVE, DEFAULT_X * 2, DEFAULT_Y * 4)); send(pointerEvent(ACTION_MOVE, DEFAULT_X * 2, DEFAULT_Y * 5)); - } break; - case STATE_SINGLE_PANNING: { + break; + case STATE_SINGLE_PANNING: goFromStateIdleTo(STATE_ACTIVATED); swipeAndHold(); - } break; + break; default: throw new IllegalArgumentException("Illegal state: " + state); } @@ -913,14 +961,11 @@ public class FullScreenMagnificationGestureHandlerTest { */ private void returnToNormalFrom(int state) { switch (state) { - case STATE_IDLE: { + case STATE_IDLE: // no op - } break; - case STATE_2TAPS: { - allowEventDelegation(); - fastForward1sec(); - } break; - case STATE_ACTIVATED: { + break; + case STATE_ACTIVATED: + case STATE_ZOOMED_OUT_FROM_SERVICE: if (mMgh.mDetectTripleTap) { tap(); tap(); @@ -928,39 +973,45 @@ public class FullScreenMagnificationGestureHandlerTest { } else { triggerShortcut(); } - } break; - case STATE_ACTIVATED_2TAPS: { + break; + case STATE_SHORTCUT_TRIGGERED: + triggerShortcut(); + break; + case STATE_2TAPS: + allowEventDelegation(); + fastForward1sec(); + break; + case STATE_ACTIVATED_2TAPS: + case STATE_ZOOMED_OUT_FROM_SERVICE_2TAPS: tap(); - } break; - case STATE_NON_ACTIVATED_ZOOMED_TMP: { + break; + case STATE_NON_ACTIVATED_ZOOMED_TMP: send(upEvent()); - } break; - case STATE_ACTIVATED_ZOOMED_TMP: { + break; + case STATE_ZOOMED_FURTHER_TMP: send(upEvent()); returnToNormalFrom(STATE_ACTIVATED); - } break; - case STATE_SHORTCUT_TRIGGERED_ZOOMED_TMP: { + break; + case STATE_ZOOMED_WITH_PERSISTED_SCALE_TMP: send(upEvent()); if (mFullScreenMagnificationController.isAlwaysOnMagnificationEnabled()) { returnToNormalFrom(STATE_ACTIVATED); } - } break; - case STATE_SHORTCUT_TRIGGERED: { - triggerShortcut(); - } break; - case STATE_PANNING: { + break; + case STATE_PANNING: send(pointerEvent(ACTION_POINTER_UP, DEFAULT_X * 2, DEFAULT_Y)); send(upEvent()); returnToNormalFrom(STATE_ACTIVATED); - } break; - case STATE_SCALING_AND_PANNING: { + break; + case STATE_SCALING_AND_PANNING: returnToNormalFrom(STATE_PANNING); - } break; - case STATE_SINGLE_PANNING: { + break; + case STATE_SINGLE_PANNING: send(upEvent()); returnToNormalFrom(STATE_ACTIVATED); - } break; - default: throw new IllegalArgumentException("Illegal state: " + state); + break; + default: + throw new IllegalArgumentException("Illegal state: " + state); } }