Loading services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +2 −1 Original line number Diff line number Diff line Loading @@ -607,7 +607,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mLock, mContext, new MagnificationScaleProvider(mContext), Executors.newSingleThreadExecutor() Executors.newSingleThreadExecutor(), mContext.getMainLooper() ); mMagnificationProcessor = new MagnificationProcessor(mMagnificationController); mCaptioningManagerImpl = new CaptioningManagerImpl(mContext); Loading services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java +65 −8 Original line number Diff line number Diff line Loading @@ -36,6 +36,8 @@ import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; Loading @@ -53,6 +55,7 @@ import android.view.accessibility.MagnificationAnimationCallback; import com.android.internal.accessibility.util.AccessibilityStatsLogUtils; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.wm.WindowManagerInternal; Loading Loading @@ -111,6 +114,20 @@ public class MagnificationController implements MagnificationConnectionManager.C private final Executor mBackgroundExecutor; private final Handler mHandler; private @PanDirection int mActivePanDirection = PAN_DIRECTION_DOWN; private int mActivePanDisplay = Display.INVALID_DISPLAY; private boolean mRepeatKeysEnabled = true; private @ZoomDirection int mActiveZoomDirection = ZOOM_DIRECTION_IN; private int mActiveZoomDisplay = Display.INVALID_DISPLAY; // TODO(b/355499907): Get initial repeat interval from repeat keys settings. @VisibleForTesting public static final int INITIAL_KEYBOARD_REPEAT_INTERVAL_MS = 500; @VisibleForTesting public static final int KEYBOARD_REPEAT_INTERVAL_MS = 60; @GuardedBy("mLock") private final SparseIntArray mCurrentMagnificationModeArray = new SparseIntArray(); @GuardedBy("mLock") Loading Loading @@ -287,12 +304,13 @@ public class MagnificationController implements MagnificationConnectionManager.C public MagnificationController(AccessibilityManagerService ams, Object lock, Context context, MagnificationScaleProvider scaleProvider, Executor backgroundExecutor) { Executor backgroundExecutor, Looper looper) { mAms = ams; mLock = lock; mContext = context; mScaleProvider = scaleProvider; mBackgroundExecutor = backgroundExecutor; mHandler = new Handler(looper); LocalServices.getService(WindowManagerInternal.class) .getAccessibilityController().setUiChangesForAccessibilityCallbacks(this); mSupportWindowMagnification = context.getPackageManager().hasSystemFeature( Loading @@ -303,14 +321,20 @@ public class MagnificationController implements MagnificationConnectionManager.C mAlwaysOnMagnificationFeatureFlag = new AlwaysOnMagnificationFeatureFlag(context); mAlwaysOnMagnificationFeatureFlag.addOnChangedListener( mBackgroundExecutor, mAms::updateAlwaysOnMagnification); // TODO(b/355499907): Add an observer for repeat keys enabled changes, // rather than initializing once at startup. mRepeatKeysEnabled = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.KEY_REPEAT_ENABLED, 1, UserHandle.USER_CURRENT) != 0; } @VisibleForTesting public MagnificationController(AccessibilityManagerService ams, Object lock, Context context, FullScreenMagnificationController fullScreenMagnificationController, MagnificationConnectionManager magnificationConnectionManager, MagnificationScaleProvider scaleProvider, Executor backgroundExecutor) { this(ams, lock, context, scaleProvider, backgroundExecutor); MagnificationScaleProvider scaleProvider, Executor backgroundExecutor, Looper looper) { this(ams, lock, context, scaleProvider, backgroundExecutor, looper); mFullScreenMagnificationController = fullScreenMagnificationController; mMagnificationConnectionManager = magnificationConnectionManager; } Loading Loading @@ -354,27 +378,60 @@ public class MagnificationController implements MagnificationConnectionManager.C // pan diagonally) by decreasing diagonal movement by sqrt(2) to make it appear the same // speed as non-diagonal movement. panMagnificationByStep(displayId, direction); mActivePanDirection = direction; mActivePanDisplay = displayId; if (mRepeatKeysEnabled) { mHandler.sendMessageDelayed( PooledLambda.obtainMessage(MagnificationController::maybeContinuePan, this), INITIAL_KEYBOARD_REPEAT_INTERVAL_MS); } } @Override public void onPanMagnificationStop(int displayId, @MagnificationController.PanDirection int direction) { // TODO(b/388847283): Handle held key gestures, which can be used // for continuous scaling and panning, until they are released. if (direction == mActivePanDirection) { mActivePanDisplay = Display.INVALID_DISPLAY; } } @Override public void onScaleMagnificationStart(int displayId, @MagnificationController.ZoomDirection int direction) { scaleMagnificationByStep(displayId, direction); mActiveZoomDirection = direction; mActiveZoomDisplay = displayId; if (mRepeatKeysEnabled) { mHandler.sendMessageDelayed( PooledLambda.obtainMessage(MagnificationController::maybeContinueZoom, this), INITIAL_KEYBOARD_REPEAT_INTERVAL_MS); } } @Override public void onScaleMagnificationStop(int displayId, @MagnificationController.ZoomDirection int direction) { // TODO(b/388847283): Handle held key gestures, which can be used // for continuous scaling and panning, until they are released. if (direction == mActiveZoomDirection) { mActiveZoomDisplay = Display.INVALID_DISPLAY; } } private void maybeContinuePan() { if (mActivePanDisplay != Display.INVALID_DISPLAY) { panMagnificationByStep(mActivePanDisplay, mActivePanDirection); mHandler.sendMessageDelayed( PooledLambda.obtainMessage(MagnificationController::maybeContinuePan, this), KEYBOARD_REPEAT_INTERVAL_MS); } } private void maybeContinueZoom() { if (mActiveZoomDisplay != Display.INVALID_DISPLAY) { scaleMagnificationByStep(mActiveZoomDisplay, mActiveZoomDirection); mHandler.sendMessageDelayed( PooledLambda.obtainMessage(MagnificationController::maybeContinueZoom, this), KEYBOARD_REPEAT_INTERVAL_MS); } } private void handleUserInteractionChanged(int displayId, int mode) { Loading services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java +106 −15 Original line number Diff line number Diff line Loading @@ -58,9 +58,9 @@ import android.graphics.Rect; import android.graphics.Region; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerInternal; import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import android.os.test.TestLooper; import android.provider.Settings; import android.test.mock.MockContentResolver; import android.testing.DexmakerShareClassLoaderRule; Loading Loading @@ -173,6 +173,8 @@ public class MagnificationControllerTest { @Mock private Scroller mMockScroller; private TestLooper mTestLooper; // To mock package-private class @Rule public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = Loading @@ -199,14 +201,16 @@ public class MagnificationControllerTest { mMockResolver = new MockContentResolver(); mMockResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); Looper looper = InstrumentationRegistry.getContext().getMainLooper(); // Pretending ID of the Thread associated with looper as main thread ID in controller when(mContext.getMainLooper()).thenReturn(looper); mTestLooper = new TestLooper(); when(mContext.getMainLooper()).thenReturn( InstrumentationRegistry.getContext().getMainLooper()); when(mContext.getContentResolver()).thenReturn(mMockResolver); when(mContext.getPackageManager()).thenReturn(mPackageManager); Settings.Secure.putFloatForUser(mMockResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, DEFAULT_SCALE, CURRENT_USER_ID); Settings.Secure.putFloatForUser(mMockResolver, Settings.Secure.KEY_REPEAT_ENABLED, 1, CURRENT_USER_ID); mScaleProvider = spy(new MagnificationScaleProvider(mContext)); when(mControllerCtx.getContext()).thenReturn(mContext); Loading Loading @@ -251,7 +255,7 @@ public class MagnificationControllerTest { mMagnificationController = spy(new MagnificationController(mService, globalLock, mContext, mScreenMagnificationController, mMagnificationConnectionManager, mScaleProvider, ConcurrentUtils.DIRECT_EXECUTOR)); ConcurrentUtils.DIRECT_EXECUTOR, mTestLooper.getLooper())); mMagnificationController.setMagnificationCapabilities( Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL); Loading @@ -261,6 +265,7 @@ public class MagnificationControllerTest { @After public void tearDown() { mTestLooper.dispatchAll(); FakeSettingsProvider.clearSettingsProvider(); } Loading Loading @@ -879,6 +884,69 @@ public class MagnificationControllerTest { .that(numSteps).isLessThan(maxNumSteps); } @Test public void magnificationCallbacks_panMagnificationContinuous() throws RemoteException { setMagnificationEnabled(MODE_FULLSCREEN); mMagnificationController.onPerformScaleAction(TEST_DISPLAY, 8.0f, false); reset(mScreenMagnificationController); DisplayMetrics metrics = new DisplayMetrics(); mDisplay.getMetrics(metrics); float expectedStep = 27 * metrics.density; float currentCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float currentCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); // Start moving right using keyboard callbacks. mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_RIGHT); float newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(currentCenterX).isLessThan(newCenterX); expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); expect.that(currentCenterY).isEqualTo(newCenterY); currentCenterX = newCenterX; currentCenterY = newCenterY; // Wait for the initial delay to occur. advanceTime(MagnificationController.INITIAL_KEYBOARD_REPEAT_INTERVAL_MS + 1); // It should have moved again after the handler was triggered. newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(currentCenterX).isLessThan(newCenterX); expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); expect.that(currentCenterY).isEqualTo(newCenterY); currentCenterX = newCenterX; currentCenterY = newCenterY; // Wait for repeat delay to occur. advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); // It should have moved a third time. newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(currentCenterX).isLessThan(newCenterX); expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); expect.that(currentCenterY).isEqualTo(newCenterY); currentCenterX = newCenterX; currentCenterY = newCenterY; // Stop magnification pan. mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_RIGHT); // It should not move again, even after the appropriate delay. advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(newCenterX).isEqualTo(currentCenterX); expect.that(newCenterY).isEqualTo(currentCenterY); } @Test public void enableWindowMode_notifyMagnificationChanged() throws RemoteException { setMagnificationEnabled(MODE_WINDOW); Loading Loading @@ -1196,7 +1264,8 @@ public class MagnificationControllerTest { assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, lastActivatedMode); } @Test public void activateFullScreenMagnification_triggerCallback() throws RemoteException { @Test public void activateFullScreenMagnification_triggerCallback() throws RemoteException { setMagnificationEnabled(MODE_FULLSCREEN); verify(mMagnificationController).onFullScreenMagnificationActivationState( eq(TEST_DISPLAY), eq(true)); Loading Loading @@ -1573,8 +1642,8 @@ public class MagnificationControllerTest { float currentCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float currentCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); // Move right. mMagnificationController.panMagnificationByStep(TEST_DISPLAY, // Move right using keyboard callbacks. mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_RIGHT); float newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); Loading @@ -1582,11 +1651,13 @@ public class MagnificationControllerTest { expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); expect.that(currentCenterY).isEqualTo(newCenterY); mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_RIGHT); currentCenterX = newCenterX; currentCenterY = newCenterY; // Move left. mMagnificationController.panMagnificationByStep(TEST_DISPLAY, mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_LEFT); newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); Loading @@ -1594,11 +1665,13 @@ public class MagnificationControllerTest { expect.that(currentCenterX - newCenterX).isWithin(0.01f).of(expectedStep); expect.that(currentCenterY).isEqualTo(newCenterY); mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_LEFT); currentCenterX = newCenterX; currentCenterY = newCenterY; // Move down. mMagnificationController.panMagnificationByStep(TEST_DISPLAY, mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_DOWN); newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); Loading @@ -1606,17 +1679,22 @@ public class MagnificationControllerTest { expect.that(currentCenterY).isLessThan(newCenterY); expect.that(newCenterY - currentCenterY).isWithin(0.1f).of(expectedStep); mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_DOWN); currentCenterX = newCenterX; currentCenterY = newCenterY; // Move up. mMagnificationController.panMagnificationByStep(TEST_DISPLAY, mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_UP); newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(currentCenterX).isEqualTo(newCenterX); expect.that(currentCenterY).isGreaterThan(newCenterY); expect.that(currentCenterY - newCenterY).isWithin(0.01f).of(expectedStep); mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_UP); } private void testWindowMagnificationPanWithStepSize(float expectedStepDip) Loading @@ -1626,28 +1704,41 @@ public class MagnificationControllerTest { final float expectedStep = expectedStepDip * metrics.density; // Move right. mMagnificationController.panMagnificationByStep(TEST_DISPLAY, mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_RIGHT); verify(mMockConnection.getConnection()).moveWindowMagnifier(eq(TEST_DISPLAY), floatThat(step -> Math.abs(step - expectedStep) < 0.0001), eq(0.0f)); mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_RIGHT); // Move left. mMagnificationController.panMagnificationByStep(TEST_DISPLAY, mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_LEFT); verify(mMockConnection.getConnection()).moveWindowMagnifier(eq(TEST_DISPLAY), floatThat(step -> Math.abs(expectedStep - step) < 0.0001), eq(0.0f)); mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_LEFT); // Move down. mMagnificationController.panMagnificationByStep(TEST_DISPLAY, mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_DOWN); verify(mMockConnection.getConnection()).moveWindowMagnifier(eq(TEST_DISPLAY), eq(0.0f), floatThat(step -> Math.abs(expectedStep - step) < 0.0001)); mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_DOWN); // Move up. mMagnificationController.panMagnificationByStep(TEST_DISPLAY, mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_UP); verify(mMockConnection.getConnection()).moveWindowMagnifier(eq(TEST_DISPLAY), eq(0.0f), floatThat(step -> Math.abs(expectedStep - step) < 0.0001)); mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_UP); } private void advanceTime(long timeMs) { mTestLooper.moveTimeForward(timeMs); mTestLooper.dispatchAll(); } private static class WindowMagnificationMgrCallbackDelegate implements Loading Loading
services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +2 −1 Original line number Diff line number Diff line Loading @@ -607,7 +607,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mLock, mContext, new MagnificationScaleProvider(mContext), Executors.newSingleThreadExecutor() Executors.newSingleThreadExecutor(), mContext.getMainLooper() ); mMagnificationProcessor = new MagnificationProcessor(mMagnificationController); mCaptioningManagerImpl = new CaptioningManagerImpl(mContext); Loading
services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java +65 −8 Original line number Diff line number Diff line Loading @@ -36,6 +36,8 @@ import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; Loading @@ -53,6 +55,7 @@ import android.view.accessibility.MagnificationAnimationCallback; import com.android.internal.accessibility.util.AccessibilityStatsLogUtils; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.function.pooled.PooledLambda; import com.android.server.LocalServices; import com.android.server.accessibility.AccessibilityManagerService; import com.android.server.wm.WindowManagerInternal; Loading Loading @@ -111,6 +114,20 @@ public class MagnificationController implements MagnificationConnectionManager.C private final Executor mBackgroundExecutor; private final Handler mHandler; private @PanDirection int mActivePanDirection = PAN_DIRECTION_DOWN; private int mActivePanDisplay = Display.INVALID_DISPLAY; private boolean mRepeatKeysEnabled = true; private @ZoomDirection int mActiveZoomDirection = ZOOM_DIRECTION_IN; private int mActiveZoomDisplay = Display.INVALID_DISPLAY; // TODO(b/355499907): Get initial repeat interval from repeat keys settings. @VisibleForTesting public static final int INITIAL_KEYBOARD_REPEAT_INTERVAL_MS = 500; @VisibleForTesting public static final int KEYBOARD_REPEAT_INTERVAL_MS = 60; @GuardedBy("mLock") private final SparseIntArray mCurrentMagnificationModeArray = new SparseIntArray(); @GuardedBy("mLock") Loading Loading @@ -287,12 +304,13 @@ public class MagnificationController implements MagnificationConnectionManager.C public MagnificationController(AccessibilityManagerService ams, Object lock, Context context, MagnificationScaleProvider scaleProvider, Executor backgroundExecutor) { Executor backgroundExecutor, Looper looper) { mAms = ams; mLock = lock; mContext = context; mScaleProvider = scaleProvider; mBackgroundExecutor = backgroundExecutor; mHandler = new Handler(looper); LocalServices.getService(WindowManagerInternal.class) .getAccessibilityController().setUiChangesForAccessibilityCallbacks(this); mSupportWindowMagnification = context.getPackageManager().hasSystemFeature( Loading @@ -303,14 +321,20 @@ public class MagnificationController implements MagnificationConnectionManager.C mAlwaysOnMagnificationFeatureFlag = new AlwaysOnMagnificationFeatureFlag(context); mAlwaysOnMagnificationFeatureFlag.addOnChangedListener( mBackgroundExecutor, mAms::updateAlwaysOnMagnification); // TODO(b/355499907): Add an observer for repeat keys enabled changes, // rather than initializing once at startup. mRepeatKeysEnabled = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.KEY_REPEAT_ENABLED, 1, UserHandle.USER_CURRENT) != 0; } @VisibleForTesting public MagnificationController(AccessibilityManagerService ams, Object lock, Context context, FullScreenMagnificationController fullScreenMagnificationController, MagnificationConnectionManager magnificationConnectionManager, MagnificationScaleProvider scaleProvider, Executor backgroundExecutor) { this(ams, lock, context, scaleProvider, backgroundExecutor); MagnificationScaleProvider scaleProvider, Executor backgroundExecutor, Looper looper) { this(ams, lock, context, scaleProvider, backgroundExecutor, looper); mFullScreenMagnificationController = fullScreenMagnificationController; mMagnificationConnectionManager = magnificationConnectionManager; } Loading Loading @@ -354,27 +378,60 @@ public class MagnificationController implements MagnificationConnectionManager.C // pan diagonally) by decreasing diagonal movement by sqrt(2) to make it appear the same // speed as non-diagonal movement. panMagnificationByStep(displayId, direction); mActivePanDirection = direction; mActivePanDisplay = displayId; if (mRepeatKeysEnabled) { mHandler.sendMessageDelayed( PooledLambda.obtainMessage(MagnificationController::maybeContinuePan, this), INITIAL_KEYBOARD_REPEAT_INTERVAL_MS); } } @Override public void onPanMagnificationStop(int displayId, @MagnificationController.PanDirection int direction) { // TODO(b/388847283): Handle held key gestures, which can be used // for continuous scaling and panning, until they are released. if (direction == mActivePanDirection) { mActivePanDisplay = Display.INVALID_DISPLAY; } } @Override public void onScaleMagnificationStart(int displayId, @MagnificationController.ZoomDirection int direction) { scaleMagnificationByStep(displayId, direction); mActiveZoomDirection = direction; mActiveZoomDisplay = displayId; if (mRepeatKeysEnabled) { mHandler.sendMessageDelayed( PooledLambda.obtainMessage(MagnificationController::maybeContinueZoom, this), INITIAL_KEYBOARD_REPEAT_INTERVAL_MS); } } @Override public void onScaleMagnificationStop(int displayId, @MagnificationController.ZoomDirection int direction) { // TODO(b/388847283): Handle held key gestures, which can be used // for continuous scaling and panning, until they are released. if (direction == mActiveZoomDirection) { mActiveZoomDisplay = Display.INVALID_DISPLAY; } } private void maybeContinuePan() { if (mActivePanDisplay != Display.INVALID_DISPLAY) { panMagnificationByStep(mActivePanDisplay, mActivePanDirection); mHandler.sendMessageDelayed( PooledLambda.obtainMessage(MagnificationController::maybeContinuePan, this), KEYBOARD_REPEAT_INTERVAL_MS); } } private void maybeContinueZoom() { if (mActiveZoomDisplay != Display.INVALID_DISPLAY) { scaleMagnificationByStep(mActiveZoomDisplay, mActiveZoomDirection); mHandler.sendMessageDelayed( PooledLambda.obtainMessage(MagnificationController::maybeContinueZoom, this), KEYBOARD_REPEAT_INTERVAL_MS); } } private void handleUserInteractionChanged(int displayId, int mode) { Loading
services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java +106 −15 Original line number Diff line number Diff line Loading @@ -58,9 +58,9 @@ import android.graphics.Rect; import android.graphics.Region; import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManagerInternal; import android.os.Looper; import android.os.RemoteException; import android.os.UserHandle; import android.os.test.TestLooper; import android.provider.Settings; import android.test.mock.MockContentResolver; import android.testing.DexmakerShareClassLoaderRule; Loading Loading @@ -173,6 +173,8 @@ public class MagnificationControllerTest { @Mock private Scroller mMockScroller; private TestLooper mTestLooper; // To mock package-private class @Rule public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = Loading @@ -199,14 +201,16 @@ public class MagnificationControllerTest { mMockResolver = new MockContentResolver(); mMockResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); Looper looper = InstrumentationRegistry.getContext().getMainLooper(); // Pretending ID of the Thread associated with looper as main thread ID in controller when(mContext.getMainLooper()).thenReturn(looper); mTestLooper = new TestLooper(); when(mContext.getMainLooper()).thenReturn( InstrumentationRegistry.getContext().getMainLooper()); when(mContext.getContentResolver()).thenReturn(mMockResolver); when(mContext.getPackageManager()).thenReturn(mPackageManager); Settings.Secure.putFloatForUser(mMockResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, DEFAULT_SCALE, CURRENT_USER_ID); Settings.Secure.putFloatForUser(mMockResolver, Settings.Secure.KEY_REPEAT_ENABLED, 1, CURRENT_USER_ID); mScaleProvider = spy(new MagnificationScaleProvider(mContext)); when(mControllerCtx.getContext()).thenReturn(mContext); Loading Loading @@ -251,7 +255,7 @@ public class MagnificationControllerTest { mMagnificationController = spy(new MagnificationController(mService, globalLock, mContext, mScreenMagnificationController, mMagnificationConnectionManager, mScaleProvider, ConcurrentUtils.DIRECT_EXECUTOR)); ConcurrentUtils.DIRECT_EXECUTOR, mTestLooper.getLooper())); mMagnificationController.setMagnificationCapabilities( Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL); Loading @@ -261,6 +265,7 @@ public class MagnificationControllerTest { @After public void tearDown() { mTestLooper.dispatchAll(); FakeSettingsProvider.clearSettingsProvider(); } Loading Loading @@ -879,6 +884,69 @@ public class MagnificationControllerTest { .that(numSteps).isLessThan(maxNumSteps); } @Test public void magnificationCallbacks_panMagnificationContinuous() throws RemoteException { setMagnificationEnabled(MODE_FULLSCREEN); mMagnificationController.onPerformScaleAction(TEST_DISPLAY, 8.0f, false); reset(mScreenMagnificationController); DisplayMetrics metrics = new DisplayMetrics(); mDisplay.getMetrics(metrics); float expectedStep = 27 * metrics.density; float currentCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float currentCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); // Start moving right using keyboard callbacks. mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_RIGHT); float newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(currentCenterX).isLessThan(newCenterX); expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); expect.that(currentCenterY).isEqualTo(newCenterY); currentCenterX = newCenterX; currentCenterY = newCenterY; // Wait for the initial delay to occur. advanceTime(MagnificationController.INITIAL_KEYBOARD_REPEAT_INTERVAL_MS + 1); // It should have moved again after the handler was triggered. newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(currentCenterX).isLessThan(newCenterX); expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); expect.that(currentCenterY).isEqualTo(newCenterY); currentCenterX = newCenterX; currentCenterY = newCenterY; // Wait for repeat delay to occur. advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); // It should have moved a third time. newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(currentCenterX).isLessThan(newCenterX); expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); expect.that(currentCenterY).isEqualTo(newCenterY); currentCenterX = newCenterX; currentCenterY = newCenterY; // Stop magnification pan. mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_RIGHT); // It should not move again, even after the appropriate delay. advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(newCenterX).isEqualTo(currentCenterX); expect.that(newCenterY).isEqualTo(currentCenterY); } @Test public void enableWindowMode_notifyMagnificationChanged() throws RemoteException { setMagnificationEnabled(MODE_WINDOW); Loading Loading @@ -1196,7 +1264,8 @@ public class MagnificationControllerTest { assertEquals(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, lastActivatedMode); } @Test public void activateFullScreenMagnification_triggerCallback() throws RemoteException { @Test public void activateFullScreenMagnification_triggerCallback() throws RemoteException { setMagnificationEnabled(MODE_FULLSCREEN); verify(mMagnificationController).onFullScreenMagnificationActivationState( eq(TEST_DISPLAY), eq(true)); Loading Loading @@ -1573,8 +1642,8 @@ public class MagnificationControllerTest { float currentCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float currentCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); // Move right. mMagnificationController.panMagnificationByStep(TEST_DISPLAY, // Move right using keyboard callbacks. mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_RIGHT); float newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); Loading @@ -1582,11 +1651,13 @@ public class MagnificationControllerTest { expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); expect.that(currentCenterY).isEqualTo(newCenterY); mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_RIGHT); currentCenterX = newCenterX; currentCenterY = newCenterY; // Move left. mMagnificationController.panMagnificationByStep(TEST_DISPLAY, mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_LEFT); newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); Loading @@ -1594,11 +1665,13 @@ public class MagnificationControllerTest { expect.that(currentCenterX - newCenterX).isWithin(0.01f).of(expectedStep); expect.that(currentCenterY).isEqualTo(newCenterY); mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_LEFT); currentCenterX = newCenterX; currentCenterY = newCenterY; // Move down. mMagnificationController.panMagnificationByStep(TEST_DISPLAY, mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_DOWN); newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); Loading @@ -1606,17 +1679,22 @@ public class MagnificationControllerTest { expect.that(currentCenterY).isLessThan(newCenterY); expect.that(newCenterY - currentCenterY).isWithin(0.1f).of(expectedStep); mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_DOWN); currentCenterX = newCenterX; currentCenterY = newCenterY; // Move up. mMagnificationController.panMagnificationByStep(TEST_DISPLAY, mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_UP); newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(currentCenterX).isEqualTo(newCenterX); expect.that(currentCenterY).isGreaterThan(newCenterY); expect.that(currentCenterY - newCenterY).isWithin(0.01f).of(expectedStep); mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_UP); } private void testWindowMagnificationPanWithStepSize(float expectedStepDip) Loading @@ -1626,28 +1704,41 @@ public class MagnificationControllerTest { final float expectedStep = expectedStepDip * metrics.density; // Move right. mMagnificationController.panMagnificationByStep(TEST_DISPLAY, mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_RIGHT); verify(mMockConnection.getConnection()).moveWindowMagnifier(eq(TEST_DISPLAY), floatThat(step -> Math.abs(step - expectedStep) < 0.0001), eq(0.0f)); mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_RIGHT); // Move left. mMagnificationController.panMagnificationByStep(TEST_DISPLAY, mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_LEFT); verify(mMockConnection.getConnection()).moveWindowMagnifier(eq(TEST_DISPLAY), floatThat(step -> Math.abs(expectedStep - step) < 0.0001), eq(0.0f)); mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_LEFT); // Move down. mMagnificationController.panMagnificationByStep(TEST_DISPLAY, mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_DOWN); verify(mMockConnection.getConnection()).moveWindowMagnifier(eq(TEST_DISPLAY), eq(0.0f), floatThat(step -> Math.abs(expectedStep - step) < 0.0001)); mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_DOWN); // Move up. mMagnificationController.panMagnificationByStep(TEST_DISPLAY, mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_UP); verify(mMockConnection.getConnection()).moveWindowMagnifier(eq(TEST_DISPLAY), eq(0.0f), floatThat(step -> Math.abs(expectedStep - step) < 0.0001)); mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_UP); } private void advanceTime(long timeMs) { mTestLooper.moveTimeForward(timeMs); mTestLooper.dispatchAll(); } private static class WindowMagnificationMgrCallbackDelegate implements Loading