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

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

Implement ACTION_LONG_CLICK for accessibility

Due to changes in R, the a11y framework no longer dispatches touch
events for a long press. This prevents the activation of EditText's floating menu.

We can re-enable it by implementing the proper a11y action
ACTION_LONG_CLICK. The menu itself is diffult to access through TalkBack's linear
navigation, but this is future work for a separate known issue.

Start and stop the menu for editable TextViews, which includes EditTexts.
Since touch events are no longer sent by a11y, separate the
accessibility handling from the touch handling infrastructure for long clicks in Editor.

We can't go through the main performLongClick code because it doesn't
actually start the action mode but rather sets pending, which routes
back to TextView. There's too little separation between the touch events and action logic.

Whoever touches the performLongClick code may need to also make
corresponding changes to the a11y path, but I suspect this won't happen often.

Remove the onInitializeA11yNodeInfo override for EditText because this
is handled by TextView.

Bug: 148127445
Test: Tested text fields in various apps. ag/10602004. atest
FrameworksCoreTests:TextViewActivityTest#testToolbarAppearsAccessibilityLongClick

Change-Id: I3958e5b80e6156e03c99335e0d0b671438965ebb
(cherry picked from commit 3f1203fb)
Merged-In: I3958e5b80e6156e03c99335e0d0b671438965ebb
parent 59624b21
Loading
Loading
Loading
Loading
+0 −10
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import android.text.TextUtils;
import android.text.method.ArrowKeyMovementMethod;
import android.text.method.MovementMethod;
import android.util.AttributeSet;
import android.view.accessibility.AccessibilityNodeInfo;

/*
 * This is supposed to be a *very* thin veneer over TextView.
@@ -179,13 +178,4 @@ public class EditText extends TextView {
    protected boolean supportsAutoSizeText() {
        return false;
    }

    /** @hide */
    @Override
    public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
        super.onInitializeAccessibilityNodeInfoInternal(info);
        if (isEnabled()) {
            info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT);
        }
    }
}
+16 −5
Original line number Diff line number Diff line
@@ -317,6 +317,7 @@ public class Editor {
    private SelectionActionModeHelper mSelectionActionModeHelper;

    boolean mIsBeingLongClicked;
    boolean mIsBeingLongClickedByAccessibility;

    private SuggestionsPopupWindow mSuggestionsPopupWindow;
    SuggestionRangeSpan mSuggestionRangeSpan;
@@ -1312,6 +1313,12 @@ public class Editor {
        if (TextView.DEBUG_CURSOR) {
            logCursor("performLongClick", "handled=%s", handled);
        }
        if (mIsBeingLongClickedByAccessibility) {
            if (!handled) {
                toggleInsertionActionMode();
            }
            return true;
        }
        // Long press in empty space moves cursor and starts the insertion action mode.
        if (!handled && !isPositionOnText(mTouchState.getLastDownX(), mTouchState.getLastDownY())
                && !mTouchState.isOnHandle() && mInsertionControllerEnabled) {
@@ -1359,6 +1366,14 @@ public class Editor {
        return handled;
    }

    private void toggleInsertionActionMode() {
        if (mTextActionMode != null) {
            stopTextActionMode();
        } else {
            startInsertionActionMode();
        }
    }

    float getLastUpPositionX() {
        return mTouchState.getLastUpX();
    }
@@ -5426,11 +5441,7 @@ public class Editor {
                                config.getScaledTouchSlop());
                        if (isWithinTouchSlop) {
                            // Tapping on the handle toggles the insertion action mode.
                            if (mTextActionMode != null) {
                                stopTextActionMode();
                            } else {
                                startInsertionActionMode();
                            }
                            toggleInsertionActionMode();
                        }
                    } else {
                        if (mTextActionMode != null) {
+17 −0
Original line number Diff line number Diff line
@@ -12108,6 +12108,23 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    onEditorAction(getImeActionId());
                }
            } return true;
            case AccessibilityNodeInfo.ACTION_LONG_CLICK: {
                if (isLongClickable()) {
                    boolean handled;
                    if (isEnabled() && (mBufferType == BufferType.EDITABLE)) {
                        mEditor.mIsBeingLongClickedByAccessibility = true;
                        try {
                            handled = performLongClick();
                        } finally {
                            mEditor.mIsBeingLongClickedByAccessibility = false;
                        }
                    } else {
                        handled = performLongClick();
                    }
                    return handled;
                }
            }
            return false;
            default: {
                return super.performAccessibilityActionInternal(action, arguments);
            }
+16 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ import android.app.Activity;
import android.app.Instrumentation;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.os.Bundle;
import android.support.test.uiautomator.UiDevice;
import android.text.InputType;
import android.text.Selection;
@@ -75,6 +76,7 @@ import android.view.ActionMode;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.textclassifier.SelectionEvent;
import android.view.textclassifier.TextClassificationManager;
import android.view.textclassifier.TextClassifier;
@@ -357,6 +359,20 @@ public class TextViewActivityTest {
        assertFalse(textView.hasSelection());
    }

    @Test
    public void testToolbarAppearsAccessibilityLongClick() throws Throwable {
        final String text = "Toolbar appears after performing accessibility's ACTION_LONG_CLICK.";
        mActivityRule.runOnUiThread(() -> {
            final TextView textView = mActivity.findViewById(R.id.textview);
            final Bundle args = new Bundle();
            textView.performAccessibilityAction(AccessibilityNodeInfo.ACTION_LONG_CLICK, args);
        });
        mInstrumentation.waitForIdleSync();

        sleepForFloatingToolbarPopup();
        assertFloatingToolbarIsDisplayed();
    }

    @Test
    public void testSelectionRemovedWhenNonselectableTextLosesFocus() throws Throwable {
        final TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.nonselectable_textview);