aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java')
-rw-r--r--java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java116
1 files changed, 115 insertions, 1 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
index 955cb4c42..67e21b10c 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
@@ -18,13 +18,18 @@ package com.android.inputmethod.accessibility;
import android.graphics.Rect;
import android.inputmethodservice.InputMethodService;
+import android.os.Bundle;
+import android.os.SystemClock;
import android.support.v4.view.ViewCompat;
+import android.support.v4.view.accessibility.AccessibilityEventCompat;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.support.v4.view.accessibility.AccessibilityNodeProviderCompat;
import android.support.v4.view.accessibility.AccessibilityRecordCompat;
import android.util.Log;
import android.util.SparseArray;
+import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewParent;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.accessibility.AccessibilityEvent;
import android.view.inputmethod.EditorInfo;
@@ -45,6 +50,7 @@ import com.android.inputmethod.keyboard.KeyboardView;
*/
public class AccessibilityEntityProvider extends AccessibilityNodeProviderCompat {
private static final String TAG = AccessibilityEntityProvider.class.getSimpleName();
+ private static final int UNDEFINED = Integer.MIN_VALUE;
private final KeyboardView mKeyboardView;
private final InputMethodService mInputMethodService;
@@ -60,6 +66,9 @@ public class AccessibilityEntityProvider extends AccessibilityNodeProviderCompat
/** The parent view's cached on-screen location. */
private final int[] mParentLocation = new int[2];
+ /** The virtual view identifier for the focused node. */
+ private int mAccessibilityFocusedView = UNDEFINED;
+
public AccessibilityEntityProvider(KeyboardView keyboardView, InputMethodService inputMethod) {
mKeyboardView = keyboardView;
mInputMethodService = inputMethod;
@@ -124,7 +133,9 @@ public class AccessibilityEntityProvider extends AccessibilityNodeProviderCompat
public AccessibilityNodeInfoCompat createAccessibilityNodeInfo(int virtualViewId) {
AccessibilityNodeInfoCompat info = null;
- if (virtualViewId == View.NO_ID) {
+ if (virtualViewId == UNDEFINED) {
+ return null;
+ } else if (virtualViewId == View.NO_ID) {
// We are requested to create an AccessibilityNodeInfo describing
// this View, i.e. the root of the virtual sub-tree.
info = AccessibilityNodeInfoCompat.obtain(mKeyboardView);
@@ -166,12 +177,115 @@ public class AccessibilityEntityProvider extends AccessibilityNodeProviderCompat
info.setSource(mKeyboardView, virtualViewId);
info.setBoundsInScreen(boundsInScreen);
info.setEnabled(true);
+ info.setClickable(true);
+ info.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
+
+ if (mAccessibilityFocusedView == virtualViewId) {
+ info.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS);
+ } else {
+ info.addAction(AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
+ }
}
return info;
}
/**
+ * Simulates a key press by injecting touch events into the keyboard view.
+ * This avoids the complexity of trackers and listeners within the keyboard.
+ *
+ * @param key The key to press.
+ */
+ void simulateKeyPress(Key key) {
+ final int x = key.mX + (key.mWidth / 2);
+ final int y = key.mY + (key.mHeight / 2);
+ final long downTime = SystemClock.uptimeMillis();
+ final MotionEvent downEvent = MotionEvent.obtain(
+ downTime, downTime, MotionEvent.ACTION_DOWN, x, y, 0);
+ final MotionEvent upEvent = MotionEvent.obtain(
+ downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, x, y, 0);
+
+ mKeyboardView.onTouchEvent(downEvent);
+ mKeyboardView.onTouchEvent(upEvent);
+ }
+
+ @Override
+ public boolean performAction(int virtualViewId, int action, Bundle arguments) {
+ final Key key = mVirtualViewIdToKey.get(virtualViewId);
+
+ if (key == null) {
+ return false;
+ }
+
+ return performActionForKey(key, action, arguments);
+ }
+
+ /**
+ * Performs the specified accessibility action for the given key.
+ *
+ * @param key The on which to perform the action.
+ * @param action The action to perform.
+ * @param arguments The action's arguments.
+ * @return The result of performing the action, or false if the action is
+ * not supported.
+ */
+ boolean performActionForKey(Key key, int action, Bundle arguments) {
+ final int virtualViewId = generateVirtualViewIdForKey(key);
+
+ switch (action) {
+ case AccessibilityNodeInfoCompat.ACTION_CLICK:
+ simulateKeyPress(key);
+ return true;
+ case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
+ if (mAccessibilityFocusedView == virtualViewId) {
+ return false;
+ }
+ mAccessibilityFocusedView = virtualViewId;
+ sendAccessibilityEventForKey(
+ key, AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
+ return true;
+ case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
+ if (mAccessibilityFocusedView != virtualViewId) {
+ return false;
+ }
+ mAccessibilityFocusedView = UNDEFINED;
+ sendAccessibilityEventForKey(
+ key, AccessibilityEventCompat.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public AccessibilityNodeInfoCompat findAccessibilityFocus(int virtualViewId) {
+ return createAccessibilityNodeInfo(mAccessibilityFocusedView);
+ }
+
+ @Override
+ public AccessibilityNodeInfoCompat accessibilityFocusSearch(int direction, int virtualViewId) {
+ // Focus search is not currently supported for IMEs.
+ return null;
+ }
+
+ /**
+ * Sends an accessibility event for the given {@link Key}.
+ *
+ * @param key The key that's sending the event.
+ * @param eventType The type of event to send.
+ */
+ void sendAccessibilityEventForKey(Key key, int eventType) {
+ final AccessibilityEvent event = createAccessibilityEvent(key, eventType);
+ final ViewParent parent = mKeyboardView.getParent();
+
+ if (parent == null) {
+ return;
+ }
+
+ parent.requestSendAccessibilityEvent(mKeyboardView, event);
+ }
+
+ /**
* Returns the context-specific description for a {@link Key}.
*
* @param key The key to describe.