Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4df1a964 authored by David Padlipsky's avatar David Padlipsky Committed by Android (Google) Code Review
Browse files

Merge "Implement magnification scale control shortcuts" into main

parents 8a7945fa 248654d8
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -117,6 +117,8 @@ public final class KeyGestureEvent {
    public static final int KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW = 69;
    public static final int KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW = 70;
    public static final int KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE = 71;
    public static final int KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN = 72;
    public static final int KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT = 73;

    public static final int FLAG_CANCELLED = 1;

@@ -203,6 +205,8 @@ public final class KeyGestureEvent {
            KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW,
            KEY_GESTURE_TYPE_MAXIMIZE_FREEFORM_WINDOW,
            KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE,
            KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN,
            KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface KeyGestureType {
@@ -773,6 +777,10 @@ public final class KeyGestureEvent {
                return "KEY_GESTURE_TYPE_SNAP_RIGHT_FREEFORM_WINDOW";
            case KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE:
                return "KEY_GESTURE_TYPE_RESTORE_FREEFORM_WINDOW_SIZE";
            case KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN:
                return "KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN";
            case KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT:
                return "KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT";
            default:
                return Integer.toHexString(value);
        }
+60 −0
Original line number Diff line number Diff line
@@ -27,6 +27,8 @@ import android.annotation.NonNull;
import android.content.Context;
import android.graphics.Region;
import android.hardware.input.InputManager;
import android.hardware.input.KeyGestureEvent;
import android.os.IBinder;
import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemClock;
@@ -44,11 +46,14 @@ import android.view.MotionEvent.PointerCoords;
import android.view.MotionEvent.PointerProperties;
import android.view.accessibility.AccessibilityEvent;

import androidx.annotation.Nullable;

import com.android.server.LocalServices;
import com.android.server.accessibility.gestures.TouchExplorer;
import com.android.server.accessibility.magnification.FullScreenMagnificationController;
import com.android.server.accessibility.magnification.FullScreenMagnificationGestureHandler;
import com.android.server.accessibility.magnification.FullScreenMagnificationVibrationHelper;
import com.android.server.accessibility.magnification.MagnificationController;
import com.android.server.accessibility.magnification.MagnificationGestureHandler;
import com.android.server.accessibility.magnification.MouseEventHandler;
import com.android.server.accessibility.magnification.WindowMagnificationGestureHandler;
@@ -187,6 +192,8 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo

    private final AccessibilityManagerService mAms;

    private final InputManager mInputManager;

    private final SparseArray<EventStreamTransformation> mEventHandler;

    private final SparseArray<TouchExplorer> mTouchExplorer = new SparseArray<>(0);
@@ -228,6 +235,47 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
     */
    private MotionEvent mLastActiveDeviceMotionEvent = null;

    private boolean mKeyGestureEventHandlerInstalled = false;
    private InputManager.KeyGestureEventHandler mKeyGestureEventHandler =
            new InputManager.KeyGestureEventHandler() {
                @Override
                public boolean handleKeyGestureEvent(
                        @NonNull KeyGestureEvent event,
                        @Nullable IBinder focusedToken) {
                    final boolean complete =
                            event.getAction() == KeyGestureEvent.ACTION_GESTURE_COMPLETE
                                    && !event.isCancelled();
                    final int gestureType = event.getKeyGestureType();
                    final int displayId = isDisplayIdValid(event.getDisplayId())
                            ? event.getDisplayId() : Display.DEFAULT_DISPLAY;

                    switch (gestureType) {
                        case KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN:
                            if (complete) {
                                mAms.getMagnificationController().scaleMagnificationByStep(
                                        displayId, MagnificationController.ZOOM_DIRECTION_IN);
                            }
                            return true;
                        case KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT:
                            if (complete) {
                                mAms.getMagnificationController().scaleMagnificationByStep(
                                        displayId, MagnificationController.ZOOM_DIRECTION_OUT);
                            }
                            return true;
                    }
                    return false;
                }

                @Override
                public boolean isKeyGestureSupported(int gestureType) {
                    return switch (gestureType) {
                        case KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN,
                             KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT -> true;
                        default -> false;
                    };
                }
            };

    private static MotionEvent cancelMotion(MotionEvent event) {
        if (event.getActionMasked() == MotionEvent.ACTION_CANCEL
                || event.getActionMasked() == MotionEvent.ACTION_HOVER_EXIT
@@ -287,6 +335,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
        mContext = context;
        mAms = service;
        mPm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mInputManager = context.getSystemService(InputManager.class);
        mEventHandler = eventHandler;
    }

@@ -723,6 +772,12 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
                    createMagnificationGestureHandler(displayId, displayContext);
            addFirstEventHandler(displayId, magnificationGestureHandler);
            mMagnificationGestureHandler.put(displayId, magnificationGestureHandler);

            if (com.android.hardware.input.Flags.enableTalkbackAndMagnifierKeyGestures()
                    && !mKeyGestureEventHandlerInstalled) {
                mInputManager.registerKeyGestureEventHandler(mKeyGestureEventHandler);
                mKeyGestureEventHandlerInstalled = true;
            }
        }

        if ((mEnabledFeatures & FLAG_FEATURE_INJECT_MOTION_EVENTS) != 0) {
@@ -842,6 +897,11 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
            mMouseKeysInterceptor.onDestroy();
            mMouseKeysInterceptor = null;
        }

        if (mKeyGestureEventHandlerInstalled) {
            mInputManager.unregisterKeyGestureEventHandler(mKeyGestureEventHandler);
            mKeyGestureEventHandlerInstalled = false;
        }
    }

    private MagnificationGestureHandler createMagnificationGestureHandler(
+77 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_
import static com.android.server.accessibility.AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID;

import android.accessibilityservice.MagnificationConfig;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -101,6 +102,7 @@ public class MagnificationController implements MagnificationConnectionManager.C
    private int mMagnificationCapabilities = ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
    /** Whether the platform supports window magnification feature. */
    private final boolean mSupportWindowMagnification;
    private final MagnificationScaleStepProvider mScaleStepProvider;

    private final Executor mBackgroundExecutor;

@@ -131,6 +133,14 @@ public class MagnificationController implements MagnificationConnectionManager.C
            .UiChangesForAccessibilityCallbacks> mAccessibilityCallbacksDelegateArray =
            new SparseArray<>();

    // Direction magnifier scale can be altered.
    public static final int ZOOM_DIRECTION_IN = 0;
    public static final int ZOOM_DIRECTION_OUT = 1;

    @IntDef({ZOOM_DIRECTION_IN, ZOOM_DIRECTION_OUT})
    public @interface ZoomDirection {
    }

    /**
     * A callback to inform the magnification transition result on the given display.
     */
@@ -144,6 +154,41 @@ public class MagnificationController implements MagnificationConnectionManager.C
        void onResult(int displayId, boolean success);
    }


    /**
     * An interface to configure how much the magnification scale should be affected when moving in
     * steps.
     */
    public interface MagnificationScaleStepProvider {
        /**
         * Calculate the next value given which direction (in/out) to adjust the magnification
         * scale.
         *
         * @param currentScale The current magnification scale value.
         * @param direction    Whether to zoom in or out.
         * @return The next scale value.
         */
        float nextScaleStep(float currentScale, @ZoomDirection int direction);
    }

    public static class DefaultMagnificationScaleStepProvider implements
            MagnificationScaleStepProvider {
        // Factor of magnification scale. For example, when this value is 1.189, scale
        // value will be changed x1.000, x1.189, x1.414, x1.681, x2.000, ...
        // Note: this value is 2.0 ^ (1 / 4).
        public static final float ZOOM_STEP_SCALE_FACTOR = 1.18920712f;

        @Override
        public float nextScaleStep(float currentScale, @ZoomDirection int direction) {
            final int stepDelta = direction == ZOOM_DIRECTION_IN ? 1 : -1;
            final long scaleIndex = Math.round(
                    Math.log(currentScale) / Math.log(ZOOM_STEP_SCALE_FACTOR));
            final float nextScale = (float) Math.pow(ZOOM_STEP_SCALE_FACTOR,
                    scaleIndex + stepDelta);
            return MagnificationScaleProvider.constrainScale(nextScale);
        }
    }

    public MagnificationController(AccessibilityManagerService ams, Object lock,
            Context context, MagnificationScaleProvider scaleProvider,
            Executor backgroundExecutor) {
@@ -156,6 +201,7 @@ public class MagnificationController implements MagnificationConnectionManager.C
                .getAccessibilityController().setUiChangesForAccessibilityCallbacks(this);
        mSupportWindowMagnification = context.getPackageManager().hasSystemFeature(
                FEATURE_WINDOW_MAGNIFICATION);
        mScaleStepProvider = new DefaultMagnificationScaleStepProvider();

        mAlwaysOnMagnificationFeatureFlag = new AlwaysOnMagnificationFeatureFlag(context);
        mAlwaysOnMagnificationFeatureFlag.addOnChangedListener(
@@ -891,6 +937,37 @@ public class MagnificationController implements MagnificationConnectionManager.C
        return isActivated;
    }

    /**
     * Scales the magnifier on the given display one step in/out based on the zoomIn param.
     *
     * @param displayId The logical display id.
     * @param direction Whether the scale should be zoomed in or out.
     * @return {@code true} if the magnification scale was affected.
     */
    public boolean scaleMagnificationByStep(int displayId, @ZoomDirection int direction) {
        if (getFullScreenMagnificationController().isActivated(displayId)) {
            final float magnificationScale = getFullScreenMagnificationController().getScale(
                    displayId);
            final float nextMagnificationScale = mScaleStepProvider.nextScaleStep(
                    magnificationScale, direction);
            getFullScreenMagnificationController().setScaleAndCenter(displayId,
                    nextMagnificationScale,
                    Float.NaN, Float.NaN, true, MAGNIFICATION_GESTURE_HANDLER_ID);
            return nextMagnificationScale != magnificationScale;
        }

        if (getMagnificationConnectionManager().isWindowMagnifierEnabled(displayId)) {
            final float magnificationScale = getMagnificationConnectionManager().getScale(
                    displayId);
            final float nextMagnificationScale = mScaleStepProvider.nextScaleStep(
                    magnificationScale, direction);
            getMagnificationConnectionManager().setScale(displayId, nextMagnificationScale);
            return nextMagnificationScale != magnificationScale;
        }

        return false;
    }

    private final class DisableMagnificationCallback implements
            MagnificationAnimationCallback {
        private final TransitionCallBack mTransitionCallBack;
+6 −0
Original line number Diff line number Diff line
@@ -215,6 +215,12 @@ final class InputGestureManager {
            systemShortcuts.add(createKeyGesture(KeyEvent.KEYCODE_T,
                    KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
                    KeyGestureEvent.KEY_GESTURE_TYPE_TOGGLE_TALKBACK));
            systemShortcuts.add(createKeyGesture(KeyEvent.KEYCODE_MINUS,
                    KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
                    KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_OUT));
            systemShortcuts.add(createKeyGesture(KeyEvent.KEYCODE_EQUALS,
                    KeyEvent.META_META_ON | KeyEvent.META_ALT_ON,
                    KeyGestureEvent.KEY_GESTURE_TYPE_MAGNIFIER_ZOOM_IN));
        }
        if (keyboardA11yShortcutControl()) {
            if (InputSettings.isAccessibilityBounceKeysFeatureEnabled()) {
+1 −0
Original line number Diff line number Diff line
@@ -114,6 +114,7 @@
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.CREATE_VIRTUAL_DEVICE" />
    <uses-permission android:name="android.permission.MANAGE_KEY_GESTURES" />

    <queries>
        <package android:name="com.android.servicestests.apps.suspendtestapp" />
Loading