Loading core/java/android/widget/Editor.java +69 −3 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.widget; import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP; import static android.widget.TextView.ACCESSIBILITY_ACTION_SMART_START_ID; import android.R; import android.animation.ValueAnimator; Loading Loading @@ -84,6 +85,7 @@ import android.text.style.URLSpan; import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.Log; import android.util.Pair; import android.util.SparseArray; import android.util.TypedValue; import android.view.ActionMode; Loading Loading @@ -112,6 +114,7 @@ import android.view.ViewParent; import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.view.animation.LinearInterpolator; import android.view.inputmethod.CorrectionInfo; import android.view.inputmethod.CursorAnchorInfo; Loading Loading @@ -449,11 +452,14 @@ public class Editor { private int mLineChangeSlopMax; private int mLineChangeSlopMin; private final AccessibilitySmartActions mA11ySmartActions; Editor(TextView textView) { mTextView = textView; // Synchronize the filter list, which places the undo input filter at the end. mTextView.setFilters(mTextView.getFilters()); mProcessTextIntentActionsHandler = new ProcessTextIntentActionsHandler(this); mA11ySmartActions = new AccessibilitySmartActions(mTextView); mHapticTextHandleEnabled = mTextView.getContext().getResources().getBoolean( com.android.internal.R.bool.config_enableHapticTextHandle); Loading Loading @@ -4381,6 +4387,7 @@ public class Editor { item.setShowAsAction(showAsAction); mAssistClickHandlers.put(item, TextClassification.createIntentOnClickListener(action.getActionIntent())); mA11ySmartActions.addAction(action); return item; } Loading @@ -4394,6 +4401,7 @@ public class Editor { } i++; } mA11ySmartActions.reset(); } private boolean hasLegacyAssistItem(TextClassification classification) { Loading Loading @@ -7656,7 +7664,7 @@ public class Editor { private final PackageManager mPackageManager; private final String mPackageName; private final SparseArray<Intent> mAccessibilityIntents = new SparseArray<>(); private final SparseArray<AccessibilityNodeInfo.AccessibilityAction> mAccessibilityActions = private final SparseArray<AccessibilityAction> mAccessibilityActions = new SparseArray<>(); private final List<ResolveInfo> mSupportedActivities = new ArrayList<>(); Loading Loading @@ -7706,8 +7714,7 @@ public class Editor { int actionId = TextView.ACCESSIBILITY_ACTION_PROCESS_TEXT_START_ID + i++; mAccessibilityActions.put( actionId, new AccessibilityNodeInfo.AccessibilityAction( actionId, getLabel(resolveInfo))); new AccessibilityAction(actionId, getLabel(resolveInfo))); mAccessibilityIntents.put( actionId, createProcessTextIntentForResolveInfo(resolveInfo)); } Loading Loading @@ -7786,6 +7793,65 @@ public class Editor { } } /** * Accessibility helper for "smart" (i.e. textAssist) actions. * Helps ensure that "smart" actions are shown in the accessibility menu. * NOTE that these actions are only available when an action mode is live. * * @hide */ private static final class AccessibilitySmartActions { private final TextView mTextView; private final SparseArray<Pair<AccessibilityAction, RemoteAction>> mActions = new SparseArray<>(); private AccessibilitySmartActions(TextView textView) { mTextView = Objects.requireNonNull(textView); } private void addAction(RemoteAction action) { final int actionId = ACCESSIBILITY_ACTION_SMART_START_ID + mActions.size(); mActions.put(actionId, new Pair(new AccessibilityAction(actionId, action.getTitle()), action)); } private void reset() { mActions.clear(); } void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo nodeInfo) { for (int i = 0; i < mActions.size(); i++) { nodeInfo.addAction(mActions.valueAt(i).first); } } boolean performAccessibilityAction(int actionId) { final Pair<AccessibilityAction, RemoteAction> pair = mActions.get(actionId); if (pair != null) { TextClassification.createIntentOnClickListener(pair.second.getActionIntent()) .onClick(mTextView); return true; } return false; } } /** * Initializes the nodeInfo with smart actions. */ void onInitializeSmartActionsAccessibilityNodeInfo(AccessibilityNodeInfo nodeInfo) { mA11ySmartActions.onInitializeAccessibilityNodeInfo(nodeInfo); } /** * Handles the accessibility action if it is an active smart action. * Return false if this method does not hanle the action. */ boolean performSmartActionsAccessibilityAction(int actionId) { return mA11ySmartActions.performAccessibilityAction(actionId); } static void logCursor(String location, @Nullable String msgFormat, Object ... msgArgs) { if (msgFormat == null) { Log.d(TAG, location); Loading core/java/android/widget/TextView.java +9 −3 Original line number Diff line number Diff line Loading @@ -442,6 +442,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Accessibility action start id for "process text" actions. static final int ACCESSIBILITY_ACTION_PROCESS_TEXT_START_ID = 0x10000100; /** Accessibility action start id for "smart" actions. @hide */ static final int ACCESSIBILITY_ACTION_SMART_START_ID = 0x10001000; /** * @hide */ Loading Loading @@ -12223,6 +12226,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } if (canProcessText()) { // also implies mEditor is not null. mEditor.mProcessTextIntentActionsHandler.onInitializeAccessibilityNodeInfo(info); mEditor.onInitializeSmartActionsAccessibilityNodeInfo(info); } } Loading Loading @@ -12426,10 +12430,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ @Override public boolean performAccessibilityActionInternal(int action, Bundle arguments) { if (mEditor != null && mEditor.mProcessTextIntentActionsHandler.performAccessibilityAction(action)) { if (mEditor != null) { if (mEditor.mProcessTextIntentActionsHandler.performAccessibilityAction(action) || mEditor.performSmartActionsAccessibilityAction(action)) { return true; } } switch (action) { case AccessibilityNodeInfo.ACTION_CLICK: { return performAccessibilityActionClick(arguments); Loading Loading
core/java/android/widget/Editor.java +69 −3 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package android.widget; import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP; import static android.widget.TextView.ACCESSIBILITY_ACTION_SMART_START_ID; import android.R; import android.animation.ValueAnimator; Loading Loading @@ -84,6 +85,7 @@ import android.text.style.URLSpan; import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.Log; import android.util.Pair; import android.util.SparseArray; import android.util.TypedValue; import android.view.ActionMode; Loading Loading @@ -112,6 +114,7 @@ import android.view.ViewParent; import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.view.animation.LinearInterpolator; import android.view.inputmethod.CorrectionInfo; import android.view.inputmethod.CursorAnchorInfo; Loading Loading @@ -449,11 +452,14 @@ public class Editor { private int mLineChangeSlopMax; private int mLineChangeSlopMin; private final AccessibilitySmartActions mA11ySmartActions; Editor(TextView textView) { mTextView = textView; // Synchronize the filter list, which places the undo input filter at the end. mTextView.setFilters(mTextView.getFilters()); mProcessTextIntentActionsHandler = new ProcessTextIntentActionsHandler(this); mA11ySmartActions = new AccessibilitySmartActions(mTextView); mHapticTextHandleEnabled = mTextView.getContext().getResources().getBoolean( com.android.internal.R.bool.config_enableHapticTextHandle); Loading Loading @@ -4381,6 +4387,7 @@ public class Editor { item.setShowAsAction(showAsAction); mAssistClickHandlers.put(item, TextClassification.createIntentOnClickListener(action.getActionIntent())); mA11ySmartActions.addAction(action); return item; } Loading @@ -4394,6 +4401,7 @@ public class Editor { } i++; } mA11ySmartActions.reset(); } private boolean hasLegacyAssistItem(TextClassification classification) { Loading Loading @@ -7656,7 +7664,7 @@ public class Editor { private final PackageManager mPackageManager; private final String mPackageName; private final SparseArray<Intent> mAccessibilityIntents = new SparseArray<>(); private final SparseArray<AccessibilityNodeInfo.AccessibilityAction> mAccessibilityActions = private final SparseArray<AccessibilityAction> mAccessibilityActions = new SparseArray<>(); private final List<ResolveInfo> mSupportedActivities = new ArrayList<>(); Loading Loading @@ -7706,8 +7714,7 @@ public class Editor { int actionId = TextView.ACCESSIBILITY_ACTION_PROCESS_TEXT_START_ID + i++; mAccessibilityActions.put( actionId, new AccessibilityNodeInfo.AccessibilityAction( actionId, getLabel(resolveInfo))); new AccessibilityAction(actionId, getLabel(resolveInfo))); mAccessibilityIntents.put( actionId, createProcessTextIntentForResolveInfo(resolveInfo)); } Loading Loading @@ -7786,6 +7793,65 @@ public class Editor { } } /** * Accessibility helper for "smart" (i.e. textAssist) actions. * Helps ensure that "smart" actions are shown in the accessibility menu. * NOTE that these actions are only available when an action mode is live. * * @hide */ private static final class AccessibilitySmartActions { private final TextView mTextView; private final SparseArray<Pair<AccessibilityAction, RemoteAction>> mActions = new SparseArray<>(); private AccessibilitySmartActions(TextView textView) { mTextView = Objects.requireNonNull(textView); } private void addAction(RemoteAction action) { final int actionId = ACCESSIBILITY_ACTION_SMART_START_ID + mActions.size(); mActions.put(actionId, new Pair(new AccessibilityAction(actionId, action.getTitle()), action)); } private void reset() { mActions.clear(); } void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo nodeInfo) { for (int i = 0; i < mActions.size(); i++) { nodeInfo.addAction(mActions.valueAt(i).first); } } boolean performAccessibilityAction(int actionId) { final Pair<AccessibilityAction, RemoteAction> pair = mActions.get(actionId); if (pair != null) { TextClassification.createIntentOnClickListener(pair.second.getActionIntent()) .onClick(mTextView); return true; } return false; } } /** * Initializes the nodeInfo with smart actions. */ void onInitializeSmartActionsAccessibilityNodeInfo(AccessibilityNodeInfo nodeInfo) { mA11ySmartActions.onInitializeAccessibilityNodeInfo(nodeInfo); } /** * Handles the accessibility action if it is an active smart action. * Return false if this method does not hanle the action. */ boolean performSmartActionsAccessibilityAction(int actionId) { return mA11ySmartActions.performAccessibilityAction(actionId); } static void logCursor(String location, @Nullable String msgFormat, Object ... msgArgs) { if (msgFormat == null) { Log.d(TAG, location); Loading
core/java/android/widget/TextView.java +9 −3 Original line number Diff line number Diff line Loading @@ -442,6 +442,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Accessibility action start id for "process text" actions. static final int ACCESSIBILITY_ACTION_PROCESS_TEXT_START_ID = 0x10000100; /** Accessibility action start id for "smart" actions. @hide */ static final int ACCESSIBILITY_ACTION_SMART_START_ID = 0x10001000; /** * @hide */ Loading Loading @@ -12223,6 +12226,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } if (canProcessText()) { // also implies mEditor is not null. mEditor.mProcessTextIntentActionsHandler.onInitializeAccessibilityNodeInfo(info); mEditor.onInitializeSmartActionsAccessibilityNodeInfo(info); } } Loading Loading @@ -12426,10 +12430,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ @Override public boolean performAccessibilityActionInternal(int action, Bundle arguments) { if (mEditor != null && mEditor.mProcessTextIntentActionsHandler.performAccessibilityAction(action)) { if (mEditor != null) { if (mEditor.mProcessTextIntentActionsHandler.performAccessibilityAction(action) || mEditor.performSmartActionsAccessibilityAction(action)) { return true; } } switch (action) { case AccessibilityNodeInfo.ACTION_CLICK: { return performAccessibilityActionClick(arguments); Loading