Support performAccessibilityAction for CLICK and LONG_CLICK

Bug: 15727335
Change-Id: I83274c1a9d3cf2e8237d1674fe915b7b2d222a53
This commit is contained in:
Tadashi G. Takaoka 2014-06-24 15:14:24 -07:00
parent c9c3ea0b68
commit 1e31672295
4 changed files with 47 additions and 27 deletions

View file

@ -26,7 +26,7 @@ import com.android.inputmethod.latin.R;
// Handling long press timer to show a more keys keyboard. // Handling long press timer to show a more keys keyboard.
final class AccessibilityLongPressTimer extends Handler { final class AccessibilityLongPressTimer extends Handler {
public interface LongPressTimerCallback { public interface LongPressTimerCallback {
public void onLongPressed(Key key); public void performLongClickOn(Key key);
} }
private static final int MSG_LONG_PRESS = 1; private static final int MSG_LONG_PRESS = 1;
@ -47,7 +47,7 @@ final class AccessibilityLongPressTimer extends Handler {
switch (msg.what) { switch (msg.what) {
case MSG_LONG_PRESS: case MSG_LONG_PRESS:
cancelLongPress(); cancelLongPress();
mCallback.onLongPressed((Key)msg.obj); mCallback.performLongClickOn((Key)msg.obj);
return; return;
default: default:
super.handleMessage(msg); super.handleMessage(msg);

View file

@ -17,6 +17,7 @@
package com.android.inputmethod.accessibility; package com.android.inputmethod.accessibility;
import android.content.Context; import android.content.Context;
import android.os.SystemClock;
import android.support.v4.view.AccessibilityDelegateCompat; import android.support.v4.view.AccessibilityDelegateCompat;
import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewCompat;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
@ -49,7 +50,7 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView>
protected final KV mKeyboardView; protected final KV mKeyboardView;
protected final KeyDetector mKeyDetector; protected final KeyDetector mKeyDetector;
private Keyboard mKeyboard; private Keyboard mKeyboard;
private KeyboardAccessibilityNodeProvider mAccessibilityNodeProvider; private KeyboardAccessibilityNodeProvider<KV> mAccessibilityNodeProvider;
private Key mLastHoverKey; private Key mLastHoverKey;
public static final int HOVER_EVENT_POINTER_ID = 0; public static final int HOVER_EVENT_POINTER_ID = 0;
@ -132,19 +133,20 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView>
* @return The accessibility node provider for the current keyboard. * @return The accessibility node provider for the current keyboard.
*/ */
@Override @Override
public KeyboardAccessibilityNodeProvider getAccessibilityNodeProvider(final View host) { public KeyboardAccessibilityNodeProvider<KV> getAccessibilityNodeProvider(final View host) {
return getAccessibilityNodeProvider(); return getAccessibilityNodeProvider();
} }
/** /**
* @return A lazily-instantiated node provider for this view delegate. * @return A lazily-instantiated node provider for this view delegate.
*/ */
protected KeyboardAccessibilityNodeProvider getAccessibilityNodeProvider() { protected KeyboardAccessibilityNodeProvider<KV> getAccessibilityNodeProvider() {
// Instantiate the provide only when requested. Since the system // Instantiate the provide only when requested. Since the system
// will call this method multiple times it is a good practice to // will call this method multiple times it is a good practice to
// cache the provider instance. // cache the provider instance.
if (mAccessibilityNodeProvider == null) { if (mAccessibilityNodeProvider == null) {
mAccessibilityNodeProvider = new KeyboardAccessibilityNodeProvider(mKeyboardView); mAccessibilityNodeProvider =
new KeyboardAccessibilityNodeProvider<>(mKeyboardView, this);
} }
return mAccessibilityNodeProvider; return mAccessibilityNodeProvider;
} }
@ -241,35 +243,37 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView>
// Make sure we're not getting an EXIT event because the user slid // Make sure we're not getting an EXIT event because the user slid
// off the keyboard area, then force a key press. // off the keyboard area, then force a key press.
if (key != null) { if (key != null) {
onRegisterHoverKey(key, event); performClickOn(key);
onHoverExitFrom(key); onHoverExitFrom(key);
} }
setLastHoverKey(null); setLastHoverKey(null);
} }
/** /**
* Register a key that is selected by a hover event * Perform click on a key.
* *
* @param key A key to be registered. * @param key A key to be registered.
* @param event A hover exit event that triggers key registering.
*/ */
protected void onRegisterHoverKey(final Key key, final MotionEvent event) { public void performClickOn(final Key key) {
if (DEBUG_HOVER) { if (DEBUG_HOVER) {
Log.d(TAG, "onRegisterHoverKey: key=" + key); Log.d(TAG, "performClickOn: key=" + key);
} }
simulateTouchEvent(MotionEvent.ACTION_DOWN, event); simulateTouchEvent(MotionEvent.ACTION_DOWN, key);
simulateTouchEvent(MotionEvent.ACTION_UP, event); simulateTouchEvent(MotionEvent.ACTION_UP, key);
} }
/** /**
* Simulating a touch event by injecting a synthesized touch event into {@link KeyboardView}. * Simulating a touch event by injecting a synthesized touch event into {@link KeyboardView}.
* *
* @param touchAction The action of the synthesizing touch event. * @param touchAction The action of the synthesizing touch event.
* @param hoverEvent The base hover event from that the touch event is synthesized. * @param key The key that a synthesized touch event is on.
*/ */
private void simulateTouchEvent(final int touchAction, final MotionEvent hoverEvent) { private void simulateTouchEvent(final int touchAction, final Key key) {
final MotionEvent touchEvent = MotionEvent.obtain(hoverEvent); final int x = key.getHitBox().centerX();
touchEvent.setAction(touchAction); final int y = key.getHitBox().centerY();
final long eventTime = SystemClock.uptimeMillis();
final MotionEvent touchEvent = MotionEvent.obtain(
eventTime, eventTime, touchAction, x, y, 0 /* metaState */);
mKeyboardView.onTouchEvent(touchEvent); mKeyboardView.onTouchEvent(touchEvent);
touchEvent.recycle(); touchEvent.recycle();
} }
@ -285,7 +289,7 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView>
} }
key.onPressed(); key.onPressed();
mKeyboardView.invalidateKey(key); mKeyboardView.invalidateKey(key);
final KeyboardAccessibilityNodeProvider provider = getAccessibilityNodeProvider(); final KeyboardAccessibilityNodeProvider<KV> provider = getAccessibilityNodeProvider();
provider.onHoverEnterTo(key); provider.onHoverEnterTo(key);
provider.performActionForKey(key, AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS); provider.performActionForKey(key, AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS);
} }
@ -308,7 +312,16 @@ public class KeyboardAccessibilityDelegate<KV extends KeyboardView>
} }
key.onReleased(); key.onReleased();
mKeyboardView.invalidateKey(key); mKeyboardView.invalidateKey(key);
final KeyboardAccessibilityNodeProvider provider = getAccessibilityNodeProvider(); final KeyboardAccessibilityNodeProvider<KV> provider = getAccessibilityNodeProvider();
provider.onHoverExitFrom(key); provider.onHoverExitFrom(key);
} }
/**
* Perform long click on a key.
*
* @param key A key to be long pressed on.
*/
public void performLongClickOn(final Key key) {
// A extended class should override this method to implement long press.
}
} }

View file

@ -47,7 +47,8 @@ import java.util.List;
* virtual views, thus conveying their logical structure. * virtual views, thus conveying their logical structure.
* </p> * </p>
*/ */
final class KeyboardAccessibilityNodeProvider extends AccessibilityNodeProviderCompat { final class KeyboardAccessibilityNodeProvider<KV extends KeyboardView>
extends AccessibilityNodeProviderCompat {
private static final String TAG = KeyboardAccessibilityNodeProvider.class.getSimpleName(); private static final String TAG = KeyboardAccessibilityNodeProvider.class.getSimpleName();
// From {@link android.view.accessibility.AccessibilityNodeInfo#UNDEFINED_ITEM_ID}. // From {@link android.view.accessibility.AccessibilityNodeInfo#UNDEFINED_ITEM_ID}.
@ -69,16 +70,20 @@ final class KeyboardAccessibilityNodeProvider extends AccessibilityNodeProviderC
private int mHoveringNodeId = UNDEFINED; private int mHoveringNodeId = UNDEFINED;
/** The keyboard view to provide an accessibility node info. */ /** The keyboard view to provide an accessibility node info. */
private final KeyboardView mKeyboardView; private final KV mKeyboardView;
/** The accessibility delegate. */
private final KeyboardAccessibilityDelegate<KV> mDelegate;
/** The current keyboard. */ /** The current keyboard. */
private Keyboard mKeyboard; private Keyboard mKeyboard;
public KeyboardAccessibilityNodeProvider(final KeyboardView keyboardView) { public KeyboardAccessibilityNodeProvider(final KV keyboardView,
final KeyboardAccessibilityDelegate<KV> delegate) {
super(); super();
mKeyCodeDescriptionMapper = KeyCodeDescriptionMapper.getInstance(); mKeyCodeDescriptionMapper = KeyCodeDescriptionMapper.getInstance();
mAccessibilityUtils = AccessibilityUtils.getInstance(); mAccessibilityUtils = AccessibilityUtils.getInstance();
mKeyboardView = keyboardView; mKeyboardView = keyboardView;
mDelegate = delegate;
// Since this class is constructed lazily, we might not get a subsequent // Since this class is constructed lazily, we might not get a subsequent
// call to setKeyboard() and therefore need to call it now. // call to setKeyboard() and therefore need to call it now.
@ -287,9 +292,11 @@ final class KeyboardAccessibilityNodeProvider extends AccessibilityNodeProviderC
return true; return true;
case AccessibilityNodeInfoCompat.ACTION_CLICK: case AccessibilityNodeInfoCompat.ACTION_CLICK:
sendAccessibilityEventForKey(key, AccessibilityEvent.TYPE_VIEW_CLICKED); sendAccessibilityEventForKey(key, AccessibilityEvent.TYPE_VIEW_CLICKED);
mDelegate.performClickOn(key);
return true; return true;
case AccessibilityNodeInfoCompat.ACTION_LONG_CLICK: case AccessibilityNodeInfoCompat.ACTION_LONG_CLICK:
sendAccessibilityEventForKey(key, AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); sendAccessibilityEventForKey(key, AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
mDelegate.performLongClickOn(key);
return true; return true;
default: default:
return false; return false;

View file

@ -207,11 +207,11 @@ public final class MainKeyboardAccessibilityDelegate
} }
@Override @Override
protected void onRegisterHoverKey(final Key key, final MotionEvent event) { public void performClickOn(final Key key) {
final int x = key.getHitBox().centerX(); final int x = key.getHitBox().centerX();
final int y = key.getHitBox().centerY(); final int y = key.getHitBox().centerY();
if (DEBUG_HOVER) { if (DEBUG_HOVER) {
Log.d(TAG, "onRegisterHoverKey: key=" + key Log.d(TAG, "performClickOn: key=" + key
+ " inIgnoreBounds=" + mBoundsToIgnoreHoverEvent.contains(x, y)); + " inIgnoreBounds=" + mBoundsToIgnoreHoverEvent.contains(x, y));
} }
if (mBoundsToIgnoreHoverEvent.contains(x, y)) { if (mBoundsToIgnoreHoverEvent.contains(x, y)) {
@ -220,7 +220,7 @@ public final class MainKeyboardAccessibilityDelegate
mBoundsToIgnoreHoverEvent.setEmpty(); mBoundsToIgnoreHoverEvent.setEmpty();
return; return;
} }
super.onRegisterHoverKey(key, event); super.performClickOn(key);
} }
@Override @Override
@ -257,9 +257,9 @@ public final class MainKeyboardAccessibilityDelegate
} }
@Override @Override
public void onLongPressed(final Key key) { public void performLongClickOn(final Key key) {
if (DEBUG_HOVER) { if (DEBUG_HOVER) {
Log.d(TAG, "onLongPressed: key=" + key); Log.d(TAG, "performLongClickOn: key=" + key);
} }
final PointerTracker tracker = PointerTracker.getPointerTracker(HOVER_EVENT_POINTER_ID); final PointerTracker tracker = PointerTracker.getPointerTracker(HOVER_EVENT_POINTER_ID);
final long eventTime = SystemClock.uptimeMillis(); final long eventTime = SystemClock.uptimeMillis();