diff options
author | 2025-03-03 16:55:24 -0800 | |
---|---|---|
committer | 2025-03-03 16:55:24 -0800 | |
commit | cf191b8ca9cab234e0cf88496d60494e2cde99bf (patch) | |
tree | 8c3c917d08d0f61d1ecaaa02664bfffe2c68391a /services/accessibility | |
parent | 1eeb9667feb274722980ce1b750188dfb3981d89 (diff) | |
parent | 872880ee3f2f1c95acf42e4a81cf6f4f79eb6de2 (diff) |
Merge "Re-implement full screen magnification continuous cursor following" into main
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 42834ce20783..c49151dd5e30 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}; + } +} |