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

Commit 8f223c59 authored by sallyyuen's avatar sallyyuen Committed by Sally Yuen
Browse files

Set the a11yNodeInfo unclickable if the TextView has a

LinkMovementMethod and there are no onClickListeners or
onLongClickListeners

A view with links shouldn't be exposing itself as clickable to
an a11yService if only the links are clickable. If a movement method is
set, the view turns both clickable and long-clickable. This has brought
a number of bugs where an a11yService will notify users the element is
clickable but performing the action does nothing.

We can't delete years-old code without breaking a lot of things, so try
to minimize the consequences by adding logic in onInitializeA11yNodeInfo.
Add checks so a view with links and no click listeners will be made un-clickable.

Bug: b/131758159
Test: Tested on several bugs with TalkBack, CtsAccessibilityTests, CtsTextTestCases,
CtsWidgetTestCases:TextViewTest
Change-Id: I53b695139ecea2c34d125e7077fd2077593adbe1
parent caaddf13
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -50331,6 +50331,7 @@ package android.view {
    method public boolean hasFocusable();
    method public boolean hasNestedScrollingParent();
    method public boolean hasOnClickListeners();
    method public boolean hasOnLongClickListeners();
    method @android.view.ViewDebug.ExportedProperty(category="drawing") public boolean hasOverlappingRendering();
    method public boolean hasPointerCapture();
    method @android.view.ViewDebug.ExportedProperty(category="layout") public boolean hasTransientState();
+9 −0
Original line number Diff line number Diff line
@@ -7066,6 +7066,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        getListenerInfo().mOnLongClickListener = l;
    }
    /**
     * Return whether this view has an attached OnLongClickListener.  Returns
     * true if there is a listener, false if there is none.
     */
    public boolean hasOnLongClickListeners() {
        ListenerInfo li = mListenerInfo;
        return (li != null && li.mOnLongClickListener != null);
    }
    /**
     * Register a callback to be invoked when this view is context clicked. If the view is not
     * context clickable, it becomes context clickable.
+14 −0
Original line number Diff line number Diff line
@@ -11735,6 +11735,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        if (!isSingleLine()) {
            info.setMultiLine(true);
        }
        // A view should not be exposed as clickable/long-clickable to a service because of a
        // LinkMovementMethod.
        if ((info.isClickable() || info.isLongClickable())
                && mMovement instanceof LinkMovementMethod) {
            if (!hasOnClickListeners()) {
                info.setClickable(false);
                info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK);
            }
            if (!hasOnLongClickListeners()) {
                info.setLongClickable(false);
                info.removeAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
            }
        }
    }
    @Override