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 3f1203fb78)
Merged-In: I3958e5b80e6156e03c99335e0d0b671438965ebb
This commit is contained in:
@@ -24,7 +24,6 @@ import android.text.TextUtils;
|
|||||||
import android.text.method.ArrowKeyMovementMethod;
|
import android.text.method.ArrowKeyMovementMethod;
|
||||||
import android.text.method.MovementMethod;
|
import android.text.method.MovementMethod;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.accessibility.AccessibilityNodeInfo;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is supposed to be a *very* thin veneer over TextView.
|
* This is supposed to be a *very* thin veneer over TextView.
|
||||||
@@ -179,13 +178,4 @@ public class EditText extends TextView {
|
|||||||
protected boolean supportsAutoSizeText() {
|
protected boolean supportsAutoSizeText() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @hide */
|
|
||||||
@Override
|
|
||||||
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
|
|
||||||
super.onInitializeAccessibilityNodeInfoInternal(info);
|
|
||||||
if (isEnabled()) {
|
|
||||||
info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_TEXT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -317,6 +317,7 @@ public class Editor {
|
|||||||
private SelectionActionModeHelper mSelectionActionModeHelper;
|
private SelectionActionModeHelper mSelectionActionModeHelper;
|
||||||
|
|
||||||
boolean mIsBeingLongClicked;
|
boolean mIsBeingLongClicked;
|
||||||
|
boolean mIsBeingLongClickedByAccessibility;
|
||||||
|
|
||||||
private SuggestionsPopupWindow mSuggestionsPopupWindow;
|
private SuggestionsPopupWindow mSuggestionsPopupWindow;
|
||||||
SuggestionRangeSpan mSuggestionRangeSpan;
|
SuggestionRangeSpan mSuggestionRangeSpan;
|
||||||
@@ -1312,6 +1313,12 @@ public class Editor {
|
|||||||
if (TextView.DEBUG_CURSOR) {
|
if (TextView.DEBUG_CURSOR) {
|
||||||
logCursor("performLongClick", "handled=%s", handled);
|
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.
|
// Long press in empty space moves cursor and starts the insertion action mode.
|
||||||
if (!handled && !isPositionOnText(mTouchState.getLastDownX(), mTouchState.getLastDownY())
|
if (!handled && !isPositionOnText(mTouchState.getLastDownX(), mTouchState.getLastDownY())
|
||||||
&& !mTouchState.isOnHandle() && mInsertionControllerEnabled) {
|
&& !mTouchState.isOnHandle() && mInsertionControllerEnabled) {
|
||||||
@@ -1359,6 +1366,14 @@ public class Editor {
|
|||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void toggleInsertionActionMode() {
|
||||||
|
if (mTextActionMode != null) {
|
||||||
|
stopTextActionMode();
|
||||||
|
} else {
|
||||||
|
startInsertionActionMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float getLastUpPositionX() {
|
float getLastUpPositionX() {
|
||||||
return mTouchState.getLastUpX();
|
return mTouchState.getLastUpX();
|
||||||
}
|
}
|
||||||
@@ -5426,11 +5441,7 @@ public class Editor {
|
|||||||
config.getScaledTouchSlop());
|
config.getScaledTouchSlop());
|
||||||
if (isWithinTouchSlop) {
|
if (isWithinTouchSlop) {
|
||||||
// Tapping on the handle toggles the insertion action mode.
|
// Tapping on the handle toggles the insertion action mode.
|
||||||
if (mTextActionMode != null) {
|
toggleInsertionActionMode();
|
||||||
stopTextActionMode();
|
|
||||||
} else {
|
|
||||||
startInsertionActionMode();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (mTextActionMode != null) {
|
if (mTextActionMode != null) {
|
||||||
|
|||||||
@@ -12108,6 +12108,23 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
onEditorAction(getImeActionId());
|
onEditorAction(getImeActionId());
|
||||||
}
|
}
|
||||||
} return true;
|
} 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: {
|
default: {
|
||||||
return super.performAccessibilityActionInternal(action, arguments);
|
return super.performAccessibilityActionInternal(action, arguments);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ import android.app.Activity;
|
|||||||
import android.app.Instrumentation;
|
import android.app.Instrumentation;
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.support.test.uiautomator.UiDevice;
|
import android.support.test.uiautomator.UiDevice;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.text.Selection;
|
import android.text.Selection;
|
||||||
@@ -75,6 +76,7 @@ import android.view.ActionMode;
|
|||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
import android.view.accessibility.AccessibilityNodeInfo;
|
||||||
import android.view.textclassifier.SelectionEvent;
|
import android.view.textclassifier.SelectionEvent;
|
||||||
import android.view.textclassifier.TextClassificationManager;
|
import android.view.textclassifier.TextClassificationManager;
|
||||||
import android.view.textclassifier.TextClassifier;
|
import android.view.textclassifier.TextClassifier;
|
||||||
@@ -357,6 +359,20 @@ public class TextViewActivityTest {
|
|||||||
assertFalse(textView.hasSelection());
|
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
|
@Test
|
||||||
public void testSelectionRemovedWhenNonselectableTextLosesFocus() throws Throwable {
|
public void testSelectionRemovedWhenNonselectableTextLosesFocus() throws Throwable {
|
||||||
final TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.nonselectable_textview);
|
final TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.nonselectable_textview);
|
||||||
|
|||||||
Reference in New Issue
Block a user