Loading services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java +157 −90 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; Loading Loading @@ -166,9 +167,12 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH @VisibleForTesting boolean mIsSinglePanningEnabled; /** * FullScreenMagnificationGestureHandler Constructor. */ private final FullScreenMagnificationVibrationHelper mFullScreenMagnificationVibrationHelper; @VisibleForTesting final OverscrollHandler mOverscrollHandler; private final boolean mIsWatch; public FullScreenMagnificationGestureHandler(@UiContext Context context, FullScreenMagnificationController fullScreenMagnificationController, AccessibilityTraceManager trace, Loading Loading @@ -254,11 +258,13 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH mDetectingState = new DetectingState(context); mViewportDraggingState = new ViewportDraggingState(); mPanningScalingState = new PanningScalingState(context); mSinglePanningState = new SinglePanningState(context, fullScreenMagnificationVibrationHelper); mSinglePanningState = new SinglePanningState(context); mFullScreenMagnificationVibrationHelper = fullScreenMagnificationVibrationHelper; setSinglePanningEnabled( context.getResources() .getBoolean(R.bool.config_enable_a11y_magnification_single_panning)); mOverscrollHandler = new OverscrollHandler(); mIsWatch = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); if (mDetectShortcutTrigger) { mScreenStateReceiver = new ScreenStateReceiver(context, this); Loading Loading @@ -468,15 +474,21 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { int action = event.getActionMasked(); if (action == ACTION_POINTER_UP && event.getPointerCount() == 2 // includes the pointer currently being released && mPreviousState == mViewportDraggingState) { // if feature flag is enabled, currently only true on watches if (mIsSinglePanningEnabled) { mOverscrollHandler.setScaleAndCenterToEdgeIfNeeded(); mOverscrollHandler.clearEdgeState(); } persistScaleAndTransitionTo(mViewportDraggingState); } else if (action == ACTION_UP || action == ACTION_CANCEL) { // if feature flag is enabled, currently only true on watches if (mIsSinglePanningEnabled) { mOverscrollHandler.setScaleAndCenterToEdgeIfNeeded(); mOverscrollHandler.clearEdgeState(); } persistScaleAndTransitionTo(mDetectingState); } } Loading @@ -502,7 +514,12 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH } public void persistScaleAndTransitionTo(State state) { // If device is a watch don't change user settings scale. On watches, warp effect // is enabled and the current display scale could be differ from the default user // settings scale (should not change the scale due to the warp effect) if (!mIsWatch) { mFullScreenMagnificationController.persistScale(mDisplayId); } clear(); transitionTo(state); } Loading Loading @@ -546,6 +563,9 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH } mFullScreenMagnificationController.offsetMagnifiedRegion(mDisplayId, distanceX, distanceY, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); if (mIsSinglePanningEnabled) { mOverscrollHandler.onScrollStateChanged(first, second); } return /* event consumed: */ true; } Loading Loading @@ -893,6 +913,11 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH if (isMultiTapTriggered(2 /* taps */) && event.getPointerCount() == 1) { transitionToViewportDraggingStateAndClear(event); } else if (isActivated() && event.getPointerCount() == 2) { if (mIsSinglePanningEnabled && overscrollState(event, mFirstPointerDownLocation) == OVERSCROLL_VERTICAL_EDGE) { transitionToDelegatingStateAndClear(); } //Primary pointer is swiping, so transit to PanningScalingState transitToPanningScalingStateAndClear(); } else if (mIsSinglePanningEnabled Loading Loading @@ -1264,6 +1289,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH + ", mMagnificationController=" + mFullScreenMagnificationController + ", mDisplayId=" + mDisplayId + ", mIsSinglePanningEnabled=" + mIsSinglePanningEnabled + ", mOverscrollHandler=" + mOverscrollHandler + '}'; } Loading Loading @@ -1411,32 +1437,8 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH private final GestureDetector mScrollGestureDetector; private MotionEventInfo mEvent; private final FullScreenMagnificationVibrationHelper mFullScreenMagnificationVibrationHelper; @VisibleForTesting int mOverscrollState; // mPivotEdge is the point on the edge of the screen when the magnified view hits the edge // This point sets the center of magnified view when warp/scale effect is triggered private final PointF mPivotEdge; // mReachedEdgeCoord is the user's pointer location on the screen when the magnified view // has hit the edge private final PointF mReachedEdgeCoord; // mEdgeCooldown value will be set to true when user hits the edge and will be set to false // once the user moves x distance away from the edge. This is so that vibrating haptic // doesn't get triggered by slight movements private boolean mEdgeCooldown; SinglePanningState( Context context, FullScreenMagnificationVibrationHelper fullScreenMagnificationVibrationHelper) { SinglePanningState(Context context) { mScrollGestureDetector = new GestureDetector(context, this, Handler.getMain()); mFullScreenMagnificationVibrationHelper = fullScreenMagnificationVibrationHelper; mOverscrollState = OVERSCROLL_NONE; mPivotEdge = new PointF(Float.NaN, Float.NaN); mReachedEdgeCoord = new PointF(Float.NaN, Float.NaN); mEdgeCooldown = false; } @Override Loading @@ -1445,17 +1447,8 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH switch (action) { case ACTION_UP: case ACTION_CANCEL: if (mOverscrollState == OVERSCROLL_LEFT_EDGE || mOverscrollState == OVERSCROLL_RIGHT_EDGE) { mFullScreenMagnificationController.setScaleAndCenter( mDisplayId, mFullScreenMagnificationController.getPersistedScale(mDisplayId), mPivotEdge.x, mPivotEdge.y, true, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); } clear(); mOverscrollHandler.setScaleAndCenterToEdgeIfNeeded(); mOverscrollHandler.clearEdgeState(); transitionTo(mDetectingState); break; } Loading @@ -1482,23 +1475,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH + " isAtEdge: " + mFullScreenMagnificationController.isAtEdge(mDisplayId)); } if (mFullScreenMagnificationController.isAtEdge(mDisplayId)) { playEdgeVibration(second); setPivotEdge(); } if (mOverscrollState == OVERSCROLL_NONE) { mOverscrollState = overscrollState(second, new PointF(first.getX(), first.getY())); } else if (mOverscrollState == OVERSCROLL_VERTICAL_EDGE) { clear(); transitionTo(mDelegatingState); } else { boolean reset = warpEffectReset(second); if (reset) { mFullScreenMagnificationController.reset(mDisplayId, /* animate */ true); clear(); transitionTo(mDetectingState); } } mOverscrollHandler.onScrollStateChanged(first, second); return /* event consumed: */ true; } Loading @@ -1515,35 +1492,37 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH public String toString() { return "SinglePanningState{" + "isEdgeOfView=" + mFullScreenMagnificationController.isAtEdge(mDisplayId) + "overscrollStatus=" + mOverscrollState + "}"; + mFullScreenMagnificationController.isAtEdge(mDisplayId); } private void playEdgeVibration(MotionEvent event) { if (mOverscrollState == OVERSCROLL_NONE) { vibrateIfNeeded(event); } } private void setPivotEdge() { if (!pointerValid(mPivotEdge)) { Rect bounds = new Rect(); mFullScreenMagnificationController.getMagnificationBounds(mDisplayId, bounds); if (mOverscrollState == OVERSCROLL_LEFT_EDGE) { mPivotEdge.set( bounds.left, mFullScreenMagnificationController.getCenterY(mDisplayId)); } else if (mOverscrollState == OVERSCROLL_RIGHT_EDGE) { mPivotEdge.set( bounds.right, mFullScreenMagnificationController.getCenterY(mDisplayId)); } } /** Overscroll Handler handles the logic when user is at the edge and scrolls past an edge */ final class OverscrollHandler { @VisibleForTesting int mOverscrollState; // mPivotEdge is the point on the edge of the screen when the magnified view hits the edge // This point sets the center of magnified view when warp/scale effect is triggered private final PointF mPivotEdge; // mReachedEdgeCoord is the user's pointer location on the screen when the magnified view // has hit the edge private final PointF mReachedEdgeCoord; // mEdgeCooldown value will be set to true when user hits the edge and will be set to false // once the user moves x distance away from the edge. This is so that vibrating haptic // doesn't get triggered by slight movements private boolean mEdgeCooldown; OverscrollHandler() { mOverscrollState = OVERSCROLL_NONE; mPivotEdge = new PointF(Float.NaN, Float.NaN); mReachedEdgeCoord = new PointF(Float.NaN, Float.NaN); mEdgeCooldown = false; } private boolean warpEffectReset(MotionEvent second) { protected boolean warpEffectReset(MotionEvent second) { float scale = calculateOverscrollScale(second); if (scale < 0) return false; mFullScreenMagnificationController.setScaleAndCenter( Loading @@ -1566,7 +1545,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH float overshootDistX = second.getX() - mReachedEdgeCoord.x; if ((mOverscrollState == OVERSCROLL_LEFT_EDGE && overshootDistX < 0) || (mOverscrollState == OVERSCROLL_RIGHT_EDGE && overshootDistX > 0)) { clear(); clearEdgeState(); return -1.0f; } float overshootDistY = second.getY() - mReachedEdgeCoord.y; Loading Loading @@ -1611,21 +1590,109 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH } private void vibrateIfNeeded(MotionEvent event) { if (mOverscrollState != OVERSCROLL_NONE) { return; } if ((mFullScreenMagnificationController.isAtLeftEdge(mDisplayId) || mFullScreenMagnificationController.isAtRightEdge(mDisplayId)) && !mEdgeCooldown) { mFullScreenMagnificationVibrationHelper.vibrateIfSettingEnabled(); } } private void setPivotEdge(MotionEvent event) { if (!pointerValid(mPivotEdge)) { Rect bounds = new Rect(); mFullScreenMagnificationController.getMagnificationBounds(mDisplayId, bounds); if (mOverscrollState == OVERSCROLL_LEFT_EDGE) { mPivotEdge.set( bounds.left, mFullScreenMagnificationController.getCenterY(mDisplayId)); } else if (mOverscrollState == OVERSCROLL_RIGHT_EDGE) { mPivotEdge.set( bounds.right, mFullScreenMagnificationController.getCenterY(mDisplayId)); } mReachedEdgeCoord.set(event.getX(), event.getY()); mEdgeCooldown = true; } } @Override public void clear() { private void onScrollStateChanged(MotionEvent first, MotionEvent second) { if (mFullScreenMagnificationController.isAtEdge(mDisplayId)) { vibrateIfNeeded(second); setPivotEdge(second); } switch (mOverscrollState) { case OVERSCROLL_NONE: onNoOverscroll(first, second); break; case OVERSCROLL_VERTICAL_EDGE: onVerticalOverscroll(); break; case OVERSCROLL_LEFT_EDGE: case OVERSCROLL_RIGHT_EDGE: onHorizontalOverscroll(second); break; default: Slog.d(mLogTag, "Invalid overscroll state"); break; } } public void onNoOverscroll(MotionEvent first, MotionEvent second) { mOverscrollState = overscrollState(second, new PointF(first.getX(), first.getY())); } public void onVerticalOverscroll() { clearEdgeState(); transitionTo(mDelegatingState); } public void onHorizontalOverscroll(MotionEvent second) { boolean reset = warpEffectReset(second); if (reset) { mFullScreenMagnificationController.reset(mDisplayId, /* animate */ true); clearEdgeState(); transitionTo(mDelegatingState); } } private void setScaleAndCenterToEdgeIfNeeded() { if (mOverscrollState == OVERSCROLL_LEFT_EDGE || mOverscrollState == OVERSCROLL_RIGHT_EDGE) { mFullScreenMagnificationController.setScaleAndCenter( mDisplayId, mFullScreenMagnificationController.getPersistedScale(mDisplayId), mPivotEdge.x, mPivotEdge.y, true, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); } } private void clearEdgeState() { mOverscrollState = OVERSCROLL_NONE; mPivotEdge.set(Float.NaN, Float.NaN); mReachedEdgeCoord.set(Float.NaN, Float.NaN); mEdgeCooldown = false; } @Override public String toString() { return "OverscrollHandler {" + "mOverscrollState=" + mOverscrollState + "mPivotEdge.x=" + mPivotEdge.x + "mPivotEdge.y=" + mPivotEdge.y + "mReachedEdgeCoord.x=" + mReachedEdgeCoord.x + "mReachedEdgeCoord.y=" + mReachedEdgeCoord.y + "mEdgeCooldown=" + mEdgeCooldown + "}"; } } } services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java +4 −4 Original line number Diff line number Diff line Loading @@ -687,7 +687,7 @@ public class FullScreenMagnificationGestureHandlerTest { swipeAndHold(initCoords, edgeCoords); assertTrue(mMgh.mCurrentState == mMgh.mSinglePanningState); assertTrue(mMgh.mSinglePanningState.mOverscrollState == mMgh.OVERSCROLL_LEFT_EDGE); assertTrue(mMgh.mOverscrollHandler.mOverscrollState == mMgh.OVERSCROLL_LEFT_EDGE); assertTrue(isZoomed()); } Loading @@ -711,7 +711,7 @@ public class FullScreenMagnificationGestureHandlerTest { swipeAndHold(initCoords, edgeCoords); assertTrue(mMgh.mCurrentState == mMgh.mSinglePanningState); assertTrue(mMgh.mSinglePanningState.mOverscrollState == mMgh.OVERSCROLL_RIGHT_EDGE); assertTrue(mMgh.mOverscrollHandler.mOverscrollState == mMgh.OVERSCROLL_RIGHT_EDGE); assertTrue(isZoomed()); } Loading @@ -734,7 +734,7 @@ public class FullScreenMagnificationGestureHandlerTest { swipeAndHold(initCoords, edgeCoords); assertTrue(mMgh.mSinglePanningState.mOverscrollState == mMgh.OVERSCROLL_VERTICAL_EDGE); assertTrue(mMgh.mOverscrollHandler.mOverscrollState == mMgh.OVERSCROLL_VERTICAL_EDGE); assertTrue(isZoomed()); } Loading @@ -756,7 +756,7 @@ public class FullScreenMagnificationGestureHandlerTest { swipeAndHold(initCoords, edgeCoords); assertTrue(mMgh.mSinglePanningState.mOverscrollState == mMgh.OVERSCROLL_NONE); assertTrue(mMgh.mOverscrollHandler.mOverscrollState == mMgh.OVERSCROLL_NONE); assertTrue(isZoomed()); } Loading Loading
services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java +157 −90 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; Loading Loading @@ -166,9 +167,12 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH @VisibleForTesting boolean mIsSinglePanningEnabled; /** * FullScreenMagnificationGestureHandler Constructor. */ private final FullScreenMagnificationVibrationHelper mFullScreenMagnificationVibrationHelper; @VisibleForTesting final OverscrollHandler mOverscrollHandler; private final boolean mIsWatch; public FullScreenMagnificationGestureHandler(@UiContext Context context, FullScreenMagnificationController fullScreenMagnificationController, AccessibilityTraceManager trace, Loading Loading @@ -254,11 +258,13 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH mDetectingState = new DetectingState(context); mViewportDraggingState = new ViewportDraggingState(); mPanningScalingState = new PanningScalingState(context); mSinglePanningState = new SinglePanningState(context, fullScreenMagnificationVibrationHelper); mSinglePanningState = new SinglePanningState(context); mFullScreenMagnificationVibrationHelper = fullScreenMagnificationVibrationHelper; setSinglePanningEnabled( context.getResources() .getBoolean(R.bool.config_enable_a11y_magnification_single_panning)); mOverscrollHandler = new OverscrollHandler(); mIsWatch = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); if (mDetectShortcutTrigger) { mScreenStateReceiver = new ScreenStateReceiver(context, this); Loading Loading @@ -468,15 +474,21 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH @Override public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { int action = event.getActionMasked(); if (action == ACTION_POINTER_UP && event.getPointerCount() == 2 // includes the pointer currently being released && mPreviousState == mViewportDraggingState) { // if feature flag is enabled, currently only true on watches if (mIsSinglePanningEnabled) { mOverscrollHandler.setScaleAndCenterToEdgeIfNeeded(); mOverscrollHandler.clearEdgeState(); } persistScaleAndTransitionTo(mViewportDraggingState); } else if (action == ACTION_UP || action == ACTION_CANCEL) { // if feature flag is enabled, currently only true on watches if (mIsSinglePanningEnabled) { mOverscrollHandler.setScaleAndCenterToEdgeIfNeeded(); mOverscrollHandler.clearEdgeState(); } persistScaleAndTransitionTo(mDetectingState); } } Loading @@ -502,7 +514,12 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH } public void persistScaleAndTransitionTo(State state) { // If device is a watch don't change user settings scale. On watches, warp effect // is enabled and the current display scale could be differ from the default user // settings scale (should not change the scale due to the warp effect) if (!mIsWatch) { mFullScreenMagnificationController.persistScale(mDisplayId); } clear(); transitionTo(state); } Loading Loading @@ -546,6 +563,9 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH } mFullScreenMagnificationController.offsetMagnifiedRegion(mDisplayId, distanceX, distanceY, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); if (mIsSinglePanningEnabled) { mOverscrollHandler.onScrollStateChanged(first, second); } return /* event consumed: */ true; } Loading Loading @@ -893,6 +913,11 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH if (isMultiTapTriggered(2 /* taps */) && event.getPointerCount() == 1) { transitionToViewportDraggingStateAndClear(event); } else if (isActivated() && event.getPointerCount() == 2) { if (mIsSinglePanningEnabled && overscrollState(event, mFirstPointerDownLocation) == OVERSCROLL_VERTICAL_EDGE) { transitionToDelegatingStateAndClear(); } //Primary pointer is swiping, so transit to PanningScalingState transitToPanningScalingStateAndClear(); } else if (mIsSinglePanningEnabled Loading Loading @@ -1264,6 +1289,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH + ", mMagnificationController=" + mFullScreenMagnificationController + ", mDisplayId=" + mDisplayId + ", mIsSinglePanningEnabled=" + mIsSinglePanningEnabled + ", mOverscrollHandler=" + mOverscrollHandler + '}'; } Loading Loading @@ -1411,32 +1437,8 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH private final GestureDetector mScrollGestureDetector; private MotionEventInfo mEvent; private final FullScreenMagnificationVibrationHelper mFullScreenMagnificationVibrationHelper; @VisibleForTesting int mOverscrollState; // mPivotEdge is the point on the edge of the screen when the magnified view hits the edge // This point sets the center of magnified view when warp/scale effect is triggered private final PointF mPivotEdge; // mReachedEdgeCoord is the user's pointer location on the screen when the magnified view // has hit the edge private final PointF mReachedEdgeCoord; // mEdgeCooldown value will be set to true when user hits the edge and will be set to false // once the user moves x distance away from the edge. This is so that vibrating haptic // doesn't get triggered by slight movements private boolean mEdgeCooldown; SinglePanningState( Context context, FullScreenMagnificationVibrationHelper fullScreenMagnificationVibrationHelper) { SinglePanningState(Context context) { mScrollGestureDetector = new GestureDetector(context, this, Handler.getMain()); mFullScreenMagnificationVibrationHelper = fullScreenMagnificationVibrationHelper; mOverscrollState = OVERSCROLL_NONE; mPivotEdge = new PointF(Float.NaN, Float.NaN); mReachedEdgeCoord = new PointF(Float.NaN, Float.NaN); mEdgeCooldown = false; } @Override Loading @@ -1445,17 +1447,8 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH switch (action) { case ACTION_UP: case ACTION_CANCEL: if (mOverscrollState == OVERSCROLL_LEFT_EDGE || mOverscrollState == OVERSCROLL_RIGHT_EDGE) { mFullScreenMagnificationController.setScaleAndCenter( mDisplayId, mFullScreenMagnificationController.getPersistedScale(mDisplayId), mPivotEdge.x, mPivotEdge.y, true, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); } clear(); mOverscrollHandler.setScaleAndCenterToEdgeIfNeeded(); mOverscrollHandler.clearEdgeState(); transitionTo(mDetectingState); break; } Loading @@ -1482,23 +1475,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH + " isAtEdge: " + mFullScreenMagnificationController.isAtEdge(mDisplayId)); } if (mFullScreenMagnificationController.isAtEdge(mDisplayId)) { playEdgeVibration(second); setPivotEdge(); } if (mOverscrollState == OVERSCROLL_NONE) { mOverscrollState = overscrollState(second, new PointF(first.getX(), first.getY())); } else if (mOverscrollState == OVERSCROLL_VERTICAL_EDGE) { clear(); transitionTo(mDelegatingState); } else { boolean reset = warpEffectReset(second); if (reset) { mFullScreenMagnificationController.reset(mDisplayId, /* animate */ true); clear(); transitionTo(mDetectingState); } } mOverscrollHandler.onScrollStateChanged(first, second); return /* event consumed: */ true; } Loading @@ -1515,35 +1492,37 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH public String toString() { return "SinglePanningState{" + "isEdgeOfView=" + mFullScreenMagnificationController.isAtEdge(mDisplayId) + "overscrollStatus=" + mOverscrollState + "}"; + mFullScreenMagnificationController.isAtEdge(mDisplayId); } private void playEdgeVibration(MotionEvent event) { if (mOverscrollState == OVERSCROLL_NONE) { vibrateIfNeeded(event); } } private void setPivotEdge() { if (!pointerValid(mPivotEdge)) { Rect bounds = new Rect(); mFullScreenMagnificationController.getMagnificationBounds(mDisplayId, bounds); if (mOverscrollState == OVERSCROLL_LEFT_EDGE) { mPivotEdge.set( bounds.left, mFullScreenMagnificationController.getCenterY(mDisplayId)); } else if (mOverscrollState == OVERSCROLL_RIGHT_EDGE) { mPivotEdge.set( bounds.right, mFullScreenMagnificationController.getCenterY(mDisplayId)); } } /** Overscroll Handler handles the logic when user is at the edge and scrolls past an edge */ final class OverscrollHandler { @VisibleForTesting int mOverscrollState; // mPivotEdge is the point on the edge of the screen when the magnified view hits the edge // This point sets the center of magnified view when warp/scale effect is triggered private final PointF mPivotEdge; // mReachedEdgeCoord is the user's pointer location on the screen when the magnified view // has hit the edge private final PointF mReachedEdgeCoord; // mEdgeCooldown value will be set to true when user hits the edge and will be set to false // once the user moves x distance away from the edge. This is so that vibrating haptic // doesn't get triggered by slight movements private boolean mEdgeCooldown; OverscrollHandler() { mOverscrollState = OVERSCROLL_NONE; mPivotEdge = new PointF(Float.NaN, Float.NaN); mReachedEdgeCoord = new PointF(Float.NaN, Float.NaN); mEdgeCooldown = false; } private boolean warpEffectReset(MotionEvent second) { protected boolean warpEffectReset(MotionEvent second) { float scale = calculateOverscrollScale(second); if (scale < 0) return false; mFullScreenMagnificationController.setScaleAndCenter( Loading @@ -1566,7 +1545,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH float overshootDistX = second.getX() - mReachedEdgeCoord.x; if ((mOverscrollState == OVERSCROLL_LEFT_EDGE && overshootDistX < 0) || (mOverscrollState == OVERSCROLL_RIGHT_EDGE && overshootDistX > 0)) { clear(); clearEdgeState(); return -1.0f; } float overshootDistY = second.getY() - mReachedEdgeCoord.y; Loading Loading @@ -1611,21 +1590,109 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH } private void vibrateIfNeeded(MotionEvent event) { if (mOverscrollState != OVERSCROLL_NONE) { return; } if ((mFullScreenMagnificationController.isAtLeftEdge(mDisplayId) || mFullScreenMagnificationController.isAtRightEdge(mDisplayId)) && !mEdgeCooldown) { mFullScreenMagnificationVibrationHelper.vibrateIfSettingEnabled(); } } private void setPivotEdge(MotionEvent event) { if (!pointerValid(mPivotEdge)) { Rect bounds = new Rect(); mFullScreenMagnificationController.getMagnificationBounds(mDisplayId, bounds); if (mOverscrollState == OVERSCROLL_LEFT_EDGE) { mPivotEdge.set( bounds.left, mFullScreenMagnificationController.getCenterY(mDisplayId)); } else if (mOverscrollState == OVERSCROLL_RIGHT_EDGE) { mPivotEdge.set( bounds.right, mFullScreenMagnificationController.getCenterY(mDisplayId)); } mReachedEdgeCoord.set(event.getX(), event.getY()); mEdgeCooldown = true; } } @Override public void clear() { private void onScrollStateChanged(MotionEvent first, MotionEvent second) { if (mFullScreenMagnificationController.isAtEdge(mDisplayId)) { vibrateIfNeeded(second); setPivotEdge(second); } switch (mOverscrollState) { case OVERSCROLL_NONE: onNoOverscroll(first, second); break; case OVERSCROLL_VERTICAL_EDGE: onVerticalOverscroll(); break; case OVERSCROLL_LEFT_EDGE: case OVERSCROLL_RIGHT_EDGE: onHorizontalOverscroll(second); break; default: Slog.d(mLogTag, "Invalid overscroll state"); break; } } public void onNoOverscroll(MotionEvent first, MotionEvent second) { mOverscrollState = overscrollState(second, new PointF(first.getX(), first.getY())); } public void onVerticalOverscroll() { clearEdgeState(); transitionTo(mDelegatingState); } public void onHorizontalOverscroll(MotionEvent second) { boolean reset = warpEffectReset(second); if (reset) { mFullScreenMagnificationController.reset(mDisplayId, /* animate */ true); clearEdgeState(); transitionTo(mDelegatingState); } } private void setScaleAndCenterToEdgeIfNeeded() { if (mOverscrollState == OVERSCROLL_LEFT_EDGE || mOverscrollState == OVERSCROLL_RIGHT_EDGE) { mFullScreenMagnificationController.setScaleAndCenter( mDisplayId, mFullScreenMagnificationController.getPersistedScale(mDisplayId), mPivotEdge.x, mPivotEdge.y, true, AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID); } } private void clearEdgeState() { mOverscrollState = OVERSCROLL_NONE; mPivotEdge.set(Float.NaN, Float.NaN); mReachedEdgeCoord.set(Float.NaN, Float.NaN); mEdgeCooldown = false; } @Override public String toString() { return "OverscrollHandler {" + "mOverscrollState=" + mOverscrollState + "mPivotEdge.x=" + mPivotEdge.x + "mPivotEdge.y=" + mPivotEdge.y + "mReachedEdgeCoord.x=" + mReachedEdgeCoord.x + "mReachedEdgeCoord.y=" + mReachedEdgeCoord.y + "mEdgeCooldown=" + mEdgeCooldown + "}"; } } }
services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java +4 −4 Original line number Diff line number Diff line Loading @@ -687,7 +687,7 @@ public class FullScreenMagnificationGestureHandlerTest { swipeAndHold(initCoords, edgeCoords); assertTrue(mMgh.mCurrentState == mMgh.mSinglePanningState); assertTrue(mMgh.mSinglePanningState.mOverscrollState == mMgh.OVERSCROLL_LEFT_EDGE); assertTrue(mMgh.mOverscrollHandler.mOverscrollState == mMgh.OVERSCROLL_LEFT_EDGE); assertTrue(isZoomed()); } Loading @@ -711,7 +711,7 @@ public class FullScreenMagnificationGestureHandlerTest { swipeAndHold(initCoords, edgeCoords); assertTrue(mMgh.mCurrentState == mMgh.mSinglePanningState); assertTrue(mMgh.mSinglePanningState.mOverscrollState == mMgh.OVERSCROLL_RIGHT_EDGE); assertTrue(mMgh.mOverscrollHandler.mOverscrollState == mMgh.OVERSCROLL_RIGHT_EDGE); assertTrue(isZoomed()); } Loading @@ -734,7 +734,7 @@ public class FullScreenMagnificationGestureHandlerTest { swipeAndHold(initCoords, edgeCoords); assertTrue(mMgh.mSinglePanningState.mOverscrollState == mMgh.OVERSCROLL_VERTICAL_EDGE); assertTrue(mMgh.mOverscrollHandler.mOverscrollState == mMgh.OVERSCROLL_VERTICAL_EDGE); assertTrue(isZoomed()); } Loading @@ -756,7 +756,7 @@ public class FullScreenMagnificationGestureHandlerTest { swipeAndHold(initCoords, edgeCoords); assertTrue(mMgh.mSinglePanningState.mOverscrollState == mMgh.OVERSCROLL_NONE); assertTrue(mMgh.mOverscrollHandler.mOverscrollState == mMgh.OVERSCROLL_NONE); assertTrue(isZoomed()); } Loading