Merge "feat(#AlwaysOnMagnifier)!: Supports magnification zooming to 100% [1/2]"

This commit is contained in:
Roy Chou
2023-01-13 07:21:51 +00:00
committed by Android (Google) Code Review
9 changed files with 247 additions and 199 deletions

View File

@@ -3248,7 +3248,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (targetName.equals(MAGNIFICATION_CONTROLLER_NAME)) {
final boolean enabled =
!getMagnificationController().getFullScreenMagnificationController()
.isMagnifying(displayId);
.isActivated(displayId);
logAccessibilityShortcutActivated(mContext, MAGNIFICATION_COMPONENT_NAME, shortcutType,
enabled);
sendAccessibilityButtonToInputFilter(displayId);

View File

@@ -126,8 +126,6 @@ public class FullScreenMagnificationController implements
private boolean mUnregisterPending;
private boolean mDeleteAfterUnregister;
private boolean mForceShowMagnifiableBounds;
private final int mDisplayId;
private int mIdOfLastServiceToMagnify = INVALID_SERVICE_ID;
@@ -213,8 +211,8 @@ public class FullScreenMagnificationController implements
return mRegistered;
}
boolean isMagnifying() {
return mCurrentMagnificationSpec.scale > 1.0f;
boolean isActivated() {
return mMagnificationActivated;
}
float getScale() {
@@ -370,12 +368,6 @@ public class FullScreenMagnificationController implements
@GuardedBy("mLock")
void onMagnificationChangedLocked() {
final float scale = getScale();
final boolean lastMagnificationActivated = mMagnificationActivated;
mMagnificationActivated = scale > 1.0f;
if (mMagnificationActivated != lastMagnificationActivated) {
mMagnificationInfoChangedCallback.onFullScreenMagnificationActivationState(
mDisplayId, mMagnificationActivated);
}
final MagnificationConfig config = new MagnificationConfig.Builder()
.setMode(MAGNIFICATION_MODE_FULLSCREEN)
@@ -384,7 +376,7 @@ public class FullScreenMagnificationController implements
.setCenterY(getCenterY()).build();
mMagnificationInfoChangedCallback.onFullScreenMagnificationChanged(mDisplayId,
mMagnificationRegion, config);
if (mUnregisterPending && !isMagnifying()) {
if (mUnregisterPending && !isActivated()) {
unregister(mDeleteAfterUnregister);
}
}
@@ -476,21 +468,22 @@ public class FullScreenMagnificationController implements
}
@GuardedBy("mLock")
void setForceShowMagnifiableBounds(boolean show) {
if (mRegistered) {
mForceShowMagnifiableBounds = show;
if (traceEnabled()) {
logTrace("setForceShowMagnifiableBounds",
"displayID=" + mDisplayId + ";show=" + show);
}
mControllerCtx.getWindowManager().setForceShowMagnifiableBounds(
mDisplayId, show);
private boolean setActivated(boolean activated) {
if (DEBUG) {
Slog.i(LOG_TAG, "setActivated(activated = " + activated + ")");
}
}
@GuardedBy("mLock")
boolean isForceShowMagnifiableBounds() {
return mRegistered && mForceShowMagnifiableBounds;
final boolean changed = (mMagnificationActivated != activated);
if (changed) {
mMagnificationActivated = activated;
mMagnificationInfoChangedCallback.onFullScreenMagnificationActivationState(
mDisplayId, mMagnificationActivated);
mControllerCtx.getWindowManager().setForceShowMagnifiableBounds(
mDisplayId, activated);
}
return changed;
}
@GuardedBy("mLock")
@@ -504,13 +497,13 @@ public class FullScreenMagnificationController implements
return false;
}
final MagnificationSpec spec = mCurrentMagnificationSpec;
final boolean changed = !spec.isNop();
final boolean changed = isActivated();
setActivated(false);
if (changed) {
spec.clear();
onMagnificationChangedLocked();
}
mIdOfLastServiceToMagnify = INVALID_SERVICE_ID;
mForceShowMagnifiableBounds = false;
sendSpecToAnimation(spec, animationCallback);
return changed;
}
@@ -554,9 +547,10 @@ public class FullScreenMagnificationController implements
+ ", centerY = " + centerY + ", endCallback = "
+ animationCallback + ", id = " + id + ")");
}
final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY);
boolean changed = setActivated(true);
changed |= updateMagnificationSpecLocked(scale, centerX, centerY);
sendSpecToAnimation(mCurrentMagnificationSpec, animationCallback);
if (isMagnifying() && (id != INVALID_SERVICE_ID)) {
if (isActivated() && (id != INVALID_SERVICE_ID)) {
mIdOfLastServiceToMagnify = id;
mMagnificationInfoChangedCallback.onRequestMagnificationSpec(mDisplayId,
mIdOfLastServiceToMagnify);
@@ -779,7 +773,7 @@ public class FullScreenMagnificationController implements
if (display == null) {
return;
}
if (!display.isMagnifying()) {
if (!display.isActivated()) {
return;
}
final Rect magnifiedRegionBounds = mTempRect;
@@ -831,16 +825,16 @@ public class FullScreenMagnificationController implements
/**
* @param displayId The logical display id.
* @return {@code true} if magnification is active, e.g. the scale
* is > 1, {@code false} otherwise
* @return {@code true} if magnification is activated,
* {@code false} otherwise
*/
public boolean isMagnifying(int displayId) {
public boolean isActivated(int displayId) {
synchronized (mLock) {
final DisplayMagnification display = mDisplays.get(displayId);
if (display == null) {
return false;
}
return display.isMagnifying();
return display.isActivated();
}
}
@@ -1166,6 +1160,9 @@ public class FullScreenMagnificationController implements
*/
public void persistScale(int displayId) {
final float scale = getScale(Display.DEFAULT_DISPLAY);
if (scale < 2.0f) {
return;
}
mScaleProvider.putScale(scale, displayId);
}
@@ -1177,7 +1174,8 @@ public class FullScreenMagnificationController implements
* scale if none is available
*/
public float getPersistedScale(int displayId) {
return mScaleProvider.getScale(displayId);
return MathUtils.constrain(mScaleProvider.getScale(displayId),
2.0f, MagnificationScaleProvider.MAX_SCALE);
}
/**
@@ -1198,12 +1196,12 @@ public class FullScreenMagnificationController implements
*
* @param displayId The logical display id.
* @param animate whether the animate the transition
* @return whether was {@link #isMagnifying(int) magnifying}
* @return whether was {@link #isActivated(int)} activated}
*/
boolean resetIfNeeded(int displayId, boolean animate) {
synchronized (mLock) {
final DisplayMagnification display = mDisplays.get(displayId);
if (display == null || !display.isMagnifying()) {
if (display == null || !display.isActivated()) {
return false;
}
display.reset(animate);
@@ -1221,7 +1219,7 @@ public class FullScreenMagnificationController implements
boolean resetIfNeeded(int displayId, int connectionId) {
synchronized (mLock) {
final DisplayMagnification display = mDisplays.get(displayId);
if (display == null || !display.isMagnifying()
if (display == null || !display.isActivated()
|| connectionId != display.getIdOfLastServiceToMagnify()) {
return false;
}
@@ -1230,16 +1228,6 @@ public class FullScreenMagnificationController implements
}
}
void setForceShowMagnifiableBounds(int displayId, boolean show) {
synchronized (mLock) {
final DisplayMagnification display = mDisplays.get(displayId);
if (display == null) {
return;
}
display.setForceShowMagnifiableBounds(show);
}
}
/**
* Notifies that the IME window visibility changed.
*
@@ -1251,21 +1239,6 @@ public class FullScreenMagnificationController implements
mMagnificationInfoChangedCallback.onImeWindowVisibilityChanged(displayId, shown);
}
/**
* Returns {@code true} if the magnifiable regions of the display is forced to be shown.
*
* @param displayId The logical display id.
*/
public boolean isForceShowMagnifiableBounds(int displayId) {
synchronized (mLock) {
final DisplayMagnification display = mDisplays.get(displayId);
if (display == null) {
return false;
}
return display.isForceShowMagnifiableBounds();
}
}
private void onScreenTurnedOff() {
final Message m = PooledLambda.obtainMessage(
FullScreenMagnificationController::resetAllIfNeeded, this, false);
@@ -1295,7 +1268,7 @@ public class FullScreenMagnificationController implements
}
return;
}
if (!display.isMagnifying()) {
if (!display.isActivated()) {
display.unregister(delete);
} else {
display.unregisterPending(delete);

View File

@@ -122,7 +122,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
// The MIN_SCALE is different from MagnificationScaleProvider.MIN_SCALE due
// to AccessibilityService.MagnificationController#setScale() has
// different scale range
private static final float MIN_SCALE = 2.0f;
private static final float MIN_SCALE = 1.0f;
private static final float MAX_SCALE = MagnificationScaleProvider.MAX_SCALE;
@VisibleForTesting final FullScreenMagnificationController mFullScreenMagnificationController;
@@ -220,14 +220,19 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
@Override
public void handleShortcutTriggered() {
boolean wasMagnifying = mFullScreenMagnificationController.resetIfNeeded(mDisplayId,
/* animate */ true);
if (wasMagnifying) {
final boolean isActivated = mFullScreenMagnificationController.isActivated(mDisplayId);
if (isActivated) {
zoomOff();
clearAndTransitionToStateDetecting();
} else {
mPromptController.showNotificationIfNeeded();
mDetectingState.toggleShortcutTriggered();
}
if (mDetectingState.isShortcutTriggered()) {
mPromptController.showNotificationIfNeeded();
zoomToScale(1.0f, Float.NaN, Float.NaN);
}
}
@Override
@@ -441,7 +446,12 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
final class ViewportDraggingState implements State {
/** Whether to disable zoom after dragging ends */
boolean mZoomedInBeforeDrag;
@VisibleForTesting boolean mActivatedBeforeDrag;
/** Whether to restore scale after dragging ends */
private boolean mZoomedInTemporary;
/** The cached scale for recovering after dragging ends */
private float mScaleBeforeZoomedInTemporary;
private boolean mLastMoveOutsideMagnifiedRegion;
@Override
@@ -474,7 +484,13 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
case ACTION_UP:
case ACTION_CANCEL: {
if (!mZoomedInBeforeDrag) zoomOff();
if (mActivatedBeforeDrag) {
if (mZoomedInTemporary) {
zoomToScale(mScaleBeforeZoomedInTemporary, event.getX(), event.getY());
}
} else {
zoomOff();
}
clear();
transitionTo(mDetectingState);
}
@@ -488,15 +504,27 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
}
}
public void prepareForZoomInTemporary() {
mViewportDraggingState.mActivatedBeforeDrag =
mFullScreenMagnificationController.isActivated(mDisplayId);
mViewportDraggingState.mZoomedInTemporary = true;
mViewportDraggingState.mScaleBeforeZoomedInTemporary =
mFullScreenMagnificationController.getScale(mDisplayId);
}
@Override
public void clear() {
mLastMoveOutsideMagnifiedRegion = false;
mZoomedInTemporary = false;
mScaleBeforeZoomedInTemporary = 1.0f;
}
@Override
public String toString() {
return "ViewportDraggingState{"
+ "mZoomedInBeforeDrag=" + mZoomedInBeforeDrag
+ "mActivatedBeforeDrag=" + mActivatedBeforeDrag
+ ", mLastMoveOutsideMagnifiedRegion=" + mLastMoveOutsideMagnifiedRegion
+ '}';
}
@@ -625,10 +653,10 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
transitionToDelegatingStateAndClear();
} else if (mDetectTripleTap
// If magnified, delay an ACTION_DOWN for mMultiTapMaxDelay
// If activated, delay an ACTION_DOWN for mMultiTapMaxDelay
// to ensure reachability of
// STATE_PANNING_SCALING(triggerable with ACTION_POINTER_DOWN)
|| mFullScreenMagnificationController.isMagnifying(mDisplayId)) {
|| isActivated()) {
afterMultiTapTimeoutTransitionToDelegatingState();
@@ -640,8 +668,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
}
break;
case ACTION_POINTER_DOWN: {
if (mFullScreenMagnificationController.isMagnifying(mDisplayId)
&& event.getPointerCount() == 2) {
if (isActivated() && event.getPointerCount() == 2) {
storeSecondPointerDownLocation(event);
mHandler.sendEmptyMessageDelayed(MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE,
ViewConfiguration.getTapTimeout());
@@ -665,13 +692,13 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
// (which is a rare combo to be used aside from magnification)
if (isMultiTapTriggered(2 /* taps */) && event.getPointerCount() == 1) {
transitionToViewportDraggingStateAndClear(event);
} else if (isMagnifying() && event.getPointerCount() == 2) {
} else if (isActivated() && event.getPointerCount() == 2) {
//Primary pointer is swiping, so transit to PanningScalingState
transitToPanningScalingStateAndClear();
} else {
transitionToDelegatingStateAndClear();
}
} else if (isMagnifying() && secondPointerDownValid()
} else if (isActivated() && secondPointerDownValid()
&& distanceClosestPointerToPoint(
mSecondPointerDownLocation, /* move */ event) > mSwipeMinDistance) {
//Second pointer is swiping, so transit to PanningScalingState
@@ -734,7 +761,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
// Only log the triple tap event, use numTaps to filter.
if (multitapTriggered && numTaps > 2) {
final boolean enabled = mFullScreenMagnificationController.isMagnifying(mDisplayId);
final boolean enabled = isActivated();
logMagnificationTripleTap(enabled);
}
return multitapTriggered;
@@ -862,24 +889,33 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
mSecondPointerDownLocation.set(Float.NaN, Float.NaN);
}
/**
* This method could be triggered by both 2 cases.
* 1. direct three tap gesture
* 2. one tap while shortcut triggered (it counts as two taps).
*/
private void onTripleTap(MotionEvent up) {
if (DEBUG_DETECTING) {
Slog.i(mLogTag, "onTripleTap(); delayed: "
+ MotionEventInfo.toString(mDelayedEventQueue));
}
clear();
// Toggle zoom
if (mFullScreenMagnificationController.isMagnifying(mDisplayId)) {
zoomOff();
} else {
// We put mShortcutTriggered into conditions.
// The reason is when the shortcut is triggered,
// the magnifier is activated and keeps in scale 1.0,
// and in this case, we still want to zoom on the magnifier.
if (!isActivated() || mShortcutTriggered) {
mPromptController.showNotificationIfNeeded();
zoomOn(up.getX(), up.getY());
} else {
zoomOff();
}
clear();
}
private boolean isMagnifying() {
return mFullScreenMagnificationController.isMagnifying(mDisplayId);
private boolean isActivated() {
return mFullScreenMagnificationController.isActivated(mDisplayId);
}
void transitionToViewportDraggingStateAndClear(MotionEvent down) {
@@ -887,14 +923,13 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
if (DEBUG_DETECTING) Slog.i(mLogTag, "onTripleTapAndHold()");
clear();
mViewportDraggingState.mZoomedInBeforeDrag =
mFullScreenMagnificationController.isMagnifying(mDisplayId);
// Triple tap and hold also belongs to triple tap event.
final boolean enabled = !mViewportDraggingState.mZoomedInBeforeDrag;
final boolean enabled = !isActivated();
logMagnificationTripleTap(enabled);
zoomOn(down.getX(), down.getY());
mViewportDraggingState.prepareForZoomInTemporary();
zoomInTemporary(down.getX(), down.getY());
transitionTo(mViewportDraggingState);
}
@@ -919,7 +954,10 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
if (DEBUG_DETECTING) Slog.i(mLogTag, "setShortcutTriggered(" + state + ")");
mShortcutTriggered = state;
mFullScreenMagnificationController.setForceShowMagnifiableBounds(mDisplayId, state);
}
private boolean isShortcutTriggered() {
return mShortcutTriggered;
}
/**
@@ -948,12 +986,29 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
}
}
private void zoomInTemporary(float centerX, float centerY) {
final float currentScale = mFullScreenMagnificationController.getScale(mDisplayId);
final float persistedScale = MathUtils.constrain(
mFullScreenMagnificationController.getPersistedScale(mDisplayId),
MIN_SCALE, MAX_SCALE);
final float scale = MathUtils.constrain(Math.max(currentScale + 1.0f, persistedScale),
MIN_SCALE, MAX_SCALE);
zoomToScale(scale, centerX, centerY);
}
private void zoomOn(float centerX, float centerY) {
if (DEBUG_DETECTING) Slog.i(mLogTag, "zoomOn(" + centerX + ", " + centerY + ")");
final float scale = MathUtils.constrain(
mFullScreenMagnificationController.getPersistedScale(mDisplayId),
MIN_SCALE, MAX_SCALE);
zoomToScale(scale, centerX, centerY);
}
private void zoomToScale(float scale, float centerX, float centerY) {
scale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
mFullScreenMagnificationController.setScaleAndCenter(mDisplayId,
scale, centerX, centerY,
/* animate */ true,

View File

@@ -254,13 +254,15 @@ public class MagnificationController implements WindowMagnificationManager.Callb
final DisableMagnificationCallback animationEndCallback =
new DisableMagnificationCallback(transitionCallBack, displayId, targetMode,
scale, currentCenter, true);
setDisableMagnificationCallbackLocked(displayId, animationEndCallback);
if (targetMode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
screenMagnificationController.reset(displayId, animationEndCallback);
} else {
windowMagnificationMgr.disableWindowMagnification(displayId, false,
animationEndCallback);
}
setDisableMagnificationCallbackLocked(displayId, animationEndCallback);
}
/**
@@ -481,17 +483,17 @@ public class MagnificationController implements WindowMagnificationManager.Callb
*/
private boolean shouldNotifyMagnificationChange(int displayId, int changeMode) {
synchronized (mLock) {
final boolean fullScreenMagnifying = mFullScreenMagnificationController != null
&& mFullScreenMagnificationController.isMagnifying(displayId);
final boolean fullScreenActivated = mFullScreenMagnificationController != null
&& mFullScreenMagnificationController.isActivated(displayId);
final boolean windowEnabled = mWindowMagnificationMgr != null
&& mWindowMagnificationMgr.isWindowMagnifierEnabled(displayId);
final Integer transitionMode = mTransitionModes.get(displayId);
if (((changeMode == MAGNIFICATION_MODE_FULLSCREEN && fullScreenMagnifying)
if (((changeMode == MAGNIFICATION_MODE_FULLSCREEN && fullScreenActivated)
|| (changeMode == MAGNIFICATION_MODE_WINDOW && windowEnabled))
&& (transitionMode == null)) {
return true;
}
if ((!fullScreenMagnifying && !windowEnabled)
if ((!fullScreenActivated && !windowEnabled)
&& (transitionMode == null)) {
return true;
}
@@ -742,7 +744,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
mWindowMagnificationMgr.getCenterY(displayId));
} else {
if (mFullScreenMagnificationController == null
|| !mFullScreenMagnificationController.isMagnifying(displayId)) {
|| !mFullScreenMagnificationController.isActivated(displayId)) {
return null;
}
mTempPoint.set(mFullScreenMagnificationController.getCenterX(displayId),
@@ -766,9 +768,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
if (mFullScreenMagnificationController == null) {
return false;
}
isActivated = mFullScreenMagnificationController.isMagnifying(displayId)
|| mFullScreenMagnificationController.isForceShowMagnifiableBounds(
displayId);
isActivated = mFullScreenMagnificationController.isActivated(displayId);
}
} else if (mode == ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) {
synchronized (mLock) {
@@ -829,7 +829,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb
final FullScreenMagnificationController screenMagnificationController =
getFullScreenMagnificationController();
if (mCurrentMode == ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN
&& !screenMagnificationController.isMagnifying(mDisplayId)) {
&& !screenMagnificationController.isActivated(mDisplayId)) {
MagnificationConfig.Builder configBuilder =
new MagnificationConfig.Builder();
Region region = new Region();

View File

@@ -313,13 +313,13 @@ public class MagnificationProcessor {
}
/**
* {@link FullScreenMagnificationController#isMagnifying(int)}
* {@link FullScreenMagnificationController#isActivated(int)}
* {@link WindowMagnificationManager#isWindowMagnifierEnabled(int)}
*/
public boolean isMagnifying(int displayId) {
int mode = getControllingMode(displayId);
if (mode == MAGNIFICATION_MODE_FULLSCREEN) {
return mController.getFullScreenMagnificationController().isMagnifying(displayId);
return mController.getFullScreenMagnificationController().isActivated(displayId);
} else if (mode == MAGNIFICATION_MODE_WINDOW) {
return mController.getWindowMagnificationMgr().isWindowMagnifierEnabled(displayId);
}

View File

@@ -891,8 +891,7 @@ final class AccessibilityController {
// to show the border. We will do so when the pending message is handled.
if (!mHandler.hasMessages(
MyHandler.MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED)) {
setMagnifiedRegionBorderShown(
isMagnifying() || isForceShowingMagnifiableBounds(), true);
setMagnifiedRegionBorderShown(isForceShowingMagnifiableBounds(), true);
}
}
@@ -1057,7 +1056,7 @@ final class AccessibilityController {
// rotation or folding/unfolding the device. In the rotation case, the screenshot
// used for rotation already has the border. After the rotation is complete
// we will show the border.
if (isMagnifying() || isForceShowingMagnifiableBounds()) {
if (isForceShowingMagnifiableBounds()) {
setMagnifiedRegionBorderShown(false, false);
final long delay = (long) (mLongAnimationDuration
* mService.getWindowAnimationScaleLocked());
@@ -1398,8 +1397,7 @@ final class AccessibilityController {
case MESSAGE_SHOW_MAGNIFIED_REGION_BOUNDS_IF_NEEDED : {
synchronized (mService.mGlobalLock) {
if (mMagnifedViewport.isMagnifying()
|| isForceShowingMagnifiableBounds()) {
if (isForceShowingMagnifiableBounds()) {
mMagnifedViewport.setMagnifiedRegionBorderShown(true, true);
mService.scheduleAnimationLocked();
}

View File

@@ -214,7 +214,8 @@ public class FullScreenMagnificationControllerTest {
}
private void notRegistered_publicMethodsShouldBeBenign(int displayId) {
assertFalse(mFullScreenMagnificationController.isMagnifying(displayId));
checkActivatedAndMagnifyingState(/* activated= */false, /* magnifying= */false, displayId);
assertFalse(
mFullScreenMagnificationController.magnificationRegionContains(displayId, 100,
100));
@@ -646,9 +647,9 @@ public class FullScreenMagnificationControllerTest {
.setScale(displayId, 1.5f, startCenter.x, startCenter.y, false,
SERVICE_ID_2);
assertFalse(mFullScreenMagnificationController.resetIfNeeded(displayId, SERVICE_ID_1));
assertTrue(mFullScreenMagnificationController.isMagnifying(displayId));
checkActivatedAndMagnifyingState(/* activated= */true, /* magnifying= */true, displayId);
assertTrue(mFullScreenMagnificationController.resetIfNeeded(displayId, SERVICE_ID_2));
assertFalse(mFullScreenMagnificationController.isMagnifying(displayId));
checkActivatedAndMagnifyingState(/* activated= */false, /* magnifying= */false, displayId);
}
@Test
@@ -667,7 +668,7 @@ public class FullScreenMagnificationControllerTest {
assertTrue(mFullScreenMagnificationController.resetIfNeeded(displayId, false));
verify(mRequestObserver).onFullScreenMagnificationChanged(eq(displayId),
eq(INITIAL_MAGNIFICATION_REGION), any(MagnificationConfig.class));
assertFalse(mFullScreenMagnificationController.isMagnifying(displayId));
checkActivatedAndMagnifyingState(/* activated= */false, /* magnifying= */false, displayId);
assertFalse(mFullScreenMagnificationController.resetIfNeeded(displayId, false));
}
@@ -731,7 +732,7 @@ public class FullScreenMagnificationControllerTest {
mTargetAnimationListener.onAnimationUpdate(mMockValueAnimator);
mStateListener.onAnimationEnd(mMockValueAnimator);
assertFalse(mFullScreenMagnificationController.isMagnifying(DISPLAY_0));
checkActivatedAndMagnifyingState(/* activated= */false, /* magnifying= */false, displayId);
verify(lastAnimationCallback).onResult(true);
}
@@ -749,8 +750,8 @@ public class FullScreenMagnificationControllerTest {
mMessageCapturingHandler.sendAllMessages();
br.onReceive(mMockContext, null);
mMessageCapturingHandler.sendAllMessages();
assertFalse(mFullScreenMagnificationController.isMagnifying(DISPLAY_0));
assertFalse(mFullScreenMagnificationController.isMagnifying(DISPLAY_1));
checkActivatedAndMagnifyingState(/* activated= */false, /* magnifying= */false, DISPLAY_0);
checkActivatedAndMagnifyingState(/* activated= */false, /* magnifying= */false, DISPLAY_1);
}
@Test
@@ -768,7 +769,7 @@ public class FullScreenMagnificationControllerTest {
mMessageCapturingHandler.sendAllMessages();
callbacks.onUserContextChanged();
mMessageCapturingHandler.sendAllMessages();
assertFalse(mFullScreenMagnificationController.isMagnifying(displayId));
checkActivatedAndMagnifyingState(/* activated= */false, /* magnifying= */false, displayId);
}
@Test
@@ -784,10 +785,10 @@ public class FullScreenMagnificationControllerTest {
MagnificationCallbacks callbacks = getMagnificationCallbacks(displayId);
zoomIn2xToMiddle(displayId);
mMessageCapturingHandler.sendAllMessages();
assertTrue(mFullScreenMagnificationController.isMagnifying(displayId));
checkActivatedAndMagnifyingState(/* activated= */true, /* magnifying= */true, displayId);
callbacks.onDisplaySizeChanged();
mMessageCapturingHandler.sendAllMessages();
assertFalse(mFullScreenMagnificationController.isMagnifying(displayId));
checkActivatedAndMagnifyingState(/* activated= */false, /* magnifying= */false, DISPLAY_0);
}
@Test
@@ -1133,22 +1134,16 @@ public class FullScreenMagnificationControllerTest {
}
@Test
public void testSetForceShowMagnifiableBounds() {
public void testZoomTo1x_shouldActivatedAndForceShowMagnifiableBounds() {
register(DISPLAY_0);
final float scale = 1.0f;
mFullScreenMagnificationController.setScaleAndCenter(
DISPLAY_0, scale, Float.NaN, Float.NaN, true, SERVICE_ID_1);
mFullScreenMagnificationController.setForceShowMagnifiableBounds(DISPLAY_0, true);
checkActivatedAndMagnifyingState(/* activated= */true, /* magnifying= */false, DISPLAY_0);
verify(mMockWindowManager).setForceShowMagnifiableBounds(DISPLAY_0, true);
}
@Test
public void testIsForceShowMagnifiableBounds() {
register(DISPLAY_0);
mFullScreenMagnificationController.setForceShowMagnifiableBounds(DISPLAY_0, true);
assertTrue(mFullScreenMagnificationController.isForceShowMagnifiableBounds(DISPLAY_0));
}
@Test
public void testSetScale_toMagnifying_shouldNotifyActivatedState() {
setScaleToMagnifying();
@@ -1220,7 +1215,15 @@ public class FullScreenMagnificationControllerTest {
float scale = 2.0f;
mFullScreenMagnificationController.setScale(displayId, scale, startCenter.x, startCenter.y,
false, SERVICE_ID_1);
assertTrue(mFullScreenMagnificationController.isMagnifying(displayId));
checkActivatedAndMagnifyingState(/* activated= */true, /* magnifying= */true, displayId);
}
private void checkActivatedAndMagnifyingState(
boolean activated, boolean magnifying, int displayId) {
final boolean isActivated = mFullScreenMagnificationController.isActivated(displayId);
final boolean isMagnifying = mFullScreenMagnificationController.getScale(displayId) > 1.0f;
assertTrue(isActivated == activated);
assertTrue(isMagnifying == magnifying);
}
private MagnificationCallbacks getMagnificationCallbacks(int displayId) {

View File

@@ -19,6 +19,7 @@ package com.android.server.accessibility.magnification;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_INDEX_SHIFT;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
@@ -78,24 +79,25 @@ import java.util.function.IntConsumer;
* {@code
* digraph {
* IDLE -> SHORTCUT_TRIGGERED [label="a11y\nbtn"]
* SHORTCUT_TRIGGERED -> IDLE [label="a11y\nbtn"]
* IDLE -> DOUBLE_TAP [label="2tap"]
* DOUBLE_TAP -> IDLE [label="timeout"]
* DOUBLE_TAP -> TRIPLE_TAP_AND_HOLD [label="down"]
* SHORTCUT_TRIGGERED -> TRIPLE_TAP_AND_HOLD [label="down"]
* TRIPLE_TAP_AND_HOLD -> ZOOMED [label="up"]
* TRIPLE_TAP_AND_HOLD -> DRAGGING_TMP [label="hold/\nswipe"]
* DRAGGING_TMP -> IDLE [label="release"]
* DOUBLE_TAP -> ZOOMED [label="tap"]
* DOUBLE_TAP -> NON_ACTIVATED_ZOOMED_TMP [label="hold"]
* NON_ACTIVATED_ZOOMED_TMP -> IDLE [label="release"]
* SHORTCUT_TRIGGERED -> IDLE [label="a11y\nbtn"]
* SHORTCUT_TRIGGERED -> ZOOMED[label="tap"]
* SHORTCUT_TRIGGERED -> ACTIVATED_ZOOMED_TMP [label="hold"]
* SHORTCUT_TRIGGERED -> PANNING [label="2hold]
* ZOOMED -> ZOOMED_DOUBLE_TAP [label="2tap"]
* ZOOMED_DOUBLE_TAP -> ZOOMED [label="timeout"]
* ZOOMED_DOUBLE_TAP -> DRAGGING [label="hold"]
* ZOOMED_DOUBLE_TAP -> IDLE [label="tap"]
* DRAGGING -> ZOOMED [label="release"]
* ZOOMED -> IDLE [label="a11y\nbtn"]
* ZOOMED -> PANNING [label="2hold"]
* ZOOMED_DOUBLE_TAP -> ZOOMED [label="timeout"]
* ZOOMED_DOUBLE_TAP -> ACTIVATED_ZOOMED_TMP [label="hold"]
* ZOOMED_DOUBLE_TAP -> IDLE [label="tap"]
* ACTIVATED_ZOOMED_TMP -> ZOOMED [label="release"]
* PANNING -> ZOOMED [label="release"]
* PANNING -> PANNING_SCALING [label="pinch"]
* PANNING_SCALING -> ZOOMED [label="release"]
* PANNING -> ZOOMED [label="release"]
* }
* }
*/
@@ -107,12 +109,11 @@ public class FullScreenMagnificationGestureHandlerTest {
public static final int STATE_2TAPS = 3;
public static final int STATE_ZOOMED_2TAPS = 4;
public static final int STATE_SHORTCUT_TRIGGERED = 5;
public static final int STATE_DRAGGING_TMP = 6;
public static final int STATE_DRAGGING = 7;
public static final int STATE_NON_ACTIVATED_ZOOMED_TMP = 6;
public static final int STATE_ACTIVATED_ZOOMED_TMP = 7;
public static final int STATE_PANNING = 8;
public static final int STATE_SCALING_AND_PANNING = 9;
public static final int FIRST_STATE = STATE_IDLE;
public static final int LAST_STATE = STATE_SCALING_AND_PANNING;
@@ -164,10 +165,6 @@ public class FullScreenMagnificationGestureHandlerTest {
public boolean magnificationRegionContains(int displayId, float x, float y) {
return true;
}
@Override
void setForceShowMagnifiableBounds(int displayId, boolean show) {
}
};
mFullScreenMagnificationController.register(DISPLAY_0);
mClock = new OffsettableClock.Stopped();
@@ -266,11 +263,11 @@ public class FullScreenMagnificationGestureHandlerTest {
@SuppressWarnings("Convert2MethodRef")
@Test
public void testAlternativeTransitions_areWorking() {
// A11y button followed by a tap&hold turns temporary "viewport dragging" zoom on
// A11y button followed by a tap&hold turns temporary "viewport dragging" zoom in
assertTransition(STATE_SHORTCUT_TRIGGERED, () -> {
send(downEvent());
fastForward1sec();
}, STATE_DRAGGING_TMP);
}, STATE_ACTIVATED_ZOOMED_TMP);
// A11y button followed by a tap turns zoom on
assertTransition(STATE_SHORTCUT_TRIGGERED, () -> tap(), STATE_ZOOMED);
@@ -281,7 +278,6 @@ public class FullScreenMagnificationGestureHandlerTest {
// A11y button turns zoom off
assertTransition(STATE_ZOOMED, () -> triggerShortcut(), STATE_IDLE);
// Double tap times out while zoomed
assertTransition(STATE_ZOOMED_2TAPS, () -> {
allowEventDelegation();
@@ -291,8 +287,11 @@ public class FullScreenMagnificationGestureHandlerTest {
// tap+tap+swipe doesn't get delegated
assertTransition(STATE_2TAPS, () -> swipe(), STATE_IDLE);
// tap+tap+swipe initiates viewport dragging immediately
assertTransition(STATE_2TAPS, () -> swipeAndHold(), STATE_DRAGGING_TMP);
// tap+tap+swipe&hold initiates temporary viewport dragging zoom in immediately
assertTransition(STATE_2TAPS, () -> swipeAndHold(), STATE_NON_ACTIVATED_ZOOMED_TMP);
// release when activated temporary zoom in back to zoomed
assertTransition(STATE_ACTIVATED_ZOOMED_TMP, () -> upEvent(), STATE_ZOOMED);
}
@Test
@@ -337,8 +336,10 @@ public class FullScreenMagnificationGestureHandlerTest {
@Test
public void testTripleTapAndHold_zoomsImmediately() {
assertZoomsImmediatelyOnSwipeFrom(STATE_2TAPS);
assertZoomsImmediatelyOnSwipeFrom(STATE_SHORTCUT_TRIGGERED);
assertZoomsImmediatelyOnSwipeFrom(STATE_2TAPS, STATE_NON_ACTIVATED_ZOOMED_TMP);
assertZoomsImmediatelyOnSwipeFrom(STATE_SHORTCUT_TRIGGERED, STATE_ACTIVATED_ZOOMED_TMP);
assertZoomsImmediatelyOnSwipeFrom(STATE_ZOOMED_2TAPS, STATE_ACTIVATED_ZOOMED_TMP);
}
@Test
@@ -391,10 +392,10 @@ public class FullScreenMagnificationGestureHandlerTest {
PointF pointer3 = new PointF(DEFAULT_X * 2, DEFAULT_Y);
send(downEvent());
send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}));
send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2, pointer3}));
send(pointerEvent(ACTION_POINTER_UP, new PointF[] {pointer1, pointer2, pointer3}));
send(pointerEvent(ACTION_POINTER_UP, new PointF[] {pointer1, pointer2, pointer3}));
send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}, 1));
send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2, pointer3}, 2));
send(pointerEvent(ACTION_POINTER_UP, new PointF[] {pointer1, pointer2, pointer3}, 2));
send(pointerEvent(ACTION_POINTER_UP, new PointF[] {pointer1, pointer2, pointer3}, 2));
send(upEvent());
assertIn(STATE_ZOOMED);
@@ -411,38 +412,53 @@ public class FullScreenMagnificationGestureHandlerTest {
}
@Test
public void testFirstFingerSwipe_TwoPinterDownAndZoomedState_panningState() {
public void testFirstFingerSwipe_twoPointerDownAndZoomedState_panningState() {
goFromStateIdleTo(STATE_ZOOMED);
PointF pointer1 = DEFAULT_POINT;
PointF pointer2 = new PointF(DEFAULT_X * 1.5f, DEFAULT_Y);
send(downEvent());
send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}));
send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}, 1));
//The minimum movement to transit to panningState.
final float sWipeMinDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
pointer1.offset(sWipeMinDistance + 1, 0);
send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}));
send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 0));
assertIn(STATE_PANNING);
assertIn(STATE_PANNING);
returnToNormalFrom(STATE_PANNING);
}
@Test
public void testSecondFingerSwipe_TwoPinterDownAndZoomedState_panningState() {
public void testSecondFingerSwipe_twoPointerDownAndZoomedState_panningState() {
goFromStateIdleTo(STATE_ZOOMED);
PointF pointer1 = DEFAULT_POINT;
PointF pointer2 = new PointF(DEFAULT_X * 1.5f, DEFAULT_Y);
send(downEvent());
send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}));
send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}, 1));
//The minimum movement to transit to panningState.
final float sWipeMinDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
pointer2.offset(sWipeMinDistance + 1, 0);
send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}));
send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 1));
assertIn(STATE_PANNING);
returnToNormalFrom(STATE_PANNING);
}
@Test
public void testSecondFingerSwipe_twoPointerDownAndShortcutTriggeredState_panningState() {
goFromStateIdleTo(STATE_SHORTCUT_TRIGGERED);
PointF pointer1 = DEFAULT_POINT;
PointF pointer2 = new PointF(DEFAULT_X * 1.5f, DEFAULT_Y);
send(downEvent());
send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}, 1));
//The minimum movement to transit to panningState.
final float sWipeMinDistance = ViewConfiguration.get(mContext).getScaledTouchSlop();
pointer2.offset(sWipeMinDistance + 1, 0);
send(pointerEvent(ACTION_MOVE, new PointF[] {pointer1, pointer2}, 1));
assertIn(STATE_PANNING);
returnToNormalFrom(STATE_PANNING);
}
@@ -474,11 +490,11 @@ public class FullScreenMagnificationGestureHandlerTest {
}
}
private void assertZoomsImmediatelyOnSwipeFrom(int state) {
goFromStateIdleTo(state);
private void assertZoomsImmediatelyOnSwipeFrom(int fromState, int toState) {
goFromStateIdleTo(fromState);
swipeAndHold();
assertIn(STATE_DRAGGING_TMP);
returnToNormalFrom(STATE_DRAGGING_TMP);
assertIn(toState);
returnToNormalFrom(toState);
}
private void assertTransition(int fromState, Runnable transitionAction, int toState) {
@@ -522,44 +538,51 @@ public class FullScreenMagnificationGestureHandlerTest {
case STATE_IDLE: {
check(tapCount() < 2, state);
check(!mMgh.mDetectingState.mShortcutTriggered, state);
check(!isActivated(), state);
check(!isZoomed(), state);
} break;
case STATE_ZOOMED: {
check(isActivated(), state);
check(isZoomed(), state);
check(tapCount() < 2, state);
} break;
case STATE_2TAPS: {
check(!isActivated(), state);
check(!isZoomed(), state);
check(tapCount() == 2, state);
} break;
case STATE_ZOOMED_2TAPS: {
check(isActivated(), state);
check(isZoomed(), state);
check(tapCount() == 2, state);
} break;
case STATE_DRAGGING: {
case STATE_NON_ACTIVATED_ZOOMED_TMP: {
check(isActivated(), state);
check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mViewportDraggingState,
state);
check(mMgh.mViewportDraggingState.mZoomedInBeforeDrag, state);
check(!mMgh.mViewportDraggingState.mActivatedBeforeDrag, state);
} break;
case STATE_DRAGGING_TMP: {
case STATE_ACTIVATED_ZOOMED_TMP: {
check(isActivated(), state);
check(isZoomed(), state);
check(mMgh.mCurrentState == mMgh.mViewportDraggingState,
state);
check(!mMgh.mViewportDraggingState.mZoomedInBeforeDrag, state);
check(mMgh.mViewportDraggingState.mActivatedBeforeDrag, state);
} break;
case STATE_SHORTCUT_TRIGGERED: {
check(mMgh.mDetectingState.mShortcutTriggered, state);
check(isActivated(), state);
check(!isZoomed(), state);
} break;
case STATE_PANNING: {
check(isZoomed(), state);
check(isActivated(), state);
check(mMgh.mCurrentState == mMgh.mPanningScalingState,
state);
check(!mMgh.mPanningScalingState.mScaling, state);
} break;
case STATE_SCALING_AND_PANNING: {
check(isZoomed(), state);
check(isActivated(), state);
check(mMgh.mCurrentState == mMgh.mPanningScalingState,
state);
check(mMgh.mPanningScalingState.mScaling, state);
@@ -596,13 +619,13 @@ public class FullScreenMagnificationGestureHandlerTest {
tap();
tap();
} break;
case STATE_DRAGGING: {
goFromStateIdleTo(STATE_ZOOMED_2TAPS);
case STATE_NON_ACTIVATED_ZOOMED_TMP: {
goFromStateIdleTo(STATE_2TAPS);
send(downEvent());
fastForward1sec();
} break;
case STATE_DRAGGING_TMP: {
goFromStateIdleTo(STATE_2TAPS);
case STATE_ACTIVATED_ZOOMED_TMP: {
goFromStateIdleTo(STATE_ZOOMED_2TAPS);
send(downEvent());
fastForward1sec();
} break;
@@ -654,13 +677,13 @@ public class FullScreenMagnificationGestureHandlerTest {
case STATE_ZOOMED_2TAPS: {
tap();
} break;
case STATE_DRAGGING: {
case STATE_NON_ACTIVATED_ZOOMED_TMP: {
send(upEvent());
} break;
case STATE_ACTIVATED_ZOOMED_TMP: {
send(upEvent());
returnToNormalFrom(STATE_ZOOMED);
} break;
case STATE_DRAGGING_TMP: {
send(upEvent());
} break;
case STATE_SHORTCUT_TRIGGERED: {
triggerShortcut();
} break;
@@ -682,8 +705,12 @@ public class FullScreenMagnificationGestureHandlerTest {
}
}
private boolean isActivated() {
return mMgh.mFullScreenMagnificationController.isActivated(DISPLAY_0);
}
private boolean isZoomed() {
return mMgh.mFullScreenMagnificationController.isMagnifying(DISPLAY_0);
return mMgh.mFullScreenMagnificationController.getScale(DISPLAY_0) > 1.0f;
}
private int tapCount() {
@@ -770,10 +797,10 @@ public class FullScreenMagnificationGestureHandlerTest {
private MotionEvent pointerEvent(int action, float x, float y) {
return pointerEvent(action, new PointF[] {DEFAULT_POINT, new PointF(x, y)});
return pointerEvent(action, new PointF[] {DEFAULT_POINT, new PointF(x, y)}, 1);
}
private MotionEvent pointerEvent(int action, PointF[] pointersPosition) {
private MotionEvent pointerEvent(int action, PointF[] pointersPosition, int changedIndex) {
final MotionEvent.PointerProperties[] PointerPropertiesArray =
new MotionEvent.PointerProperties[pointersPosition.length];
for (int i = 0; i < pointersPosition.length; i++) {
@@ -792,6 +819,8 @@ public class FullScreenMagnificationGestureHandlerTest {
pointerCoordsArray[i] = pointerCoords;
}
action += (changedIndex << ACTION_POINTER_INDEX_SHIFT);
return MotionEvent.obtain(
/* downTime */ mClock.now(),
/* eventTime */ mClock.now(),

View File

@@ -494,16 +494,6 @@ public class MagnificationControllerTest {
eq(MODE_FULLSCREEN));
}
@Test
public void setScaleOneThroughExternalRequest_fullScreenEnabled_removeMagnificationButton()
throws RemoteException {
setMagnificationEnabled(MODE_FULLSCREEN);
mScreenMagnificationController.setScaleAndCenter(TEST_DISPLAY, 1.0f,
MAGNIFIED_CENTER_X, MAGNIFIED_CENTER_Y, false, TEST_SERVICE_ID);
verify(mWindowMagnificationManager).removeMagnificationButton(eq(TEST_DISPLAY));
}
@Test
public void onPerformScaleAction_magnifierEnabled_handleScaleChange() throws RemoteException {
final float newScale = 4.0f;
@@ -756,7 +746,7 @@ public class MagnificationControllerTest {
mMagnificationController.onWindowMagnificationActivationState(TEST_DISPLAY, true);
assertFalse(mScreenMagnificationController.isMagnifying(TEST_DISPLAY));
verify(mScreenMagnificationController).reset(eq(TEST_DISPLAY), eq(false));
}
@Test