Loading services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java +58 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; import android.hardware.input.InputManager; import android.hardware.input.InputSettings; import android.hardware.input.VirtualMouse; import android.hardware.input.VirtualMouseButtonEvent; import android.hardware.input.VirtualMouseConfig; Loading Loading @@ -111,6 +112,14 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation @VisibleForTesting public static final float MOUSE_SCROLL_STEP = 0.2f; /** * The parameter that converts the mouse keys max speed factor that ranges from 1 - 10 * to the actual float mouse pointer movement step. Assigning its value to 0.36f so * the DEFAULT_MOUSE_KEYS_MAX_SPEED matches the constant MOUSE_POINTER_MOVEMENT_STEP * when enableMouseKeyEnhancement flag is off. */ private static final float CURSOR_MOVEMENT_PARAMETER = 0.36f; private final AccessibilityManagerService mAms; private final Handler mHandler; Loading Loading @@ -160,10 +169,12 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation private int mActiveInputDeviceId = 0; /** The maximum movement step the mouse pointer can reach when accelerating. */ private float mMaxMovementStep = 10.0f; @VisibleForTesting float mMaxMovementStep = 10.0f; /** The acceleration factor applied to the mouse pointer's speed per interval. */ private float mAcceleration = 0.1f; @VisibleForTesting float mAcceleration = 0.1f; /** * The keycodes to which the mouse keys functionality will be bound to can be either Loading Loading @@ -903,6 +914,19 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation private final Uri mPrimaryKeysSettingUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_USE_PRIMARY_KEYS); /** * URI used to identify the max speed as a factor of the minimum speed for mouse * keys movement. */ private final Uri mMaxSpeedSettingsUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_MAX_SPEED); /** * URI used to identify the current acceleration value for mouse keys movement. */ private final Uri mAccelerationSettingsUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_ACCELERATION); private ContentResolver mContentResolver; private final int mUserId; Loading Loading @@ -936,6 +960,18 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation Slog.i(LOG_TAG, "Content resolver registered"); // Initialize mouse keys bindings onChange(/* selfChange= */ true, mPrimaryKeysSettingUri); contentResolver.registerContentObserver( mMaxSpeedSettingsUri, /* notifyForDescendants= */ false, /* observer= */ this, mUserId); onChange(/* selfChange= */ true, mMaxSpeedSettingsUri); contentResolver.registerContentObserver( mAccelerationSettingsUri, /* notifyForDescendants= */ false, /* observer= */ this, mUserId); onChange(/* selfChange= */ true, mAccelerationSettingsUri); } /** Loading Loading @@ -970,6 +1006,26 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation // for the device according to the key binding selected by user. mDeviceKeyCodeMap.clear(); } if (mMaxSpeedSettingsUri.equals(uri)) { mMaxMovementStep = Settings.Secure.getIntForUser( mContentResolver, Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_MAX_SPEED, InputSettings.DEFAULT_MOUSE_KEYS_MAX_SPEED, mUserId) * CURSOR_MOVEMENT_PARAMETER; Slog.i(LOG_TAG, "Mouse keys max speed updated. New value for max speed = " + mMaxMovementStep); } if (mAccelerationSettingsUri.equals(uri)) { mAcceleration = Settings.Secure.getFloatForUser( mContentResolver, Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_ACCELERATION, InputSettings.DEFAULT_MOUSE_KEYS_ACCELERATION, mUserId); Slog.i(LOG_TAG, "Mouse keys acceleration updated. New value for acceleration = " + mAcceleration); } } } } services/tests/servicestests/src/com/android/server/accessibility/MouseKeysInterceptorTest.kt +16 −20 Original line number Diff line number Diff line Loading @@ -77,13 +77,6 @@ class MouseKeysInterceptorTest { // when the handler processes the initial key down event, satisfying the required // time interval (MOVE_REPEAT_DELAY_MILLS). It should be >= MOVE_REPEAT_DELAY_MILLS. const val KEYBOARD_POST_EVENT_DELAY_MILLIS_FOR_MOUSE_POINTER = 30L // The maximum movement step, in pixels per interval, that the mouse pointer can reach when // FLAG_ENABLE_MOUSE_KEY_ENHANCEMENT is enabled. This directly corresponds to // `mMaxMovementStep` in the MouseKeysInterceptor. const val MAX_MOVEMENT_STEP = 10.0f // The acceleration factor applied to the mouse pointer's movement step per interval. // This directly corresponds to `mAcceleration` in the MouseKeysInterceptor. const val ACCELERATION = 0.1f // The initial movement step for the mouse pointer before acceleration begins. // This directly corresponds to `INITIAL_MOUSE_POINTER_MOVEMENT_STEP` in the // MouseKeysInterceptor. Loading Loading @@ -184,6 +177,10 @@ class MouseKeysInterceptorTest { val setting = if (usePrimaryKeys) 1 else 0 Settings.Secure.putIntForUser(testableContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_USE_PRIMARY_KEYS, setting, USER_ID) Settings.Secure.putIntForUser(testableContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_MAX_SPEED, 5, USER_ID) Settings.Secure.putFloatForUser(testableContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_ACCELERATION, 0.2f, USER_ID) mouseKeysInterceptor = MouseKeysInterceptor(mockAms, testableContext, testLooper.looper, DISPLAY_ID, testTimeSource, USER_ID) Loading Loading @@ -236,12 +233,11 @@ class MouseKeysInterceptorTest { USE_PRIMARY_KEYS) val downEvent = KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0, 0, DEVICE_ID, 0) val expectedStepValue = INITIAL_STEP_BEFORE_ACCEL * (1.0f + ACCELERATION) mouseKeysInterceptor.onKeyEvent(downEvent, 0) testLooper.dispatchAll() // Verify the sendRelativeEvent method is called once and capture the arguments val expectedStepValue = INITIAL_STEP_BEFORE_ACCEL * (1.0f + mouseKeysInterceptor.mAcceleration) verifyRelativeEvents(expectedX = floatArrayOf(-expectedStepValue / sqrt(2.0f)), expectedY = floatArrayOf(expectedStepValue / sqrt(2.0f))) } Loading Loading @@ -409,12 +405,11 @@ class MouseKeysInterceptorTest { USE_NUMPAD_KEYS) val downEvent = KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0, 0, DEVICE_ID, 0) val expectedStepValue = INITIAL_STEP_BEFORE_ACCEL * (1.0f + ACCELERATION) mouseKeysInterceptor.onKeyEvent(downEvent, 0) testLooper.dispatchAll() // Verify the sendRelativeEvent method is called once and capture the arguments val expectedStepValue = INITIAL_STEP_BEFORE_ACCEL * (1.0f + mouseKeysInterceptor.mAcceleration) verifyRelativeEvents(expectedX = floatArrayOf(0f), expectedY = floatArrayOf(-expectedStepValue)) } Loading @@ -429,12 +424,11 @@ class MouseKeysInterceptorTest { USE_PRIMARY_KEYS) val downEvent = KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0, 0, DEVICE_ID, 0) val expectedStepValue = INITIAL_STEP_BEFORE_ACCEL * (1.0f + ACCELERATION) mouseKeysInterceptor.onKeyEvent(downEvent, 0) testLooper.dispatchAll() // Verify the sendRelativeEvent method is called once and capture the arguments val expectedStepValue = INITIAL_STEP_BEFORE_ACCEL * (1.0f + mouseKeysInterceptor.mAcceleration) verifyRelativeEvents(expectedX = floatArrayOf(0f), expectedY = floatArrayOf(-expectedStepValue)) } Loading @@ -458,7 +452,8 @@ class MouseKeysInterceptorTest { // Update initial calculations currentMovementStepForExpectation = minOf( currentMovementStepForExpectation * (1 + ACCELERATION), MAX_MOVEMENT_STEP) currentMovementStepForExpectation * (1 + mouseKeysInterceptor.mAcceleration), mouseKeysInterceptor.mMaxMovementStep) expectedRelativeXs.add(0f) expectedRelativeYs.add(-currentMovementStepForExpectation) Loading @@ -468,7 +463,8 @@ class MouseKeysInterceptorTest { clock.fastForward(MOVE_REPEAT_DELAY_MILLS) testLooper.dispatchAll() currentMovementStepForExpectation = minOf( currentMovementStepForExpectation * (1 + ACCELERATION), MAX_MOVEMENT_STEP) currentMovementStepForExpectation * (1 + mouseKeysInterceptor.mAcceleration), mouseKeysInterceptor.mMaxMovementStep) expectedRelativeXs.add(0f) expectedRelativeYs.add(-currentMovementStepForExpectation) } Loading Loading @@ -516,12 +512,13 @@ class MouseKeysInterceptorTest { val allEvents = captor.allValues val lastCapturedEvent = allEvents.last() assertThat(lastCapturedEvent.relativeX).isEqualTo(MAX_MOVEMENT_STEP) assertThat(lastCapturedEvent.relativeX).isEqualTo(mouseKeysInterceptor.mMaxMovementStep) assertThat(lastCapturedEvent.relativeY).isEqualTo(0f) // Also check a few before last to ensure it was capped val thirdLastCapturedEvent = allEvents[allEvents.size - 3] assertThat(thirdLastCapturedEvent.relativeX).isEqualTo(MAX_MOVEMENT_STEP) assertThat(thirdLastCapturedEvent.relativeX).isEqualTo( mouseKeysInterceptor.mMaxMovementStep) assertThat(thirdLastCapturedEvent.relativeY).isEqualTo(0f) } Loading Loading @@ -564,8 +561,7 @@ class MouseKeysInterceptorTest { testLooper.dispatchAll() // Calculate expected first step for a new press val expectedFirstStepAfterReset = INITIAL_STEP_BEFORE_ACCEL * (1 + ACCELERATION) val expectedFirstStepAfterReset = INITIAL_STEP_BEFORE_ACCEL * (1 + mouseKeysInterceptor.mAcceleration) // Verify the sendRelativeEvent method is called once and capture the arguments verifyRelativeEvents(expectedX = floatArrayOf(0f), expectedY = floatArrayOf(expectedFirstStepAfterReset)) Loading @@ -584,7 +580,7 @@ class MouseKeysInterceptorTest { mouseKeysInterceptor.onKeyEvent(numpadKeyDownEvent, 0) testLooper.dispatchAll() val expectedStepValue = INITIAL_STEP_BEFORE_ACCEL * (1.0f + ACCELERATION) val expectedStepValue = INITIAL_STEP_BEFORE_ACCEL * (1.0f + mouseKeysInterceptor.mAcceleration) verifyRelativeEvents(expectedX = floatArrayOf(-expectedStepValue), expectedY = floatArrayOf(0f)) assertThat(nextInterceptor.events).isEmpty() Loading Loading
services/accessibility/java/com/android/server/accessibility/MouseKeysInterceptor.java +58 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; import android.hardware.input.InputManager; import android.hardware.input.InputSettings; import android.hardware.input.VirtualMouse; import android.hardware.input.VirtualMouseButtonEvent; import android.hardware.input.VirtualMouseConfig; Loading Loading @@ -111,6 +112,14 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation @VisibleForTesting public static final float MOUSE_SCROLL_STEP = 0.2f; /** * The parameter that converts the mouse keys max speed factor that ranges from 1 - 10 * to the actual float mouse pointer movement step. Assigning its value to 0.36f so * the DEFAULT_MOUSE_KEYS_MAX_SPEED matches the constant MOUSE_POINTER_MOVEMENT_STEP * when enableMouseKeyEnhancement flag is off. */ private static final float CURSOR_MOVEMENT_PARAMETER = 0.36f; private final AccessibilityManagerService mAms; private final Handler mHandler; Loading Loading @@ -160,10 +169,12 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation private int mActiveInputDeviceId = 0; /** The maximum movement step the mouse pointer can reach when accelerating. */ private float mMaxMovementStep = 10.0f; @VisibleForTesting float mMaxMovementStep = 10.0f; /** The acceleration factor applied to the mouse pointer's speed per interval. */ private float mAcceleration = 0.1f; @VisibleForTesting float mAcceleration = 0.1f; /** * The keycodes to which the mouse keys functionality will be bound to can be either Loading Loading @@ -903,6 +914,19 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation private final Uri mPrimaryKeysSettingUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_USE_PRIMARY_KEYS); /** * URI used to identify the max speed as a factor of the minimum speed for mouse * keys movement. */ private final Uri mMaxSpeedSettingsUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_MAX_SPEED); /** * URI used to identify the current acceleration value for mouse keys movement. */ private final Uri mAccelerationSettingsUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_ACCELERATION); private ContentResolver mContentResolver; private final int mUserId; Loading Loading @@ -936,6 +960,18 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation Slog.i(LOG_TAG, "Content resolver registered"); // Initialize mouse keys bindings onChange(/* selfChange= */ true, mPrimaryKeysSettingUri); contentResolver.registerContentObserver( mMaxSpeedSettingsUri, /* notifyForDescendants= */ false, /* observer= */ this, mUserId); onChange(/* selfChange= */ true, mMaxSpeedSettingsUri); contentResolver.registerContentObserver( mAccelerationSettingsUri, /* notifyForDescendants= */ false, /* observer= */ this, mUserId); onChange(/* selfChange= */ true, mAccelerationSettingsUri); } /** Loading Loading @@ -970,6 +1006,26 @@ public class MouseKeysInterceptor extends BaseEventStreamTransformation // for the device according to the key binding selected by user. mDeviceKeyCodeMap.clear(); } if (mMaxSpeedSettingsUri.equals(uri)) { mMaxMovementStep = Settings.Secure.getIntForUser( mContentResolver, Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_MAX_SPEED, InputSettings.DEFAULT_MOUSE_KEYS_MAX_SPEED, mUserId) * CURSOR_MOVEMENT_PARAMETER; Slog.i(LOG_TAG, "Mouse keys max speed updated. New value for max speed = " + mMaxMovementStep); } if (mAccelerationSettingsUri.equals(uri)) { mAcceleration = Settings.Secure.getFloatForUser( mContentResolver, Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_ACCELERATION, InputSettings.DEFAULT_MOUSE_KEYS_ACCELERATION, mUserId); Slog.i(LOG_TAG, "Mouse keys acceleration updated. New value for acceleration = " + mAcceleration); } } } }
services/tests/servicestests/src/com/android/server/accessibility/MouseKeysInterceptorTest.kt +16 −20 Original line number Diff line number Diff line Loading @@ -77,13 +77,6 @@ class MouseKeysInterceptorTest { // when the handler processes the initial key down event, satisfying the required // time interval (MOVE_REPEAT_DELAY_MILLS). It should be >= MOVE_REPEAT_DELAY_MILLS. const val KEYBOARD_POST_EVENT_DELAY_MILLIS_FOR_MOUSE_POINTER = 30L // The maximum movement step, in pixels per interval, that the mouse pointer can reach when // FLAG_ENABLE_MOUSE_KEY_ENHANCEMENT is enabled. This directly corresponds to // `mMaxMovementStep` in the MouseKeysInterceptor. const val MAX_MOVEMENT_STEP = 10.0f // The acceleration factor applied to the mouse pointer's movement step per interval. // This directly corresponds to `mAcceleration` in the MouseKeysInterceptor. const val ACCELERATION = 0.1f // The initial movement step for the mouse pointer before acceleration begins. // This directly corresponds to `INITIAL_MOUSE_POINTER_MOVEMENT_STEP` in the // MouseKeysInterceptor. Loading Loading @@ -184,6 +177,10 @@ class MouseKeysInterceptorTest { val setting = if (usePrimaryKeys) 1 else 0 Settings.Secure.putIntForUser(testableContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_USE_PRIMARY_KEYS, setting, USER_ID) Settings.Secure.putIntForUser(testableContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_MAX_SPEED, 5, USER_ID) Settings.Secure.putFloatForUser(testableContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_MOUSE_KEYS_ACCELERATION, 0.2f, USER_ID) mouseKeysInterceptor = MouseKeysInterceptor(mockAms, testableContext, testLooper.looper, DISPLAY_ID, testTimeSource, USER_ID) Loading Loading @@ -236,12 +233,11 @@ class MouseKeysInterceptorTest { USE_PRIMARY_KEYS) val downEvent = KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0, 0, DEVICE_ID, 0) val expectedStepValue = INITIAL_STEP_BEFORE_ACCEL * (1.0f + ACCELERATION) mouseKeysInterceptor.onKeyEvent(downEvent, 0) testLooper.dispatchAll() // Verify the sendRelativeEvent method is called once and capture the arguments val expectedStepValue = INITIAL_STEP_BEFORE_ACCEL * (1.0f + mouseKeysInterceptor.mAcceleration) verifyRelativeEvents(expectedX = floatArrayOf(-expectedStepValue / sqrt(2.0f)), expectedY = floatArrayOf(expectedStepValue / sqrt(2.0f))) } Loading Loading @@ -409,12 +405,11 @@ class MouseKeysInterceptorTest { USE_NUMPAD_KEYS) val downEvent = KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0, 0, DEVICE_ID, 0) val expectedStepValue = INITIAL_STEP_BEFORE_ACCEL * (1.0f + ACCELERATION) mouseKeysInterceptor.onKeyEvent(downEvent, 0) testLooper.dispatchAll() // Verify the sendRelativeEvent method is called once and capture the arguments val expectedStepValue = INITIAL_STEP_BEFORE_ACCEL * (1.0f + mouseKeysInterceptor.mAcceleration) verifyRelativeEvents(expectedX = floatArrayOf(0f), expectedY = floatArrayOf(-expectedStepValue)) } Loading @@ -429,12 +424,11 @@ class MouseKeysInterceptorTest { USE_PRIMARY_KEYS) val downEvent = KeyEvent(downTime, downTime, KeyEvent.ACTION_DOWN, keyCode, 0, 0, DEVICE_ID, 0) val expectedStepValue = INITIAL_STEP_BEFORE_ACCEL * (1.0f + ACCELERATION) mouseKeysInterceptor.onKeyEvent(downEvent, 0) testLooper.dispatchAll() // Verify the sendRelativeEvent method is called once and capture the arguments val expectedStepValue = INITIAL_STEP_BEFORE_ACCEL * (1.0f + mouseKeysInterceptor.mAcceleration) verifyRelativeEvents(expectedX = floatArrayOf(0f), expectedY = floatArrayOf(-expectedStepValue)) } Loading @@ -458,7 +452,8 @@ class MouseKeysInterceptorTest { // Update initial calculations currentMovementStepForExpectation = minOf( currentMovementStepForExpectation * (1 + ACCELERATION), MAX_MOVEMENT_STEP) currentMovementStepForExpectation * (1 + mouseKeysInterceptor.mAcceleration), mouseKeysInterceptor.mMaxMovementStep) expectedRelativeXs.add(0f) expectedRelativeYs.add(-currentMovementStepForExpectation) Loading @@ -468,7 +463,8 @@ class MouseKeysInterceptorTest { clock.fastForward(MOVE_REPEAT_DELAY_MILLS) testLooper.dispatchAll() currentMovementStepForExpectation = minOf( currentMovementStepForExpectation * (1 + ACCELERATION), MAX_MOVEMENT_STEP) currentMovementStepForExpectation * (1 + mouseKeysInterceptor.mAcceleration), mouseKeysInterceptor.mMaxMovementStep) expectedRelativeXs.add(0f) expectedRelativeYs.add(-currentMovementStepForExpectation) } Loading Loading @@ -516,12 +512,13 @@ class MouseKeysInterceptorTest { val allEvents = captor.allValues val lastCapturedEvent = allEvents.last() assertThat(lastCapturedEvent.relativeX).isEqualTo(MAX_MOVEMENT_STEP) assertThat(lastCapturedEvent.relativeX).isEqualTo(mouseKeysInterceptor.mMaxMovementStep) assertThat(lastCapturedEvent.relativeY).isEqualTo(0f) // Also check a few before last to ensure it was capped val thirdLastCapturedEvent = allEvents[allEvents.size - 3] assertThat(thirdLastCapturedEvent.relativeX).isEqualTo(MAX_MOVEMENT_STEP) assertThat(thirdLastCapturedEvent.relativeX).isEqualTo( mouseKeysInterceptor.mMaxMovementStep) assertThat(thirdLastCapturedEvent.relativeY).isEqualTo(0f) } Loading Loading @@ -564,8 +561,7 @@ class MouseKeysInterceptorTest { testLooper.dispatchAll() // Calculate expected first step for a new press val expectedFirstStepAfterReset = INITIAL_STEP_BEFORE_ACCEL * (1 + ACCELERATION) val expectedFirstStepAfterReset = INITIAL_STEP_BEFORE_ACCEL * (1 + mouseKeysInterceptor.mAcceleration) // Verify the sendRelativeEvent method is called once and capture the arguments verifyRelativeEvents(expectedX = floatArrayOf(0f), expectedY = floatArrayOf(expectedFirstStepAfterReset)) Loading @@ -584,7 +580,7 @@ class MouseKeysInterceptorTest { mouseKeysInterceptor.onKeyEvent(numpadKeyDownEvent, 0) testLooper.dispatchAll() val expectedStepValue = INITIAL_STEP_BEFORE_ACCEL * (1.0f + ACCELERATION) val expectedStepValue = INITIAL_STEP_BEFORE_ACCEL * (1.0f + mouseKeysInterceptor.mAcceleration) verifyRelativeEvents(expectedX = floatArrayOf(-expectedStepValue), expectedY = floatArrayOf(0f)) assertThat(nextInterceptor.events).isEmpty() Loading