Loading services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +36 −0 Original line number Original line Diff line number Diff line Loading @@ -36,6 +36,7 @@ import static android.accessibilityservice.AccessibilityTrace.FLAGS_PACKAGE_BROA import static android.accessibilityservice.AccessibilityTrace.FLAGS_USER_BROADCAST_RECEIVER; import static android.accessibilityservice.AccessibilityTrace.FLAGS_USER_BROADCAST_RECEIVER; import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL; import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL; import static android.content.Context.DEVICE_ID_DEFAULT; import static android.content.Context.DEVICE_ID_DEFAULT; import static android.hardware.input.InputSettings.isRepeatKeysFeatureFlagEnabled; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; Loading Loading @@ -156,6 +157,7 @@ import android.view.KeyEvent; import android.view.MagnificationSpec; import android.view.MagnificationSpec; import android.view.MotionEvent; import android.view.MotionEvent; import android.view.SurfaceControl; import android.view.SurfaceControl; import android.view.ViewConfiguration; import android.view.WindowInfo; import android.view.WindowInfo; import android.view.WindowManager; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityEvent; Loading Loading @@ -3494,6 +3496,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub somethingChanged |= readMagnificationFollowTypingLocked(userState); somethingChanged |= readMagnificationFollowTypingLocked(userState); somethingChanged |= readAlwaysOnMagnificationLocked(userState); somethingChanged |= readAlwaysOnMagnificationLocked(userState); somethingChanged |= readMouseKeysEnabledLocked(userState); somethingChanged |= readMouseKeysEnabledLocked(userState); somethingChanged |= readRepeatKeysSettingsLocked(userState); return somethingChanged; return somethingChanged; } } Loading Loading @@ -5771,6 +5774,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final Uri mUserSetupCompleteUri = Settings.Secure.getUriFor( private final Uri mUserSetupCompleteUri = Settings.Secure.getUriFor( Settings.Secure.USER_SETUP_COMPLETE); Settings.Secure.USER_SETUP_COMPLETE); private final Uri mRepeatKeysEnabledUri = Settings.Secure.getUriFor( Settings.Secure.KEY_REPEAT_ENABLED); private final Uri mRepeatKeysTimeoutMsUri = Settings.Secure.getUriFor( Settings.Secure.KEY_REPEAT_TIMEOUT_MS); public AccessibilityContentObserver(Handler handler) { public AccessibilityContentObserver(Handler handler) { super(handler); super(handler); } } Loading Loading @@ -5827,6 +5836,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mNavigationModeUri, false, this, UserHandle.USER_ALL); mNavigationModeUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( contentResolver.registerContentObserver( mUserSetupCompleteUri, false, this, UserHandle.USER_ALL); mUserSetupCompleteUri, false, this, UserHandle.USER_ALL); if (isRepeatKeysFeatureFlagEnabled() && Flags.enableMagnificationKeyboardControl()) { contentResolver.registerContentObserver( mRepeatKeysEnabledUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mRepeatKeysTimeoutMsUri, false, this, UserHandle.USER_ALL); } } } @Override @Override Loading Loading @@ -5917,6 +5932,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } } else if (mNavigationModeUri.equals(uri) || mUserSetupCompleteUri.equals(uri)) { } else if (mNavigationModeUri.equals(uri) || mUserSetupCompleteUri.equals(uri)) { updateShortcutsForCurrentNavigationMode(); updateShortcutsForCurrentNavigationMode(); } else if (mRepeatKeysEnabledUri.equals(uri) || mRepeatKeysTimeoutMsUri.equals(uri)) { readRepeatKeysSettingsLocked(userState); } } } } } } Loading Loading @@ -6055,6 +6073,24 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return false; return false; } } boolean readRepeatKeysSettingsLocked(AccessibilityUserState userState) { if (!isRepeatKeysFeatureFlagEnabled() || !Flags.enableMagnificationKeyboardControl()) { return false; } final boolean isRepeatKeysEnabled = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.KEY_REPEAT_ENABLED, 1, userState.mUserId) == 1; final int repeatKeysTimeoutMs = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.KEY_REPEAT_TIMEOUT_MS, ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT, userState.mUserId); mMagnificationController.setRepeatKeysEnabled(isRepeatKeysEnabled); mMagnificationController.setRepeatKeysTimeoutMs(repeatKeysTimeoutMs); // No need to update any other state, so always return false. return false; } boolean readMouseKeysEnabledLocked(AccessibilityUserState userState) { boolean readMouseKeysEnabledLocked(AccessibilityUserState userState) { if (!keyboardA11yMouseKeys()) { if (!keyboardA11yMouseKeys()) { return false; return false; Loading services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java +18 −11 Original line number Original line Diff line number Diff line Loading @@ -50,6 +50,7 @@ import android.util.SparseIntArray; import android.util.SparseLongArray; import android.util.SparseLongArray; import android.util.TypedValue; import android.util.TypedValue; import android.view.Display; import android.view.Display; import android.view.ViewConfiguration; import android.view.accessibility.MagnificationAnimationCallback; import android.view.accessibility.MagnificationAnimationCallback; import com.android.internal.accessibility.util.AccessibilityStatsLogUtils; import com.android.internal.accessibility.util.AccessibilityStatsLogUtils; Loading Loading @@ -122,9 +123,8 @@ public class MagnificationController implements MagnificationConnectionManager.C private @ZoomDirection int mActiveZoomDirection = ZOOM_DIRECTION_IN; private @ZoomDirection int mActiveZoomDirection = ZOOM_DIRECTION_IN; private int mActiveZoomDisplay = Display.INVALID_DISPLAY; private int mActiveZoomDisplay = Display.INVALID_DISPLAY; // TODO(b/355499907): Get initial repeat interval from repeat keys settings. private int mInitialKeyboardRepeatIntervalMs = @VisibleForTesting ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT; public static final int INITIAL_KEYBOARD_REPEAT_INTERVAL_MS = 500; @VisibleForTesting @VisibleForTesting public static final int KEYBOARD_REPEAT_INTERVAL_MS = 60; public static final int KEYBOARD_REPEAT_INTERVAL_MS = 60; Loading Loading @@ -321,12 +321,6 @@ public class MagnificationController implements MagnificationConnectionManager.C mAlwaysOnMagnificationFeatureFlag = new AlwaysOnMagnificationFeatureFlag(context); mAlwaysOnMagnificationFeatureFlag = new AlwaysOnMagnificationFeatureFlag(context); mAlwaysOnMagnificationFeatureFlag.addOnChangedListener( mAlwaysOnMagnificationFeatureFlag.addOnChangedListener( mBackgroundExecutor, mAms::updateAlwaysOnMagnification); 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 @VisibleForTesting Loading Loading @@ -383,7 +377,7 @@ public class MagnificationController implements MagnificationConnectionManager.C if (mRepeatKeysEnabled) { if (mRepeatKeysEnabled) { mHandler.sendMessageDelayed( mHandler.sendMessageDelayed( PooledLambda.obtainMessage(MagnificationController::maybeContinuePan, this), PooledLambda.obtainMessage(MagnificationController::maybeContinuePan, this), INITIAL_KEYBOARD_REPEAT_INTERVAL_MS); mInitialKeyboardRepeatIntervalMs); } } } } Loading @@ -404,7 +398,7 @@ public class MagnificationController implements MagnificationConnectionManager.C if (mRepeatKeysEnabled) { if (mRepeatKeysEnabled) { mHandler.sendMessageDelayed( mHandler.sendMessageDelayed( PooledLambda.obtainMessage(MagnificationController::maybeContinueZoom, this), PooledLambda.obtainMessage(MagnificationController::maybeContinueZoom, this), INITIAL_KEYBOARD_REPEAT_INTERVAL_MS); mInitialKeyboardRepeatIntervalMs); } } } } Loading Loading @@ -434,6 +428,19 @@ public class MagnificationController implements MagnificationConnectionManager.C } } } } public void setRepeatKeysEnabled(boolean isRepeatKeysEnabled) { mRepeatKeysEnabled = isRepeatKeysEnabled; } public void setRepeatKeysTimeoutMs(int repeatKeysTimeoutMs) { mInitialKeyboardRepeatIntervalMs = repeatKeysTimeoutMs; } @VisibleForTesting public int getInitialKeyboardRepeatIntervalMs() { return mInitialKeyboardRepeatIntervalMs; } private void handleUserInteractionChanged(int displayId, int mode) { private void handleUserInteractionChanged(int displayId, int mode) { if (mMagnificationCapabilities != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) { if (mMagnificationCapabilities != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) { return; return; Loading services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +28 −0 Original line number Original line Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; import static android.view.accessibility.Flags.FLAG_SKIP_ACCESSIBILITY_WARNING_DIALOG_FOR_TRUSTED_SERVICES; import static android.view.accessibility.Flags.FLAG_SKIP_ACCESSIBILITY_WARNING_DIALOG_FOR_TRUSTED_SERVICES; import static com.android.input.flags.Flags.FLAG_KEYBOARD_REPEAT_KEYS; import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE; Loading @@ -38,6 +39,7 @@ import static com.android.internal.accessibility.common.ShortcutConstants.UserSh import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE; import static com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity.EXTRA_TYPE_TO_CHOOSE; import static com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity.EXTRA_TYPE_TO_CHOOSE; import static com.android.server.accessibility.AccessibilityManagerService.ACTION_LAUNCH_HEARING_DEVICES_DIALOG; import static com.android.server.accessibility.AccessibilityManagerService.ACTION_LAUNCH_HEARING_DEVICES_DIALOG; import static com.android.server.accessibility.Flags.FLAG_ENABLE_MAGNIFICATION_KEYBOARD_CONTROL; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -93,6 +95,7 @@ import android.os.UserHandle; import android.os.test.FakePermissionEnforcer; import android.os.test.FakePermissionEnforcer; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.SetFlagsRule; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.provider.Settings; import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner; Loading Loading @@ -583,6 +586,31 @@ public class AccessibilityManagerServiceTest { verify(mMockMagnificationController).setMagnificationFollowTypingEnabled(false); verify(mMockMagnificationController).setMagnificationFollowTypingEnabled(false); } } @Test @RequiresFlagsEnabled({FLAG_ENABLE_MAGNIFICATION_KEYBOARD_CONTROL, FLAG_KEYBOARD_REPEAT_KEYS}) public void testRepeatKeysSettingsChanges_propagateToMagnificationController() { final AccessibilityUserState userState = mA11yms.mUserStates.get( mA11yms.getCurrentUserIdLocked()); Settings.Secure.putIntForUser( mTestableContext.getContentResolver(), Settings.Secure.KEY_REPEAT_ENABLED, 0, mA11yms.getCurrentUserIdLocked()); mA11yms.readRepeatKeysSettingsLocked(userState); verify(mMockMagnificationController).setRepeatKeysEnabled(false); final int timeoutMs = 42; Settings.Secure.putIntForUser( mTestableContext.getContentResolver(), Settings.Secure.KEY_REPEAT_TIMEOUT_MS, timeoutMs, mA11yms.getCurrentUserIdLocked()); mA11yms.readRepeatKeysSettingsLocked(userState); verify(mMockMagnificationController).setRepeatKeysTimeoutMs(timeoutMs); } @Test @Test public void testSettingsAlwaysOn_setEnabled_featureFlagDisabled_doNothing() { public void testSettingsAlwaysOn_setEnabled_featureFlagDisabled_doNothing() { when(mMockMagnificationController.isAlwaysOnMagnificationFeatureFlagEnabled()) when(mMockMagnificationController.isAlwaysOnMagnificationFeatureFlagEnabled()) Loading services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java +182 −37 Original line number Original line Diff line number Diff line Loading @@ -885,66 +885,142 @@ public class MagnificationControllerTest { } } @Test @Test public void magnificationCallbacks_panMagnificationContinuous() throws RemoteException { public void magnificationCallbacks_scaleMagnificationContinuous() throws RemoteException { setMagnificationEnabled(MODE_FULLSCREEN); setMagnificationEnabled(MODE_FULLSCREEN); mMagnificationController.onPerformScaleAction(TEST_DISPLAY, 8.0f, false); float currentScale = 2.0f; mMagnificationController.onPerformScaleAction(TEST_DISPLAY, currentScale, false); reset(mScreenMagnificationController); reset(mScreenMagnificationController); DisplayMetrics metrics = new DisplayMetrics(); mDisplay.getMetrics(metrics); float expectedStep = 27 * metrics.density; float currentCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float currentCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float currentCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); float currentCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); // Start moving right using keyboard callbacks. // Start zooming in using keyboard callbacks. mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, mMagnificationController.onScaleMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_RIGHT); MagnificationController.ZOOM_DIRECTION_IN); // The center is unchanged. float newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); float newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(currentCenterX).isLessThan(newCenterX); expect.that(currentCenterX).isWithin(1.0f).of(newCenterX); expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); expect.that(currentCenterY).isEqualTo(newCenterY); expect.that(currentCenterY).isEqualTo(newCenterY); currentCenterX = newCenterX; // The scale is increased. currentCenterY = newCenterY; float newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); expect.that(currentScale).isLessThan(newScale); currentScale = newScale; // Wait for the initial delay to occur. // Wait for the initial delay to occur. advanceTime(MagnificationController.INITIAL_KEYBOARD_REPEAT_INTERVAL_MS + 1); advanceTime(mMagnificationController.getInitialKeyboardRepeatIntervalMs() + 1); // It should have moved again after the handler was triggered. // It should have scaled again after the handler was triggered. newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(currentScale).isLessThan(newScale); expect.that(currentCenterX).isLessThan(newCenterX); currentScale = newScale; expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); expect.that(currentCenterY).isEqualTo(newCenterY); currentCenterX = newCenterX; currentCenterY = newCenterY; for (int i = 0; i < 3; i++) { // Wait for repeat delay to occur. // Wait for repeat delay to occur. advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); // It should have moved a third time. // It should have scaled another time. newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); expect.that(currentScale).isLessThan(newScale); currentScale = newScale; } // Stop magnification scale. mMagnificationController.onScaleMagnificationStop(TEST_DISPLAY, MagnificationController.ZOOM_DIRECTION_IN); // It should not scale again, even after the appropriate delay. advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); expect.that(currentScale).isEqualTo(newScale); } @Test public void magnificationCallbacks_panMagnificationContinuous_repeatKeysTimeout200() throws RemoteException { // Shorter than default. testMagnificationContinuousPanningWithTimeout(200); } @Test public void magnificationCallbacks_panMagnificationContinuous_repeatKeysTimeout1000() throws RemoteException { // Longer than default. testMagnificationContinuousPanningWithTimeout(1000); } @Test public void magnificationCallbacks_panMagnification_notContinuousWithRepeatKeysDisabled() throws RemoteException { mMagnificationController.setRepeatKeysEnabled(false); setMagnificationEnabled(MODE_FULLSCREEN); mMagnificationController.onPerformScaleAction(TEST_DISPLAY, 4.0f, false); reset(mScreenMagnificationController); float currentCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float currentCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); // Start moving down using keyboard callbacks. mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_DOWN); float newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(currentCenterY).isLessThan(newCenterY); expect.that(currentCenterX).isEqualTo(newCenterX); currentCenterX = newCenterX; currentCenterY = newCenterY; for (int i = 0; i < 3; i++) { // Wait for the initial delay to occur. advanceTime(mMagnificationController.getInitialKeyboardRepeatIntervalMs() + 1); // It should not have moved again because repeat keys is disabled. newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(currentCenterX).isLessThan(newCenterX); expect.that(currentCenterX).isEqualTo(newCenterX); expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); expect.that(currentCenterY).isEqualTo(newCenterY); expect.that(currentCenterY).isEqualTo(newCenterY); currentCenterX = newCenterX; currentCenterX = newCenterX; currentCenterY = newCenterY; currentCenterY = newCenterY; } // Stop magnification pan. mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_RIGHT); MagnificationController.PAN_DIRECTION_DOWN); } // It should not move again, even after the appropriate delay. @Test advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); public void magnificationCallbacks_scaleMagnification_notContinuousWithRepeatKeysDisabled() throws RemoteException { mMagnificationController.setRepeatKeysEnabled(false); setMagnificationEnabled(MODE_FULLSCREEN); float currentScale = 8.0f; mMagnificationController.onPerformScaleAction(TEST_DISPLAY, currentScale, false); reset(mScreenMagnificationController); newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); // Start scaling out using keyboard callbacks. newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); mMagnificationController.onScaleMagnificationStart(TEST_DISPLAY, expect.that(newCenterX).isEqualTo(currentCenterX); MagnificationController.ZOOM_DIRECTION_OUT); expect.that(newCenterY).isEqualTo(currentCenterY); float newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); expect.that(currentScale).isGreaterThan(newScale); currentScale = newScale; for (int i = 0; i < 3; i++) { // Wait for the initial delay to occur. advanceTime(mMagnificationController.getInitialKeyboardRepeatIntervalMs() + 1); // It should not have scaled again because repeat keys is disabled. newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); expect.that(currentScale).isEqualTo(newScale); } mMagnificationController.onScaleMagnificationStop(TEST_DISPLAY, MagnificationController.ZOOM_DIRECTION_OUT); } } @Test @Test Loading Loading @@ -1736,6 +1812,75 @@ public class MagnificationControllerTest { MagnificationController.PAN_DIRECTION_UP); MagnificationController.PAN_DIRECTION_UP); } } private void testMagnificationContinuousPanningWithTimeout(int timeoutMs) throws RemoteException { mMagnificationController.setRepeatKeysTimeoutMs(timeoutMs); expect.that(timeoutMs).isEqualTo( mMagnificationController.getInitialKeyboardRepeatIntervalMs()); 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(timeoutMs + 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; for (int i = 0; i < 3; i++) { // Wait for repeat delay to occur. advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); // It should have moved another 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); } private void advanceTime(long timeMs) { private void advanceTime(long timeMs) { mTestLooper.moveTimeForward(timeMs); mTestLooper.moveTimeForward(timeMs); mTestLooper.dispatchAll(); mTestLooper.dispatchAll(); Loading Loading
services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +36 −0 Original line number Original line Diff line number Diff line Loading @@ -36,6 +36,7 @@ import static android.accessibilityservice.AccessibilityTrace.FLAGS_PACKAGE_BROA import static android.accessibilityservice.AccessibilityTrace.FLAGS_USER_BROADCAST_RECEIVER; import static android.accessibilityservice.AccessibilityTrace.FLAGS_USER_BROADCAST_RECEIVER; import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL; import static android.accessibilityservice.AccessibilityTrace.FLAGS_WINDOW_MANAGER_INTERNAL; import static android.content.Context.DEVICE_ID_DEFAULT; import static android.content.Context.DEVICE_ID_DEFAULT; import static android.hardware.input.InputSettings.isRepeatKeysFeatureFlagEnabled; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_GESTURE; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR; Loading Loading @@ -156,6 +157,7 @@ import android.view.KeyEvent; import android.view.MagnificationSpec; import android.view.MagnificationSpec; import android.view.MotionEvent; import android.view.MotionEvent; import android.view.SurfaceControl; import android.view.SurfaceControl; import android.view.ViewConfiguration; import android.view.WindowInfo; import android.view.WindowInfo; import android.view.WindowManager; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityEvent; Loading Loading @@ -3494,6 +3496,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub somethingChanged |= readMagnificationFollowTypingLocked(userState); somethingChanged |= readMagnificationFollowTypingLocked(userState); somethingChanged |= readAlwaysOnMagnificationLocked(userState); somethingChanged |= readAlwaysOnMagnificationLocked(userState); somethingChanged |= readMouseKeysEnabledLocked(userState); somethingChanged |= readMouseKeysEnabledLocked(userState); somethingChanged |= readRepeatKeysSettingsLocked(userState); return somethingChanged; return somethingChanged; } } Loading Loading @@ -5771,6 +5774,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final Uri mUserSetupCompleteUri = Settings.Secure.getUriFor( private final Uri mUserSetupCompleteUri = Settings.Secure.getUriFor( Settings.Secure.USER_SETUP_COMPLETE); Settings.Secure.USER_SETUP_COMPLETE); private final Uri mRepeatKeysEnabledUri = Settings.Secure.getUriFor( Settings.Secure.KEY_REPEAT_ENABLED); private final Uri mRepeatKeysTimeoutMsUri = Settings.Secure.getUriFor( Settings.Secure.KEY_REPEAT_TIMEOUT_MS); public AccessibilityContentObserver(Handler handler) { public AccessibilityContentObserver(Handler handler) { super(handler); super(handler); } } Loading Loading @@ -5827,6 +5836,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mNavigationModeUri, false, this, UserHandle.USER_ALL); mNavigationModeUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( contentResolver.registerContentObserver( mUserSetupCompleteUri, false, this, UserHandle.USER_ALL); mUserSetupCompleteUri, false, this, UserHandle.USER_ALL); if (isRepeatKeysFeatureFlagEnabled() && Flags.enableMagnificationKeyboardControl()) { contentResolver.registerContentObserver( mRepeatKeysEnabledUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mRepeatKeysTimeoutMsUri, false, this, UserHandle.USER_ALL); } } } @Override @Override Loading Loading @@ -5917,6 +5932,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } } else if (mNavigationModeUri.equals(uri) || mUserSetupCompleteUri.equals(uri)) { } else if (mNavigationModeUri.equals(uri) || mUserSetupCompleteUri.equals(uri)) { updateShortcutsForCurrentNavigationMode(); updateShortcutsForCurrentNavigationMode(); } else if (mRepeatKeysEnabledUri.equals(uri) || mRepeatKeysTimeoutMsUri.equals(uri)) { readRepeatKeysSettingsLocked(userState); } } } } } } Loading Loading @@ -6055,6 +6073,24 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return false; return false; } } boolean readRepeatKeysSettingsLocked(AccessibilityUserState userState) { if (!isRepeatKeysFeatureFlagEnabled() || !Flags.enableMagnificationKeyboardControl()) { return false; } final boolean isRepeatKeysEnabled = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.KEY_REPEAT_ENABLED, 1, userState.mUserId) == 1; final int repeatKeysTimeoutMs = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.KEY_REPEAT_TIMEOUT_MS, ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT, userState.mUserId); mMagnificationController.setRepeatKeysEnabled(isRepeatKeysEnabled); mMagnificationController.setRepeatKeysTimeoutMs(repeatKeysTimeoutMs); // No need to update any other state, so always return false. return false; } boolean readMouseKeysEnabledLocked(AccessibilityUserState userState) { boolean readMouseKeysEnabledLocked(AccessibilityUserState userState) { if (!keyboardA11yMouseKeys()) { if (!keyboardA11yMouseKeys()) { return false; return false; Loading
services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java +18 −11 Original line number Original line Diff line number Diff line Loading @@ -50,6 +50,7 @@ import android.util.SparseIntArray; import android.util.SparseLongArray; import android.util.SparseLongArray; import android.util.TypedValue; import android.util.TypedValue; import android.view.Display; import android.view.Display; import android.view.ViewConfiguration; import android.view.accessibility.MagnificationAnimationCallback; import android.view.accessibility.MagnificationAnimationCallback; import com.android.internal.accessibility.util.AccessibilityStatsLogUtils; import com.android.internal.accessibility.util.AccessibilityStatsLogUtils; Loading Loading @@ -122,9 +123,8 @@ public class MagnificationController implements MagnificationConnectionManager.C private @ZoomDirection int mActiveZoomDirection = ZOOM_DIRECTION_IN; private @ZoomDirection int mActiveZoomDirection = ZOOM_DIRECTION_IN; private int mActiveZoomDisplay = Display.INVALID_DISPLAY; private int mActiveZoomDisplay = Display.INVALID_DISPLAY; // TODO(b/355499907): Get initial repeat interval from repeat keys settings. private int mInitialKeyboardRepeatIntervalMs = @VisibleForTesting ViewConfiguration.DEFAULT_LONG_PRESS_TIMEOUT; public static final int INITIAL_KEYBOARD_REPEAT_INTERVAL_MS = 500; @VisibleForTesting @VisibleForTesting public static final int KEYBOARD_REPEAT_INTERVAL_MS = 60; public static final int KEYBOARD_REPEAT_INTERVAL_MS = 60; Loading Loading @@ -321,12 +321,6 @@ public class MagnificationController implements MagnificationConnectionManager.C mAlwaysOnMagnificationFeatureFlag = new AlwaysOnMagnificationFeatureFlag(context); mAlwaysOnMagnificationFeatureFlag = new AlwaysOnMagnificationFeatureFlag(context); mAlwaysOnMagnificationFeatureFlag.addOnChangedListener( mAlwaysOnMagnificationFeatureFlag.addOnChangedListener( mBackgroundExecutor, mAms::updateAlwaysOnMagnification); 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 @VisibleForTesting Loading Loading @@ -383,7 +377,7 @@ public class MagnificationController implements MagnificationConnectionManager.C if (mRepeatKeysEnabled) { if (mRepeatKeysEnabled) { mHandler.sendMessageDelayed( mHandler.sendMessageDelayed( PooledLambda.obtainMessage(MagnificationController::maybeContinuePan, this), PooledLambda.obtainMessage(MagnificationController::maybeContinuePan, this), INITIAL_KEYBOARD_REPEAT_INTERVAL_MS); mInitialKeyboardRepeatIntervalMs); } } } } Loading @@ -404,7 +398,7 @@ public class MagnificationController implements MagnificationConnectionManager.C if (mRepeatKeysEnabled) { if (mRepeatKeysEnabled) { mHandler.sendMessageDelayed( mHandler.sendMessageDelayed( PooledLambda.obtainMessage(MagnificationController::maybeContinueZoom, this), PooledLambda.obtainMessage(MagnificationController::maybeContinueZoom, this), INITIAL_KEYBOARD_REPEAT_INTERVAL_MS); mInitialKeyboardRepeatIntervalMs); } } } } Loading Loading @@ -434,6 +428,19 @@ public class MagnificationController implements MagnificationConnectionManager.C } } } } public void setRepeatKeysEnabled(boolean isRepeatKeysEnabled) { mRepeatKeysEnabled = isRepeatKeysEnabled; } public void setRepeatKeysTimeoutMs(int repeatKeysTimeoutMs) { mInitialKeyboardRepeatIntervalMs = repeatKeysTimeoutMs; } @VisibleForTesting public int getInitialKeyboardRepeatIntervalMs() { return mInitialKeyboardRepeatIntervalMs; } private void handleUserInteractionChanged(int displayId, int mode) { private void handleUserInteractionChanged(int displayId, int mode) { if (mMagnificationCapabilities != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) { if (mMagnificationCapabilities != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) { return; return; Loading
services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +28 −0 Original line number Original line Diff line number Diff line Loading @@ -29,6 +29,7 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; import static android.view.accessibility.Flags.FLAG_SKIP_ACCESSIBILITY_WARNING_DIALOG_FOR_TRUSTED_SERVICES; import static android.view.accessibility.Flags.FLAG_SKIP_ACCESSIBILITY_WARNING_DIALOG_FOR_TRUSTED_SERVICES; import static com.android.input.flags.Flags.FLAG_KEYBOARD_REPEAT_KEYS; import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.GESTURE; Loading @@ -38,6 +39,7 @@ import static com.android.internal.accessibility.common.ShortcutConstants.UserSh import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE; import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.SOFTWARE; import static com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity.EXTRA_TYPE_TO_CHOOSE; import static com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity.EXTRA_TYPE_TO_CHOOSE; import static com.android.server.accessibility.AccessibilityManagerService.ACTION_LAUNCH_HEARING_DEVICES_DIALOG; import static com.android.server.accessibility.AccessibilityManagerService.ACTION_LAUNCH_HEARING_DEVICES_DIALOG; import static com.android.server.accessibility.Flags.FLAG_ENABLE_MAGNIFICATION_KEYBOARD_CONTROL; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat; Loading Loading @@ -93,6 +95,7 @@ import android.os.UserHandle; import android.os.test.FakePermissionEnforcer; import android.os.test.FakePermissionEnforcer; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.SetFlagsRule; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import android.provider.Settings; import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner; Loading Loading @@ -583,6 +586,31 @@ public class AccessibilityManagerServiceTest { verify(mMockMagnificationController).setMagnificationFollowTypingEnabled(false); verify(mMockMagnificationController).setMagnificationFollowTypingEnabled(false); } } @Test @RequiresFlagsEnabled({FLAG_ENABLE_MAGNIFICATION_KEYBOARD_CONTROL, FLAG_KEYBOARD_REPEAT_KEYS}) public void testRepeatKeysSettingsChanges_propagateToMagnificationController() { final AccessibilityUserState userState = mA11yms.mUserStates.get( mA11yms.getCurrentUserIdLocked()); Settings.Secure.putIntForUser( mTestableContext.getContentResolver(), Settings.Secure.KEY_REPEAT_ENABLED, 0, mA11yms.getCurrentUserIdLocked()); mA11yms.readRepeatKeysSettingsLocked(userState); verify(mMockMagnificationController).setRepeatKeysEnabled(false); final int timeoutMs = 42; Settings.Secure.putIntForUser( mTestableContext.getContentResolver(), Settings.Secure.KEY_REPEAT_TIMEOUT_MS, timeoutMs, mA11yms.getCurrentUserIdLocked()); mA11yms.readRepeatKeysSettingsLocked(userState); verify(mMockMagnificationController).setRepeatKeysTimeoutMs(timeoutMs); } @Test @Test public void testSettingsAlwaysOn_setEnabled_featureFlagDisabled_doNothing() { public void testSettingsAlwaysOn_setEnabled_featureFlagDisabled_doNothing() { when(mMockMagnificationController.isAlwaysOnMagnificationFeatureFlagEnabled()) when(mMockMagnificationController.isAlwaysOnMagnificationFeatureFlagEnabled()) Loading
services/tests/servicestests/src/com/android/server/accessibility/magnification/MagnificationControllerTest.java +182 −37 Original line number Original line Diff line number Diff line Loading @@ -885,66 +885,142 @@ public class MagnificationControllerTest { } } @Test @Test public void magnificationCallbacks_panMagnificationContinuous() throws RemoteException { public void magnificationCallbacks_scaleMagnificationContinuous() throws RemoteException { setMagnificationEnabled(MODE_FULLSCREEN); setMagnificationEnabled(MODE_FULLSCREEN); mMagnificationController.onPerformScaleAction(TEST_DISPLAY, 8.0f, false); float currentScale = 2.0f; mMagnificationController.onPerformScaleAction(TEST_DISPLAY, currentScale, false); reset(mScreenMagnificationController); reset(mScreenMagnificationController); DisplayMetrics metrics = new DisplayMetrics(); mDisplay.getMetrics(metrics); float expectedStep = 27 * metrics.density; float currentCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float currentCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float currentCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); float currentCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); // Start moving right using keyboard callbacks. // Start zooming in using keyboard callbacks. mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, mMagnificationController.onScaleMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_RIGHT); MagnificationController.ZOOM_DIRECTION_IN); // The center is unchanged. float newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); float newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(currentCenterX).isLessThan(newCenterX); expect.that(currentCenterX).isWithin(1.0f).of(newCenterX); expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); expect.that(currentCenterY).isEqualTo(newCenterY); expect.that(currentCenterY).isEqualTo(newCenterY); currentCenterX = newCenterX; // The scale is increased. currentCenterY = newCenterY; float newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); expect.that(currentScale).isLessThan(newScale); currentScale = newScale; // Wait for the initial delay to occur. // Wait for the initial delay to occur. advanceTime(MagnificationController.INITIAL_KEYBOARD_REPEAT_INTERVAL_MS + 1); advanceTime(mMagnificationController.getInitialKeyboardRepeatIntervalMs() + 1); // It should have moved again after the handler was triggered. // It should have scaled again after the handler was triggered. newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(currentScale).isLessThan(newScale); expect.that(currentCenterX).isLessThan(newCenterX); currentScale = newScale; expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); expect.that(currentCenterY).isEqualTo(newCenterY); currentCenterX = newCenterX; currentCenterY = newCenterY; for (int i = 0; i < 3; i++) { // Wait for repeat delay to occur. // Wait for repeat delay to occur. advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); // It should have moved a third time. // It should have scaled another time. newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); expect.that(currentScale).isLessThan(newScale); currentScale = newScale; } // Stop magnification scale. mMagnificationController.onScaleMagnificationStop(TEST_DISPLAY, MagnificationController.ZOOM_DIRECTION_IN); // It should not scale again, even after the appropriate delay. advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); expect.that(currentScale).isEqualTo(newScale); } @Test public void magnificationCallbacks_panMagnificationContinuous_repeatKeysTimeout200() throws RemoteException { // Shorter than default. testMagnificationContinuousPanningWithTimeout(200); } @Test public void magnificationCallbacks_panMagnificationContinuous_repeatKeysTimeout1000() throws RemoteException { // Longer than default. testMagnificationContinuousPanningWithTimeout(1000); } @Test public void magnificationCallbacks_panMagnification_notContinuousWithRepeatKeysDisabled() throws RemoteException { mMagnificationController.setRepeatKeysEnabled(false); setMagnificationEnabled(MODE_FULLSCREEN); mMagnificationController.onPerformScaleAction(TEST_DISPLAY, 4.0f, false); reset(mScreenMagnificationController); float currentCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float currentCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); // Start moving down using keyboard callbacks. mMagnificationController.onPanMagnificationStart(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_DOWN); float newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); float newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(currentCenterY).isLessThan(newCenterY); expect.that(currentCenterX).isEqualTo(newCenterX); currentCenterX = newCenterX; currentCenterY = newCenterY; for (int i = 0; i < 3; i++) { // Wait for the initial delay to occur. advanceTime(mMagnificationController.getInitialKeyboardRepeatIntervalMs() + 1); // It should not have moved again because repeat keys is disabled. newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); expect.that(currentCenterX).isLessThan(newCenterX); expect.that(currentCenterX).isEqualTo(newCenterX); expect.that(newCenterX - currentCenterX).isWithin(0.01f).of(expectedStep); expect.that(currentCenterY).isEqualTo(newCenterY); expect.that(currentCenterY).isEqualTo(newCenterY); currentCenterX = newCenterX; currentCenterX = newCenterX; currentCenterY = newCenterY; currentCenterY = newCenterY; } // Stop magnification pan. mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, mMagnificationController.onPanMagnificationStop(TEST_DISPLAY, MagnificationController.PAN_DIRECTION_RIGHT); MagnificationController.PAN_DIRECTION_DOWN); } // It should not move again, even after the appropriate delay. @Test advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); public void magnificationCallbacks_scaleMagnification_notContinuousWithRepeatKeysDisabled() throws RemoteException { mMagnificationController.setRepeatKeysEnabled(false); setMagnificationEnabled(MODE_FULLSCREEN); float currentScale = 8.0f; mMagnificationController.onPerformScaleAction(TEST_DISPLAY, currentScale, false); reset(mScreenMagnificationController); newCenterX = mScreenMagnificationController.getCenterX(TEST_DISPLAY); // Start scaling out using keyboard callbacks. newCenterY = mScreenMagnificationController.getCenterY(TEST_DISPLAY); mMagnificationController.onScaleMagnificationStart(TEST_DISPLAY, expect.that(newCenterX).isEqualTo(currentCenterX); MagnificationController.ZOOM_DIRECTION_OUT); expect.that(newCenterY).isEqualTo(currentCenterY); float newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); expect.that(currentScale).isGreaterThan(newScale); currentScale = newScale; for (int i = 0; i < 3; i++) { // Wait for the initial delay to occur. advanceTime(mMagnificationController.getInitialKeyboardRepeatIntervalMs() + 1); // It should not have scaled again because repeat keys is disabled. newScale = mScreenMagnificationController.getScale(TEST_DISPLAY); expect.that(currentScale).isEqualTo(newScale); } mMagnificationController.onScaleMagnificationStop(TEST_DISPLAY, MagnificationController.ZOOM_DIRECTION_OUT); } } @Test @Test Loading Loading @@ -1736,6 +1812,75 @@ public class MagnificationControllerTest { MagnificationController.PAN_DIRECTION_UP); MagnificationController.PAN_DIRECTION_UP); } } private void testMagnificationContinuousPanningWithTimeout(int timeoutMs) throws RemoteException { mMagnificationController.setRepeatKeysTimeoutMs(timeoutMs); expect.that(timeoutMs).isEqualTo( mMagnificationController.getInitialKeyboardRepeatIntervalMs()); 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(timeoutMs + 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; for (int i = 0; i < 3; i++) { // Wait for repeat delay to occur. advanceTime(MagnificationController.KEYBOARD_REPEAT_INTERVAL_MS + 1); // It should have moved another 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); } private void advanceTime(long timeMs) { private void advanceTime(long timeMs) { mTestLooper.moveTimeForward(timeMs); mTestLooper.moveTimeForward(timeMs); mTestLooper.dispatchAll(); mTestLooper.dispatchAll(); Loading