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

Commit 8b4519ed authored by Yongshun Liu's avatar Yongshun Liu Committed by Android (Google) Code Review
Browse files

Merge "a11y: Throttle motion events for magnification UI update" into main

parents df6b8da6 b30445a4
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -148,6 +148,16 @@ flag {
    bug: "322829049"
}

flag {
    name: "throttle_motion_events_for_ui_update"
    namespace: "accessibility"
    description: "Throttles motion events for requesting the System UI to update magnification UIs."
    bug: "435498747"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "touch_explorer_a11y_events_include_display_id"
    namespace: "accessibility"
+17 −13
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accessibility.Flags;
import com.android.server.wm.WindowManagerInternal;

import java.util.concurrent.Executor;
@@ -126,7 +127,7 @@ public class MagnificationController implements MagnificationConnectionManager.C
    // in multiple directions at once (for example, up + left), tracking last
    // panned time ensures that panning doesn't occur too frequently.
    private long mLastPannedTime = 0;
    private long mLastMouseMoveTriggeredUiChangeTime = 0;
    private long mLastMotionEventTriggeredUiChangeTime = 0;
    private boolean mRepeatKeysEnabled = true;

    private @ZoomDirection int mActiveZoomDirection = ZOOM_DIRECTION_IN;
@@ -388,25 +389,17 @@ public class MagnificationController implements MagnificationConnectionManager.C

    @Override
    public void onTouchInteractionStart(int displayId, int mode) {
        // TODO(435498747): Add throttling for touch similarly to mouse events.
        handleUserInteractionChanged(displayId, mode);
        handleUserInteractionChanged(displayId, mode, /* isMouse= */ false);
    }

    @Override
    public void onTouchInteractionEnd(int displayId, int mode) {
        // TODO(435498747): Add throttling for touch similarly to mouse events.
        handleUserInteractionChanged(displayId, mode);
        handleUserInteractionChanged(displayId, mode, /* isMouse= */ false);
    }

    @Override
    public void onMouseMove(int displayId, int mode) {
        final long currentTime = mSystemClock.uptimeMillis();
        if (currentTime - mLastMouseMoveTriggeredUiChangeTime
                < AccessibilityUtils.MAGNIFICATION_HANDLE_UI_CHANGE_INTERVAL_MS) {
            return;
        }
        mLastMouseMoveTriggeredUiChangeTime = currentTime;
        handleUserInteractionChanged(displayId, mode);
        handleUserInteractionChanged(displayId, mode, /* isMouse= */ true);
    }

    @Override
@@ -524,10 +517,21 @@ public class MagnificationController implements MagnificationConnectionManager.C
        return mInitialKeyboardRepeatIntervalMs;
    }

    private void handleUserInteractionChanged(int displayId, int mode) {
    private void handleUserInteractionChanged(int displayId, int mode, boolean isMouse) {
        if (mMagnificationCapabilities != Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL) {
            return;
        }

        // Mouse events are always throttled. Touch events are throttled only when the flag is on.
        if (isMouse || Flags.throttleMotionEventsForUiUpdate()) {
            final long currentTime = mSystemClock.uptimeMillis();
            if (currentTime - mLastMotionEventTriggeredUiChangeTime
                    < AccessibilityUtils.MAGNIFICATION_HANDLE_UI_CHANGE_INTERVAL_MS) {
                return;
            }
            mLastMotionEventTriggeredUiChangeTime = currentTime;
        }

        updateMagnificationUIControls(displayId, mode);
    }

+62 −0
Original line number Diff line number Diff line
@@ -2234,6 +2234,68 @@ public class MagnificationControllerTest {
                TEST_DISPLAY, MODE_FULLSCREEN);
    }

    @Test
    @EnableFlags(com.android.server.accessibility.Flags.FLAG_THROTTLE_MOTION_EVENTS_FOR_UI_UPDATE)
    public void onTouchEvent_withThrottleEnabled_shouldRateLimit() throws RemoteException {
        mMagnificationController.setMagnificationCapabilities(
                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
        setMagnificationEnabled(MODE_FULLSCREEN);
        clearInvocations(mMagnificationConnectionManager);

        // The first call should go through and trigger a UI update.
        mMagnificationController.onTouchInteractionStart(TEST_DISPLAY, MODE_FULLSCREEN);
        verify(mMagnificationConnectionManager).showMagnificationButton(
                TEST_DISPLAY, MODE_FULLSCREEN);
        clearInvocations(mMagnificationConnectionManager);

        // Subsequent call within the throttle period should be ignored.
        mMagnificationController.onTouchInteractionEnd(TEST_DISPLAY, MODE_FULLSCREEN);
        verify(mMagnificationConnectionManager, never()).showMagnificationButton(
                TEST_DISPLAY, MODE_FULLSCREEN);
    }

    @Test
    @EnableFlags(com.android.server.accessibility.Flags.FLAG_THROTTLE_MOTION_EVENTS_FOR_UI_UPDATE)
    public void onTouchEvent_withThrottleEnabled_shouldNotRateLimitAfterDelay()
            throws RemoteException {
        mMagnificationController.setMagnificationCapabilities(
                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
        setMagnificationEnabled(MODE_FULLSCREEN);
        clearInvocations(mMagnificationConnectionManager);

        // The first call should go through and trigger a UI update.
        mMagnificationController.onTouchInteractionStart(TEST_DISPLAY, MODE_FULLSCREEN);
        verify(mMagnificationConnectionManager).showMagnificationButton(
                TEST_DISPLAY, MODE_FULLSCREEN);
        clearInvocations(mMagnificationConnectionManager);

        // Advance time past the throttle period. The next call should now go through.
        mSystemClock.advanceTime(AccessibilityUtils.MAGNIFICATION_HANDLE_UI_CHANGE_INTERVAL_MS + 1);
        mMagnificationController.onTouchInteractionEnd(TEST_DISPLAY, MODE_FULLSCREEN);
        verify(mMagnificationConnectionManager).showMagnificationButton(
                TEST_DISPLAY, MODE_FULLSCREEN);
    }

    @Test
    @DisableFlags(com.android.server.accessibility.Flags.FLAG_THROTTLE_MOTION_EVENTS_FOR_UI_UPDATE)
    public void onTouchEvent_withThrottleDisabled_shouldNotRateLimit() throws RemoteException {
        mMagnificationController.setMagnificationCapabilities(
                Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_ALL);
        setMagnificationEnabled(MODE_FULLSCREEN);
        clearInvocations(mMagnificationConnectionManager);

        // The first call should go through and trigger a UI update.
        mMagnificationController.onTouchInteractionStart(TEST_DISPLAY, MODE_FULLSCREEN);
        verify(mMagnificationConnectionManager).showMagnificationButton(
                TEST_DISPLAY, MODE_FULLSCREEN);
        clearInvocations(mMagnificationConnectionManager);

        // Subsequent call within the throttle period should also go through.
        mMagnificationController.onTouchInteractionEnd(TEST_DISPLAY, MODE_FULLSCREEN);
        verify(mMagnificationConnectionManager).showMagnificationButton(
                TEST_DISPLAY, MODE_FULLSCREEN);
    }

    @Test
    public void enableWindowMode_showMagnificationButton()
            throws RemoteException {