diff options
author | 2025-02-05 19:45:58 +0900 | |
---|---|---|
committer | 2025-02-25 13:50:14 +0900 | |
commit | 872880ee3f2f1c95acf42e4a81cf6f4f79eb6de2 (patch) | |
tree | 5fd46c2640e2722772798be96f1cb14b6f3d54a4 /services/accessibility | |
parent | d833bce142f1970a1c30dc7a26edd33876edf21e (diff) |
Re-implement full screen magnification continuous cursor following
This migrates an existing full screen magnification's continuous cursor
following feature to use AccessibilityPointerMotionFilter so that other
types of cursor following features can be implemented similarly.
Bug: 361817142
Test: FullScreenMagnificationControllerTest
Test: FullScreenMagnificationGestureHandlerTest
Test: FullScreenMagnificationPointerMotionEventFilterTest
Flag: com.android.server.accessibility.enable_magnification_follows_mouse_with_pointer_motion_filter
Change-Id: I482c121cbc0d1da64e6d22aabcc3894caf89bb18
Diffstat (limited to 'services/accessibility')
4 files changed, 128 insertions, 6 deletions
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 9eb8442be783..327da84b0fce 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -287,7 +287,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub public static final int INVALID_SERVICE_ID = -1; - // Each service has an ID. Also provide one for magnification gesture handling + // Each service has an ID. Also provide one for magnification gesture handling. + // This ID is also used for mouse event handling. public static final int MAGNIFICATION_GESTURE_HANDLER_ID = 0; private static int sIdCounter = MAGNIFICATION_GESTURE_HANDLER_ID + 1; diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java index 11b8ccb70dfb..004b3ffcb02b 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java @@ -121,6 +121,8 @@ public class FullScreenMagnificationController implements @NonNull private final Supplier<MagnificationThumbnail> mThumbnailSupplier; @NonNull private final Supplier<Boolean> mMagnificationConnectionStateSupplier; + private boolean mIsPointerMotionFilterInstalled = false; + /** * This class implements {@link WindowManagerInternal.MagnificationCallbacks} and holds * magnification information per display. @@ -830,9 +832,17 @@ public class FullScreenMagnificationController implements return; } - final float nonNormOffsetX = mCurrentMagnificationSpec.offsetX - offsetX; - final float nonNormOffsetY = mCurrentMagnificationSpec.offsetY - offsetY; - if (updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY)) { + setOffset(mCurrentMagnificationSpec.offsetX - offsetX, + mCurrentMagnificationSpec.offsetY - offsetY, id); + } + + @GuardedBy("mLock") + void setOffset(float offsetX, float offsetY, int id) { + if (!mRegistered) { + return; + } + + if (updateCurrentSpecWithOffsetsLocked(offsetX, offsetY)) { onMagnificationChangedLocked(/* isScaleTransient= */ false); } if (id != INVALID_SERVICE_ID) { @@ -1065,6 +1075,7 @@ public class FullScreenMagnificationController implements if (display.register()) { mDisplays.put(displayId, display); mScreenStateObserver.registerIfNecessary(); + configurePointerMotionFilter(true); } } } @@ -1613,6 +1624,28 @@ public class FullScreenMagnificationController implements } /** + * Sets the offset of the magnified region. + * + * @param displayId The logical display id. + * @param offsetX the offset of the magnified region in the X coordinate, in current + * screen pixels. + * @param offsetY the offset of the magnified region in the Y coordinate, in current + * screen pixels. + * @param id the ID of the service requesting the change + */ + @SuppressWarnings("GuardedBy") + // errorprone cannot recognize an inner class guarded by an outer class member. + public void setOffset(int displayId, float offsetX, float offsetY, int id) { + synchronized (mLock) { + final DisplayMagnification display = mDisplays.get(displayId); + if (display == null) { + return; + } + display.setOffset(offsetX, offsetY, id); + } + } + + /** * Offsets the magnified region. Note that the offsetX and offsetY values actually move in the * opposite direction as the offsets passed in here. * @@ -1885,6 +1918,7 @@ public class FullScreenMagnificationController implements } if (!hasRegister) { mScreenStateObserver.unregister(); + configurePointerMotionFilter(false); } } @@ -1900,6 +1934,22 @@ public class FullScreenMagnificationController implements } } + private void configurePointerMotionFilter(boolean enabled) { + if (!Flags.enableMagnificationFollowsMouseWithPointerMotionFilter()) { + return; + } + if (enabled == mIsPointerMotionFilterInstalled) { + return; + } + if (!enabled) { + mControllerCtx.getInputManager().registerAccessibilityPointerMotionFilter(null); + } else { + mControllerCtx.getInputManager().registerAccessibilityPointerMotionFilter( + new FullScreenMagnificationPointerMotionEventFilter(this)); + } + mIsPointerMotionFilterInstalled = enabled; + } + private boolean traceEnabled() { return mControllerCtx.getTraceManager().isA11yTracingEnabledForTypes( FLAGS_WINDOW_MANAGER_INTERNAL); diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java index e0dd8b601a3d..59b4a1613e08 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java @@ -182,6 +182,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH private final int mMinimumVelocity; private final int mMaximumVelocity; + @Nullable private final MouseEventHandler mMouseEventHandler; public FullScreenMagnificationGestureHandler( @@ -313,7 +314,9 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH mOverscrollEdgeSlop = context.getResources().getDimensionPixelSize( R.dimen.accessibility_fullscreen_magnification_gesture_edge_slop); mIsWatch = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH); - mMouseEventHandler = new MouseEventHandler(mFullScreenMagnificationController); + mMouseEventHandler = + Flags.enableMagnificationFollowsMouseWithPointerMotionFilter() + ? null : new MouseEventHandler(mFullScreenMagnificationController); if (mDetectShortcutTrigger) { mScreenStateReceiver = new ScreenStateReceiver(context, this); @@ -337,9 +340,11 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH @Override void handleMouseOrStylusEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) { - if (!mFullScreenMagnificationController.isActivated(mDisplayId)) { + if (mMouseEventHandler == null + || !mFullScreenMagnificationController.isActivated(mDisplayId)) { return; } + // TODO(b/354696546): Allow mouse/stylus to activate whichever display they are // over, rather than only interacting with the current display. diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationPointerMotionEventFilter.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationPointerMotionEventFilter.java new file mode 100644 index 000000000000..f1ba83e80d54 --- /dev/null +++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationPointerMotionEventFilter.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.accessibility.magnification; + +import static com.android.server.accessibility.AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID; + +import android.annotation.NonNull; + +import com.android.server.input.InputManagerInternal; + +/** + * Handles pointer motion event for full screen magnification. + * Responsible for controlling magnification's cursor following feature. + */ +public class FullScreenMagnificationPointerMotionEventFilter implements + InputManagerInternal.AccessibilityPointerMotionFilter { + + private final FullScreenMagnificationController mController; + + public FullScreenMagnificationPointerMotionEventFilter( + FullScreenMagnificationController controller) { + mController = controller; + } + + /** + * This call happens on the input hot path and it is extremely performance sensitive. It + * also must not call back into native code. + */ + @Override + @NonNull + public float[] filterPointerMotionEvent(float dx, float dy, float currentX, float currentY, + int displayId) { + if (!mController.isActivated(displayId)) { + // unrelated display. + return new float[]{dx, dy}; + } + + // TODO(361817142): implement centered and edge following types. + + // Continuous cursor following. + float scale = mController.getScale(displayId); + final float newCursorX = currentX + dx; + final float newCursorY = currentY + dy; + mController.setOffset(displayId, + newCursorX - newCursorX * scale, newCursorY - newCursorY * scale, + MAGNIFICATION_GESTURE_HANDLER_ID); + + // In the continuous mode, the cursor speed in physical display is kept. + // Thus, we don't consume any motion delta. + return new float[]{dx, dy}; + } +} |