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

Commit 46f57445 authored by Riley Jones's avatar Riley Jones
Browse files

EventDispatcher supplies displayID to sent A11yEvents.

Test: atest com.android.server.accessibility.getstures.EventDispatcherTest
Bug: 431092453
Flag: com.android.server.accessibility.touch_explorer_a11y_events_include_display_id
Change-Id: If9ac34d69c85829f0207b8fd0cc36e5cded2994f
parent 13ca7927
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -304,6 +304,16 @@ flag {
    bug: "322829049"
}

flag {
    name: "touch_explorer_a11y_events_include_display_id"
    namespace: "accessibility"
    description: "When sending an A11y event, TouchExplorer will include its displayId"
    bug: "431092453"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "touch_explorer_use_virtual_device_id"
    namespace: "accessibility"
+18 −6
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.view.MotionEvent.PointerProperties;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;

import com.android.internal.annotations.VisibleForTesting;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accessibility.EventStreamTransformation;
import com.android.server.accessibility.Flags;
@@ -73,12 +74,17 @@ public class EventDispatcher {

    private TouchState mState;

    @VisibleForTesting
    int mDisplayId;

    EventDispatcher(
            Context context,
            int displayId,
            AccessibilityManagerService ams,
            EventStreamTransformation receiver,
            TouchState state) {
        mContext = context;
        mDisplayId = displayId;
        mAms = ams;
        mReceiver = receiver;
        mState = state;
@@ -105,7 +111,7 @@ public class EventDispatcher {
            int policyFlags) {
        prototype.setAction(action);

        MotionEvent event = null;
        MotionEvent event;
        if (pointerIdBits == ALL_POINTER_ID_BITS) {
            event = prototype;
        } else {
@@ -184,20 +190,26 @@ public class EventDispatcher {
    void sendAccessibilityEvent(int type) {
        AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(mContext);
        if (accessibilityManager.isEnabled()) {
            AccessibilityEvent event = AccessibilityEvent.obtain(type);
            event.setWindowId(mAms.getActiveWindowId());
            accessibilityManager.sendAccessibilityEvent(event);
            accessibilityManager.sendAccessibilityEvent(populateAccessibilityEvent(type));
            if (DEBUG) {
                Slog.d(
                        LOG_TAG,
                        "Sending accessibility event" + AccessibilityEvent.eventTypeToString(type));
            }
        }
        // Todo: get rid of this and have TouchState control the sending of events rather than react
        // to it.
        // Todo(b/431802110): Restructure TouchState to send a11y events rather than receive them.
        mState.onInjectedAccessibilityEvent(type);
    }

    AccessibilityEvent populateAccessibilityEvent(int type) {
        AccessibilityEvent event = new AccessibilityEvent(type);
        event.setWindowId(mAms.getActiveWindowId());
        if (Flags.touchExplorerA11yEventsIncludeDisplayId()) {
            event.setDisplayId(mDisplayId);
        }
        return event;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
+1 −1
Original line number Diff line number Diff line
@@ -188,7 +188,7 @@ public class TouchExplorer extends BaseEventStreamTransformation
        mAms = service;
        mState = new TouchState(mDisplayId, mAms);
        mReceivedPointerTracker = mState.getReceivedPointerTracker();
        mDispatcher = new EventDispatcher(context, mAms, super.getNext(), mState);
        mDispatcher = new EventDispatcher(context, mDisplayId, mAms, super.getNext(), mState);
        mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout();
        mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop();
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+62 −0
Original line number Diff line number Diff line
/*
 * 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.gestures

import android.content.Context
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
import android.view.accessibility.AccessibilityEvent
import androidx.test.runner.AndroidJUnit4
import com.android.server.accessibility.AccessibilityManagerService
import com.android.server.accessibility.EventStreamTransformation
import com.android.server.accessibility.Flags
import junit.framework.Assert
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.stub

@RunWith(AndroidJUnit4::class)
class EventDispatcherTest {
    @get:Rule val mSetFlagsRule = SetFlagsRule()

    private val ams: AccessibilityManagerService = mock<AccessibilityManagerService>()
    private var dispatcher: EventDispatcher = EventDispatcher(
        mock<Context>(),
        0,
        ams,
        mock<EventStreamTransformation>(),
        mock<TouchState>()
    )

    @Test
    @EnableFlags(Flags.FLAG_TOUCH_EXPLORER_A11Y_EVENTS_INCLUDE_DISPLAY_ID)
    fun populateAccessibilityEvent_matchesParameters() {
        val windowId = 1
        val displayId = 2
        val type = AccessibilityEvent.TYPE_TOUCH_INTERACTION_END

        ams.stub { on { activeWindowId } doReturn windowId }
        dispatcher.mDisplayId = displayId
        val event = dispatcher.populateAccessibilityEvent(type)

        Assert.assertEquals(event.windowId, windowId)
        Assert.assertEquals(event.displayId, displayId)
        Assert.assertEquals(event.eventType, type)
    }
}