Loading java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java +42 −1 Original line number Diff line number Diff line Loading @@ -16,11 +16,15 @@ package com.android.inputmethod.accessibility; import android.content.Context; import android.content.SharedPreferences; import android.inputmethodservice.InputMethodService; import android.media.AudioManager; import android.os.Looper; import android.os.Message; import android.os.Vibrator; import android.text.TextUtils; import android.view.KeyEvent; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; Loading @@ -38,8 +42,14 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi */ private static final long DELAY_NO_HOVER_SELECTION = 250; private InputMethodService mInputMethod; /** * Duration of the key click vibration in milliseconds. */ private static final long VIBRATE_KEY_CLICK = 50; private InputMethodService mInputMethod; private Vibrator mVibrator; private AudioManager mAudioManager; private AccessibilityHandler mAccessibilityHandler; private static class AccessibilityHandler Loading Loading @@ -84,6 +94,8 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi private void initInternal(InputMethodService inputMethod, SharedPreferences prefs) { mInputMethod = inputMethod; mVibrator = (Vibrator) inputMethod.getSystemService(Context.VIBRATOR_SERVICE); mAudioManager = (AudioManager) inputMethod.getSystemService(Context.AUDIO_SERVICE); mAccessibilityHandler = new AccessibilityHandler(this, inputMethod.getMainLooper()); } Loading @@ -106,6 +118,35 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi mAccessibilityHandler.postNoHoverSelection(); } /** * Handle flick gestures by mapping them to directional pad keys. */ @Override public void onFlickGesture(int direction) { final int keyEventCode; switch (direction) { case FlickGestureDetector.FLICK_LEFT: sendDownUpKeyEvents(KeyEvent.KEYCODE_DPAD_LEFT); break; case FlickGestureDetector.FLICK_RIGHT: sendDownUpKeyEvents(KeyEvent.KEYCODE_DPAD_RIGHT); break; } } /** * Provide haptic feedback and send the specified keyCode to the input * connection as a pair of down/up events. * * @param keyCode */ private void sendDownUpKeyEvents(int keyCode) { mVibrator.vibrate(VIBRATE_KEY_CLICK); mAudioManager.playSoundEffect(AudioManager.FX_KEY_CLICK); mInputMethod.sendDownUpKeyEvents(keyCode); } /** * When Accessibility is turned on, notifies the user that they are not * currently hovering above a key. By default this will speak the currently Loading java/src/com/android/inputmethod/accessibility/AccessibleKeyboardActionListener.java +11 −0 Original line number Diff line number Diff line Loading @@ -34,4 +34,15 @@ public interface AccessibleKeyboardActionListener { * @param primaryCode the code of the key that was hovered over */ public void onHoverExit(int primaryCode); /** * @param direction the direction of the flick gesture, one of * <ul> * <li>{@link FlickGestureDetector#FLICK_UP} * <li>{@link FlickGestureDetector#FLICK_DOWN} * <li>{@link FlickGestureDetector#FLICK_LEFT} * <li>{@link FlickGestureDetector#FLICK_RIGHT} * </ul> */ public void onFlickGesture(int direction); } java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java +21 −2 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ public class AccessibleKeyboardViewProxy { private int mScaledEdgeSlop; private KeyboardView mView; private AccessibleKeyboardActionListener mListener; private FlickGestureDetector mGestureDetector; private int mLastHoverKeyIndex = KeyDetector.NOT_A_KEY; private int mLastX = -1; Loading Loading @@ -71,6 +72,7 @@ public class AccessibleKeyboardViewProxy { paint.setAntiAlias(true); paint.setColor(Color.YELLOW); mGestureDetector = new KeyboardFlickGestureDetector(context); mScaledEdgeSlop = ViewConfiguration.get(context).getScaledEdgeSlop(); } Loading Loading @@ -110,7 +112,10 @@ public class AccessibleKeyboardViewProxy { * @return {@code true} if the event is handled */ public boolean onHoverEvent(MotionEvent event, PointerTracker tracker) { return onTouchExplorationEvent(event, tracker); if (mGestureDetector.onHoverEvent(event, this, tracker)) return true; return onHoverEventInternal(event, tracker); } public boolean dispatchTouchEvent(MotionEvent event) { Loading @@ -128,7 +133,7 @@ public class AccessibleKeyboardViewProxy { * @param event The touch exploration hover event. * @return {@code true} if the event was handled */ private boolean onTouchExplorationEvent(MotionEvent event, PointerTracker tracker) { /*package*/ boolean onHoverEventInternal(MotionEvent event, PointerTracker tracker) { final int x = (int) event.getX(); final int y = (int) event.getY(); Loading Loading @@ -198,4 +203,18 @@ public class AccessibleKeyboardViewProxy { tracker.onDownEvent(x, y, eventTime, null); tracker.onUpEvent(x, y, eventTime + DELAY_KEY_PRESS, null); } private class KeyboardFlickGestureDetector extends FlickGestureDetector { public KeyboardFlickGestureDetector(Context context) { super(context); } @Override public boolean onFlick(MotionEvent e1, MotionEvent e2, int direction) { if (mListener != null) { mListener.onFlickGesture(direction); } return true; } } } java/src/com/android/inputmethod/accessibility/FlickGestureDetector.java 0 → 100644 +227 −0 Original line number Diff line number Diff line /* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.inputmethod.accessibility; import android.content.Context; import android.os.Message; import android.view.MotionEvent; import android.view.ViewConfiguration; import com.android.inputmethod.compat.MotionEventCompatUtils; import com.android.inputmethod.keyboard.PointerTracker; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; /** * Detects flick gestures within a stream of hover events. * <p> * A flick gesture is defined as a stream of hover events with the following * properties: * <ul> * <li>Begins with a {@link MotionEventCompatUtils#ACTION_HOVER_ENTER} event * <li>Contains any number of {@link MotionEventCompatUtils#ACTION_HOVER_MOVE} * events * <li>Ends with a {@link MotionEventCompatUtils#ACTION_HOVER_EXIT} event * <li>Maximum duration of 250 milliseconds * <li>Minimum distance between enter and exit points must be at least equal to * scaled double tap slop (see * {@link ViewConfiguration#getScaledDoubleTapSlop()}) * </ul> * <p> * Initial enter events are intercepted and cached until the stream fails to * satisfy the constraints defined above, at which point the cached enter event * is sent to its source {@link AccessibleKeyboardViewProxy} and subsequent move * and exit events are ignored. */ public abstract class FlickGestureDetector { public static final int FLICK_UP = 0; public static final int FLICK_RIGHT = 1; public static final int FLICK_LEFT = 2; public static final int FLICK_DOWN = 3; private final FlickHandler mFlickHandler; private final int mFlickRadiusSquare; private AccessibleKeyboardViewProxy mCachedView; private PointerTracker mCachedTracker; private MotionEvent mCachedHoverEnter; private static class FlickHandler extends StaticInnerHandlerWrapper<FlickGestureDetector> { private static final int MSG_FLICK_TIMEOUT = 1; /** The maximum duration of a flick gesture in milliseconds. */ private static final int DELAY_FLICK_TIMEOUT = 250; public FlickHandler(FlickGestureDetector outerInstance) { super(outerInstance); } @Override public void handleMessage(Message msg) { final FlickGestureDetector gestureDetector = getOuterInstance(); switch (msg.what) { case MSG_FLICK_TIMEOUT: gestureDetector.clearFlick(true); } } public void startFlickTimeout() { cancelFlickTimeout(); sendEmptyMessageDelayed(MSG_FLICK_TIMEOUT, DELAY_FLICK_TIMEOUT); } public void cancelFlickTimeout() { removeMessages(MSG_FLICK_TIMEOUT); } } /** * Creates a new flick gesture detector. * * @param context The parent context. */ public FlickGestureDetector(Context context) { final int doubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop(); mFlickHandler = new FlickHandler(this); mFlickRadiusSquare = doubleTapSlop * doubleTapSlop; } /** * Processes motion events to detect flick gestures. * * @param event The current event. * @param view The source of the event. * @param tracker A pointer tracker for the event. * @return {@code true} if the event was handled. */ public boolean onHoverEvent(MotionEvent event, AccessibleKeyboardViewProxy view, PointerTracker tracker) { // Always cache and consume the first hover event. if (event.getAction() == MotionEventCompatUtils.ACTION_HOVER_ENTER) { mCachedView = view; mCachedTracker = tracker; mCachedHoverEnter = MotionEvent.obtain(event); mFlickHandler.startFlickTimeout(); return true; } // Stop if the event has already been canceled. if (mCachedHoverEnter == null) { return false; } final float distanceSquare = calculateDistanceSquare(mCachedHoverEnter, event); final long timeout = event.getEventTime() - mCachedHoverEnter.getEventTime(); switch (event.getAction()) { case MotionEventCompatUtils.ACTION_HOVER_MOVE: // Consume all valid move events before timeout. return true; case MotionEventCompatUtils.ACTION_HOVER_EXIT: // Ignore exit events outside the flick radius. if (distanceSquare < mFlickRadiusSquare) { clearFlick(true); return false; } else { return dispatchFlick(mCachedHoverEnter, event); } default: return false; } } /** * Clears the cached flick information and optionally forwards the event to * the source view's internal hover event handler. * * @param sendCachedEvent Set to {@code true} to forward the hover event to * the source view. */ private void clearFlick(boolean sendCachedEvent) { mFlickHandler.cancelFlickTimeout(); if (mCachedHoverEnter != null) { if (sendCachedEvent) { mCachedView.onHoverEventInternal(mCachedHoverEnter, mCachedTracker); } mCachedHoverEnter.recycle(); mCachedHoverEnter = null; } mCachedTracker = null; mCachedView = null; } /** * Computes the direction of a flick gesture and forwards it to * {@link #onFlick(MotionEvent, MotionEvent, int)} for handling. * * @param e1 The {@link MotionEventCompatUtils#ACTION_HOVER_ENTER} event * where the flick started. * @param e2 The {@link MotionEventCompatUtils#ACTION_HOVER_EXIT} event * where the flick ended. * @return {@code true} if the flick event was handled. */ private boolean dispatchFlick(MotionEvent e1, MotionEvent e2) { clearFlick(false); final float dX = e2.getX() - e1.getX(); final float dY = e2.getY() - e1.getY(); final int direction; if (dY > dX) { if (dY > -dX) { direction = FLICK_DOWN; } else { direction = FLICK_LEFT; } } else { if (dY > -dX) { direction = FLICK_RIGHT; } else { direction = FLICK_UP; } } return onFlick(e1, e2, direction); } private float calculateDistanceSquare(MotionEvent e1, MotionEvent e2) { final float dX = e2.getX() - e1.getX(); final float dY = e2.getY() - e1.getY(); return (dX * dX) + (dY * dY); } /** * Handles a detected flick gesture. * * @param e1 The {@link MotionEventCompatUtils#ACTION_HOVER_ENTER} event * where the flick started. * @param e2 The {@link MotionEventCompatUtils#ACTION_HOVER_EXIT} event * where the flick ended. * @param direction The direction of the flick event, one of: * <ul> * <li>{@link #FLICK_UP} * <li>{@link #FLICK_DOWN} * <li>{@link #FLICK_LEFT} * <li>{@link #FLICK_RIGHT} * </ul> * @return {@code true} if the flick event was handled. */ public abstract boolean onFlick(MotionEvent e1, MotionEvent e2, int direction); } Loading
java/src/com/android/inputmethod/accessibility/AccessibleInputMethodServiceProxy.java +42 −1 Original line number Diff line number Diff line Loading @@ -16,11 +16,15 @@ package com.android.inputmethod.accessibility; import android.content.Context; import android.content.SharedPreferences; import android.inputmethodservice.InputMethodService; import android.media.AudioManager; import android.os.Looper; import android.os.Message; import android.os.Vibrator; import android.text.TextUtils; import android.view.KeyEvent; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; Loading @@ -38,8 +42,14 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi */ private static final long DELAY_NO_HOVER_SELECTION = 250; private InputMethodService mInputMethod; /** * Duration of the key click vibration in milliseconds. */ private static final long VIBRATE_KEY_CLICK = 50; private InputMethodService mInputMethod; private Vibrator mVibrator; private AudioManager mAudioManager; private AccessibilityHandler mAccessibilityHandler; private static class AccessibilityHandler Loading Loading @@ -84,6 +94,8 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi private void initInternal(InputMethodService inputMethod, SharedPreferences prefs) { mInputMethod = inputMethod; mVibrator = (Vibrator) inputMethod.getSystemService(Context.VIBRATOR_SERVICE); mAudioManager = (AudioManager) inputMethod.getSystemService(Context.AUDIO_SERVICE); mAccessibilityHandler = new AccessibilityHandler(this, inputMethod.getMainLooper()); } Loading @@ -106,6 +118,35 @@ public class AccessibleInputMethodServiceProxy implements AccessibleKeyboardActi mAccessibilityHandler.postNoHoverSelection(); } /** * Handle flick gestures by mapping them to directional pad keys. */ @Override public void onFlickGesture(int direction) { final int keyEventCode; switch (direction) { case FlickGestureDetector.FLICK_LEFT: sendDownUpKeyEvents(KeyEvent.KEYCODE_DPAD_LEFT); break; case FlickGestureDetector.FLICK_RIGHT: sendDownUpKeyEvents(KeyEvent.KEYCODE_DPAD_RIGHT); break; } } /** * Provide haptic feedback and send the specified keyCode to the input * connection as a pair of down/up events. * * @param keyCode */ private void sendDownUpKeyEvents(int keyCode) { mVibrator.vibrate(VIBRATE_KEY_CLICK); mAudioManager.playSoundEffect(AudioManager.FX_KEY_CLICK); mInputMethod.sendDownUpKeyEvents(keyCode); } /** * When Accessibility is turned on, notifies the user that they are not * currently hovering above a key. By default this will speak the currently Loading
java/src/com/android/inputmethod/accessibility/AccessibleKeyboardActionListener.java +11 −0 Original line number Diff line number Diff line Loading @@ -34,4 +34,15 @@ public interface AccessibleKeyboardActionListener { * @param primaryCode the code of the key that was hovered over */ public void onHoverExit(int primaryCode); /** * @param direction the direction of the flick gesture, one of * <ul> * <li>{@link FlickGestureDetector#FLICK_UP} * <li>{@link FlickGestureDetector#FLICK_DOWN} * <li>{@link FlickGestureDetector#FLICK_LEFT} * <li>{@link FlickGestureDetector#FLICK_RIGHT} * </ul> */ public void onFlickGesture(int direction); }
java/src/com/android/inputmethod/accessibility/AccessibleKeyboardViewProxy.java +21 −2 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ public class AccessibleKeyboardViewProxy { private int mScaledEdgeSlop; private KeyboardView mView; private AccessibleKeyboardActionListener mListener; private FlickGestureDetector mGestureDetector; private int mLastHoverKeyIndex = KeyDetector.NOT_A_KEY; private int mLastX = -1; Loading Loading @@ -71,6 +72,7 @@ public class AccessibleKeyboardViewProxy { paint.setAntiAlias(true); paint.setColor(Color.YELLOW); mGestureDetector = new KeyboardFlickGestureDetector(context); mScaledEdgeSlop = ViewConfiguration.get(context).getScaledEdgeSlop(); } Loading Loading @@ -110,7 +112,10 @@ public class AccessibleKeyboardViewProxy { * @return {@code true} if the event is handled */ public boolean onHoverEvent(MotionEvent event, PointerTracker tracker) { return onTouchExplorationEvent(event, tracker); if (mGestureDetector.onHoverEvent(event, this, tracker)) return true; return onHoverEventInternal(event, tracker); } public boolean dispatchTouchEvent(MotionEvent event) { Loading @@ -128,7 +133,7 @@ public class AccessibleKeyboardViewProxy { * @param event The touch exploration hover event. * @return {@code true} if the event was handled */ private boolean onTouchExplorationEvent(MotionEvent event, PointerTracker tracker) { /*package*/ boolean onHoverEventInternal(MotionEvent event, PointerTracker tracker) { final int x = (int) event.getX(); final int y = (int) event.getY(); Loading Loading @@ -198,4 +203,18 @@ public class AccessibleKeyboardViewProxy { tracker.onDownEvent(x, y, eventTime, null); tracker.onUpEvent(x, y, eventTime + DELAY_KEY_PRESS, null); } private class KeyboardFlickGestureDetector extends FlickGestureDetector { public KeyboardFlickGestureDetector(Context context) { super(context); } @Override public boolean onFlick(MotionEvent e1, MotionEvent e2, int direction) { if (mListener != null) { mListener.onFlickGesture(direction); } return true; } } }
java/src/com/android/inputmethod/accessibility/FlickGestureDetector.java 0 → 100644 +227 −0 Original line number Diff line number Diff line /* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.inputmethod.accessibility; import android.content.Context; import android.os.Message; import android.view.MotionEvent; import android.view.ViewConfiguration; import com.android.inputmethod.compat.MotionEventCompatUtils; import com.android.inputmethod.keyboard.PointerTracker; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; /** * Detects flick gestures within a stream of hover events. * <p> * A flick gesture is defined as a stream of hover events with the following * properties: * <ul> * <li>Begins with a {@link MotionEventCompatUtils#ACTION_HOVER_ENTER} event * <li>Contains any number of {@link MotionEventCompatUtils#ACTION_HOVER_MOVE} * events * <li>Ends with a {@link MotionEventCompatUtils#ACTION_HOVER_EXIT} event * <li>Maximum duration of 250 milliseconds * <li>Minimum distance between enter and exit points must be at least equal to * scaled double tap slop (see * {@link ViewConfiguration#getScaledDoubleTapSlop()}) * </ul> * <p> * Initial enter events are intercepted and cached until the stream fails to * satisfy the constraints defined above, at which point the cached enter event * is sent to its source {@link AccessibleKeyboardViewProxy} and subsequent move * and exit events are ignored. */ public abstract class FlickGestureDetector { public static final int FLICK_UP = 0; public static final int FLICK_RIGHT = 1; public static final int FLICK_LEFT = 2; public static final int FLICK_DOWN = 3; private final FlickHandler mFlickHandler; private final int mFlickRadiusSquare; private AccessibleKeyboardViewProxy mCachedView; private PointerTracker mCachedTracker; private MotionEvent mCachedHoverEnter; private static class FlickHandler extends StaticInnerHandlerWrapper<FlickGestureDetector> { private static final int MSG_FLICK_TIMEOUT = 1; /** The maximum duration of a flick gesture in milliseconds. */ private static final int DELAY_FLICK_TIMEOUT = 250; public FlickHandler(FlickGestureDetector outerInstance) { super(outerInstance); } @Override public void handleMessage(Message msg) { final FlickGestureDetector gestureDetector = getOuterInstance(); switch (msg.what) { case MSG_FLICK_TIMEOUT: gestureDetector.clearFlick(true); } } public void startFlickTimeout() { cancelFlickTimeout(); sendEmptyMessageDelayed(MSG_FLICK_TIMEOUT, DELAY_FLICK_TIMEOUT); } public void cancelFlickTimeout() { removeMessages(MSG_FLICK_TIMEOUT); } } /** * Creates a new flick gesture detector. * * @param context The parent context. */ public FlickGestureDetector(Context context) { final int doubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop(); mFlickHandler = new FlickHandler(this); mFlickRadiusSquare = doubleTapSlop * doubleTapSlop; } /** * Processes motion events to detect flick gestures. * * @param event The current event. * @param view The source of the event. * @param tracker A pointer tracker for the event. * @return {@code true} if the event was handled. */ public boolean onHoverEvent(MotionEvent event, AccessibleKeyboardViewProxy view, PointerTracker tracker) { // Always cache and consume the first hover event. if (event.getAction() == MotionEventCompatUtils.ACTION_HOVER_ENTER) { mCachedView = view; mCachedTracker = tracker; mCachedHoverEnter = MotionEvent.obtain(event); mFlickHandler.startFlickTimeout(); return true; } // Stop if the event has already been canceled. if (mCachedHoverEnter == null) { return false; } final float distanceSquare = calculateDistanceSquare(mCachedHoverEnter, event); final long timeout = event.getEventTime() - mCachedHoverEnter.getEventTime(); switch (event.getAction()) { case MotionEventCompatUtils.ACTION_HOVER_MOVE: // Consume all valid move events before timeout. return true; case MotionEventCompatUtils.ACTION_HOVER_EXIT: // Ignore exit events outside the flick radius. if (distanceSquare < mFlickRadiusSquare) { clearFlick(true); return false; } else { return dispatchFlick(mCachedHoverEnter, event); } default: return false; } } /** * Clears the cached flick information and optionally forwards the event to * the source view's internal hover event handler. * * @param sendCachedEvent Set to {@code true} to forward the hover event to * the source view. */ private void clearFlick(boolean sendCachedEvent) { mFlickHandler.cancelFlickTimeout(); if (mCachedHoverEnter != null) { if (sendCachedEvent) { mCachedView.onHoverEventInternal(mCachedHoverEnter, mCachedTracker); } mCachedHoverEnter.recycle(); mCachedHoverEnter = null; } mCachedTracker = null; mCachedView = null; } /** * Computes the direction of a flick gesture and forwards it to * {@link #onFlick(MotionEvent, MotionEvent, int)} for handling. * * @param e1 The {@link MotionEventCompatUtils#ACTION_HOVER_ENTER} event * where the flick started. * @param e2 The {@link MotionEventCompatUtils#ACTION_HOVER_EXIT} event * where the flick ended. * @return {@code true} if the flick event was handled. */ private boolean dispatchFlick(MotionEvent e1, MotionEvent e2) { clearFlick(false); final float dX = e2.getX() - e1.getX(); final float dY = e2.getY() - e1.getY(); final int direction; if (dY > dX) { if (dY > -dX) { direction = FLICK_DOWN; } else { direction = FLICK_LEFT; } } else { if (dY > -dX) { direction = FLICK_RIGHT; } else { direction = FLICK_UP; } } return onFlick(e1, e2, direction); } private float calculateDistanceSquare(MotionEvent e1, MotionEvent e2) { final float dX = e2.getX() - e1.getX(); final float dY = e2.getY() - e1.getY(); return (dX * dX) + (dY * dY); } /** * Handles a detected flick gesture. * * @param e1 The {@link MotionEventCompatUtils#ACTION_HOVER_ENTER} event * where the flick started. * @param e2 The {@link MotionEventCompatUtils#ACTION_HOVER_EXIT} event * where the flick ended. * @param direction The direction of the flick event, one of: * <ul> * <li>{@link #FLICK_UP} * <li>{@link #FLICK_DOWN} * <li>{@link #FLICK_LEFT} * <li>{@link #FLICK_RIGHT} * </ul> * @return {@code true} if the flick event was handled. */ public abstract boolean onFlick(MotionEvent e1, MotionEvent e2, int direction); }