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 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); } }