aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java')
-rw-r--r--java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java135
1 files changed, 127 insertions, 8 deletions
diff --git a/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java b/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java
index c114551c8..96f84dde9 100644
--- a/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java
+++ b/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java
@@ -17,9 +17,9 @@
package com.android.inputmethod.accessibility;
import android.content.Context;
+import android.graphics.Rect;
import android.os.SystemClock;
-import android.support.v4.view.accessibility.AccessibilityEventCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.util.Log;
import android.util.SparseIntArray;
import android.view.MotionEvent;
@@ -28,11 +28,19 @@ import com.android.inputmethod.keyboard.KeyDetector;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.keyboard.MainKeyboardView;
+import com.android.inputmethod.keyboard.PointerTracker;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
+/**
+ * This class represents a delegate that can be registered in {@link MainKeyboardView} to enhance
+ * accessibility support via composition rather via inheritance.
+ */
public final class MainKeyboardAccessibilityDelegate
- extends KeyboardAccessibilityDelegate<MainKeyboardView> {
+ extends KeyboardAccessibilityDelegate<MainKeyboardView>
+ implements AccessibilityLongPressTimer.LongPressTimerCallback {
+ private static final String TAG = MainKeyboardAccessibilityDelegate.class.getSimpleName();
+
/** Map of keyboard modes to resource IDs. */
private static final SparseIntArray KEYBOARD_MODE_RES_IDS = new SparseIntArray();
@@ -51,10 +59,16 @@ public final class MainKeyboardAccessibilityDelegate
/** The most recently set keyboard mode. */
private int mLastKeyboardMode = KEYBOARD_IS_HIDDEN;
private static final int KEYBOARD_IS_HIDDEN = -1;
+ // The rectangle region to ignore hover events.
+ private final Rect mBoundsToIgnoreHoverEvent = new Rect();
+
+ private final AccessibilityLongPressTimer mAccessibilityLongPressTimer;
public MainKeyboardAccessibilityDelegate(final MainKeyboardView mainKeyboardView,
final KeyDetector keyDetector) {
super(mainKeyboardView, keyDetector);
+ mAccessibilityLongPressTimer = new AccessibilityLongPressTimer(
+ this /* callback */, mainKeyboardView.getContext());
}
/**
@@ -142,14 +156,28 @@ public final class MainKeyboardAccessibilityDelegate
case KeyboardId.ELEMENT_ALPHABET:
if (lastElementId == KeyboardId.ELEMENT_ALPHABET
|| lastElementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) {
+ // Transition between alphabet mode and automatic shifted mode should be silently
+ // ignored because it can be determined by each key's talk back announce.
return;
}
resId = R.string.spoken_description_mode_alpha;
break;
case KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED:
+ if (lastElementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) {
+ // Resetting automatic shifted mode by pressing the shift key causes the transition
+ // from automatic shifted to manual shifted that should be silently ignored.
+ return;
+ }
resId = R.string.spoken_description_shiftmode_on;
break;
case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED:
+ if (lastElementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED) {
+ // Resetting caps locked mode by pressing the shift key causes the transition
+ // from shift locked to shift lock shifted that should be silently ignored.
+ return;
+ }
+ resId = R.string.spoken_description_shiftmode_locked;
+ break;
case KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED:
resId = R.string.spoken_description_shiftmode_locked;
break;
@@ -168,17 +196,108 @@ public final class MainKeyboardAccessibilityDelegate
default:
return;
}
- final String text = mKeyboardView.getContext().getString(resId);
- sendWindowStateChanged(text);
+ sendWindowStateChanged(resId);
}
/**
* Announces that the keyboard has been hidden.
*/
private void announceKeyboardHidden() {
- final Context context = mKeyboardView.getContext();
- final String text = context.getString(R.string.announce_keyboard_hidden);
+ sendWindowStateChanged(R.string.announce_keyboard_hidden);
+ }
- sendWindowStateChanged(text);
+ @Override
+ protected void onRegisterHoverKey(final Key key, final MotionEvent event) {
+ final int x = key.getHitBox().centerX();
+ final int y = key.getHitBox().centerY();
+ if (DEBUG_HOVER) {
+ Log.d(TAG, "onRegisterHoverKey: key=" + key
+ + " inIgnoreBounds=" + mBoundsToIgnoreHoverEvent.contains(x, y));
+ }
+ if (mBoundsToIgnoreHoverEvent.contains(x, y)) {
+ // This hover exit event points to the key that should be ignored.
+ // Clear the ignoring region to handle further hover events.
+ mBoundsToIgnoreHoverEvent.setEmpty();
+ return;
+ }
+ super.onRegisterHoverKey(key, event);
+ }
+
+ @Override
+ protected void onHoverEnterTo(final Key key) {
+ final int x = key.getHitBox().centerX();
+ final int y = key.getHitBox().centerY();
+ if (DEBUG_HOVER) {
+ Log.d(TAG, "onHoverEnterTo: key=" + key
+ + " inIgnoreBounds=" + mBoundsToIgnoreHoverEvent.contains(x, y));
+ }
+ mAccessibilityLongPressTimer.cancelLongPress();
+ if (mBoundsToIgnoreHoverEvent.contains(x, y)) {
+ return;
+ }
+ // This hover enter event points to the key that isn't in the ignoring region.
+ // Further hover events should be handled.
+ mBoundsToIgnoreHoverEvent.setEmpty();
+ super.onHoverEnterTo(key);
+ if (key.isLongPressEnabled()) {
+ mAccessibilityLongPressTimer.startLongPress(key);
+ }
+ }
+
+ @Override
+ protected void onHoverExitFrom(final Key key) {
+ final int x = key.getHitBox().centerX();
+ final int y = key.getHitBox().centerY();
+ if (DEBUG_HOVER) {
+ Log.d(TAG, "onHoverExitFrom: key=" + key
+ + " inIgnoreBounds=" + mBoundsToIgnoreHoverEvent.contains(x, y));
+ }
+ mAccessibilityLongPressTimer.cancelLongPress();
+ super.onHoverExitFrom(key);
+ }
+
+ @Override
+ public void onLongPressed(final Key key) {
+ if (DEBUG_HOVER) {
+ Log.d(TAG, "onLongPressed: key=" + key);
+ }
+ final PointerTracker tracker = PointerTracker.getPointerTracker(HOVER_EVENT_POINTER_ID);
+ final long eventTime = SystemClock.uptimeMillis();
+ final int x = key.getHitBox().centerX();
+ final int y = key.getHitBox().centerY();
+ final MotionEvent downEvent = MotionEvent.obtain(
+ eventTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0 /* metaState */);
+ // Inject a fake down event to {@link PointerTracker} to handle a long press correctly.
+ tracker.processMotionEvent(downEvent, mKeyDetector);
+ // The above fake down event triggers an unnecessary long press timer that should be
+ // canceled.
+ tracker.cancelLongPressTimer();
+ downEvent.recycle();
+ // Invoke {@link MainKeyboardView#onLongPress(PointerTracker)} as if a long press timeout
+ // has passed.
+ mKeyboardView.onLongPress(tracker);
+ // If {@link Key#hasNoPanelAutoMoreKeys()} is true (such as "0 +" key on the phone layout)
+ // or a key invokes IME switcher dialog, we should just ignore the next
+ // {@link #onRegisterHoverKey(Key,MotionEvent)}. It can be determined by whether
+ // {@link PointerTracker} is in operation or not.
+ if (tracker.isInOperation()) {
+ // This long press shows a more keys keyboard and further hover events should be
+ // handled.
+ mBoundsToIgnoreHoverEvent.setEmpty();
+ return;
+ }
+ // This long press has handled at {@link MainKeyboardView#onLongPress(PointerTracker)}.
+ // We should ignore further hover events on this key.
+ mBoundsToIgnoreHoverEvent.set(key.getHitBox());
+ if (key.hasNoPanelAutoMoreKey()) {
+ // This long press has registered a code point without showing a more keys keyboard.
+ // We should talk back the code point if possible.
+ final int codePointOfNoPanelAutoMoreKey = key.getMoreKeys()[0].mCode;
+ final String text = KeyCodeDescriptionMapper.getInstance().getDescriptionForCodePoint(
+ mKeyboardView.getContext(), codePointOfNoPanelAutoMoreKey);
+ if (text != null) {
+ sendWindowStateChanged(text);
+ }
+ }
}
}