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

Commit 510043d4 authored by Hiroki Sato's avatar Hiroki Sato
Browse files

Throttle content changed events only subtree changes

Previously accessibility events of TYPE_WINDOW_CONTENT_CHANGED were
throttled in ViewRootImpl. It merges events from multiple nodes and
destroys source node information.

This makes multiple issues, for example:
- accessibility services cannot deliver proper feedback,
- view's onInitializeAccessibilityEvent is not correctly called,
- AccessibilityCache is not correctly updated.

This change limits the throttle only for subtree changes to prevent.

Bug: 143889012
Bug: 277305460
Test: CtsAccessibilityTestCases CtsAccessibilityServiceTestCases
Change-Id: Ic18cd4aa310ab37e40c6623625b59b4b9ebfea2f
parent 2a592601
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -14944,8 +14944,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    /**
     * Notifies that the accessibility state of this view changed. The change
     * is local to this view and does not represent structural changes such
     * as children and parent. For example, the view became focusable. The
     * notification is at at most once every
     * as children and parent. For example, the view became focusable. Some of
     * the notification is at at most once every
     * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}
     * to avoid unnecessary load to the system. Also once a view has a pending
     * notification this method is a NOP until the notification has been sent.
@@ -15007,7 +15007,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    /**
     * Notifies that the accessibility state of this view changed. The change
     * is *not* local to this view and does represent structural changes such
     * as children and parent. For example, the view size changed. The
     * as children and parent. For example, the view size changed. Some of the
     * notification is at at most once every
     * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}
     * to avoid unnecessary load to the system. Also once a view has a pending
+24 −2
Original line number Diff line number Diff line
@@ -218,7 +218,6 @@ import com.android.internal.os.IResultReceiver;
import com.android.internal.os.SomeArgs;
import com.android.internal.policy.DecorView;
import com.android.internal.policy.PhoneFallbackEventHandler;
import com.android.internal.util.Preconditions;
import com.android.internal.view.BaseSurfaceHolder;
import com.android.internal.view.RootViewSurfaceTaker;
import com.android.internal.view.SurfaceCallbackHelper;
@@ -808,6 +807,7 @@ public final class ViewRootImpl implements ViewParent,
    final HighContrastTextManager mHighContrastTextManager;

    SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
    boolean mSendingAccessibilityWIndowContentChange = false;

    HashSet<View> mTempHashSet;

@@ -9867,7 +9867,29 @@ public final class ViewRootImpl implements ViewParent,

    @Override
    public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
        postSendWindowContentChangedCallback(Preconditions.checkNotNull(source), changeType);
        Objects.requireNonNull(source);
        if (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) {
            postSendWindowContentChangedCallback(source, changeType);
            return;
        }
        if (mSendingAccessibilityWIndowContentChange) {
            // This allows re-entering this method.
            // Some apps update views during an event dispatch, which triggers another a11y event.
            // In order to avoid an infinite loop, postpone second event dispatch.
            mHandler.post(() -> notifySubtreeAccessibilityStateChanged(child, source, changeType));
            return;
        }

        AccessibilityEvent event =
                new AccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
        event.setContentChangeTypes(changeType);
        event.setAction(mAccessibilityManager.getPerformingAction());
        mSendingAccessibilityWIndowContentChange = true;
        try {
            source.sendAccessibilityEventUnchecked(event);
        } finally {
            mSendingAccessibilityWIndowContentChange = false;
        }
    }

    @Override