summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictoria Lease <violets@google.com>2012-08-24 13:46:02 -0700
committerVictoria Lease <violets@google.com>2012-09-10 14:01:42 -0700
commitb38070caa5143ab9fd1883e0c7c879533a480bc7 (patch)
treeffbed34eefd1fd81a028e1a14820d48953252b29
parent37ee53420ce47860807eb8eaeb454c12fa46797b (diff)
downloadframeworks_base-b38070caa5143ab9fd1883e0c7c879533a480bc7.zip
frameworks_base-b38070caa5143ab9fd1883e0c7c879533a480bc7.tar.gz
frameworks_base-b38070caa5143ab9fd1883e0c7c879533a480bc7.tar.bz2
IME support for trackball and generic motion events
Trackball and generic motion events now pass through the IME in case it would like to handle them before passing them on to the view hierarchy. While I was at it, I also... ...fixed the documentation on InputMethodService.onKeyUp() ...added documentation to InputMethodService.onTrackballEvent() ...added trackball and generic motion events to the "input" command ...fixed input consistency verification involving ACTION_OUTSIDE Bug: 7050005 Change-Id: I40ab68df4a9542af6df25de6ec2ec500e4c02902
-rw-r--r--api/current.txt3
-rwxr-xr-xcmds/input/src/com/android/commands/input/Input.java106
-rw-r--r--core/java/android/inputmethodservice/AbstractInputMethodService.java29
-rw-r--r--core/java/android/inputmethodservice/IInputMethodSessionWrapper.java16
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java25
-rw-r--r--core/java/android/view/InputEventConsistencyVerifier.java2
-rw-r--r--core/java/android/view/ViewRootImpl.java81
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java26
-rw-r--r--core/java/android/view/inputmethod/InputMethodSession.java15
-rw-r--r--core/java/com/android/internal/view/IInputMethodSession.aidl2
10 files changed, 271 insertions, 34 deletions
diff --git a/api/current.txt b/api/current.txt
index 7ad9cad..c394c99 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10215,6 +10215,7 @@ package android.inputmethodservice {
method public final android.os.IBinder onBind(android.content.Intent);
method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl onCreateInputMethodInterface();
method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
+ method public boolean onGenericMotionEvent(android.view.MotionEvent);
method public boolean onTrackballEvent(android.view.MotionEvent);
}
@@ -10227,6 +10228,7 @@ package android.inputmethodservice {
public abstract class AbstractInputMethodService.AbstractInputMethodSessionImpl implements android.view.inputmethod.InputMethodSession {
ctor public AbstractInputMethodService.AbstractInputMethodSessionImpl();
+ method public void dispatchGenericMotionEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback);
method public void dispatchKeyEvent(int, android.view.KeyEvent, android.view.inputmethod.InputMethodSession.EventCallback);
method public void dispatchTrackballEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback);
method public boolean isEnabled();
@@ -26692,6 +26694,7 @@ package android.view.inputmethod {
public abstract interface InputMethodSession {
method public abstract void appPrivateCommand(java.lang.String, android.os.Bundle);
+ method public abstract void dispatchGenericMotionEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback);
method public abstract void dispatchKeyEvent(int, android.view.KeyEvent, android.view.inputmethod.InputMethodSession.EventCallback);
method public abstract void dispatchTrackballEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback);
method public abstract void displayCompletions(android.view.inputmethod.CompletionInfo[]);
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index 341f30f..a21df0d 100755
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -66,15 +66,54 @@ public class Input {
}
} else if (command.equals("tap")) {
if (args.length == 3) {
- sendTap(Float.parseFloat(args[1]), Float.parseFloat(args[2]));
+ sendTap(InputDevice.SOURCE_TOUCHSCREEN, Float.parseFloat(args[1]), Float.parseFloat(args[2]));
return;
}
} else if (command.equals("swipe")) {
if (args.length == 5) {
- sendSwipe(Float.parseFloat(args[1]), Float.parseFloat(args[2]),
+ sendSwipe(InputDevice.SOURCE_TOUCHSCREEN, Float.parseFloat(args[1]), Float.parseFloat(args[2]),
Float.parseFloat(args[3]), Float.parseFloat(args[4]));
return;
}
+ } else if (command.equals("touchscreen") || command.equals("touchpad")) {
+ // determine input source
+ int inputSource = InputDevice.SOURCE_TOUCHSCREEN;
+ if (command.equals("touchpad")) {
+ inputSource = InputDevice.SOURCE_TOUCHPAD;
+ }
+ // determine subcommand
+ if (args.length > 1) {
+ String subcommand = args[1];
+ if (subcommand.equals("tap")) {
+ if (args.length == 4) {
+ sendTap(inputSource, Float.parseFloat(args[2]),
+ Float.parseFloat(args[3]));
+ return;
+ }
+ } else if (subcommand.equals("swipe")) {
+ if (args.length == 6) {
+ sendSwipe(inputSource, Float.parseFloat(args[2]),
+ Float.parseFloat(args[3]), Float.parseFloat(args[4]),
+ Float.parseFloat(args[5]));
+ return;
+ }
+ }
+ }
+ } else if (command.equals("trackball")) {
+ // determine subcommand
+ if (args.length > 1) {
+ String subcommand = args[1];
+ if (subcommand.equals("press")) {
+ sendTap(InputDevice.SOURCE_TRACKBALL, 0.0f, 0.0f);
+ return;
+ } else if (subcommand.equals("roll")) {
+ if (args.length == 4) {
+ sendMove(InputDevice.SOURCE_TRACKBALL, Float.parseFloat(args[2]),
+ Float.parseFloat(args[3]));
+ return;
+ }
+ }
+ }
} else {
System.err.println("Error: Unknown command: " + command);
showUsage();
@@ -127,33 +166,64 @@ public class Input {
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
}
- private void sendTap(float x, float y) {
+ private void sendTap(int inputSource, float x, float y) {
long now = SystemClock.uptimeMillis();
- injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, x, y, 0));
- injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, x, y, 0));
+ injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x, y, 1.0f);
+ injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x, y, 0.0f);
}
- private void sendSwipe(float x1, float y1, float x2, float y2) {
+ private void sendSwipe(int inputSource, float x1, float y1, float x2, float y2) {
final int NUM_STEPS = 11;
long now = SystemClock.uptimeMillis();
- injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, x1, y1, 0));
+ injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f);
for (int i = 1; i < NUM_STEPS; i++) {
- float alpha = (float)i / NUM_STEPS;
- injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_MOVE,
- lerp(x1, x2, alpha), lerp(y1, y2, alpha), 0));
+ float alpha = (float) i / NUM_STEPS;
+ injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha),
+ lerp(y1, y2, alpha), 1.0f);
}
- injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, x2, y2, 0));
+ injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x1, y1, 0.0f);
+ }
+
+ /**
+ * Sends a simple zero-pressure move event.
+ *
+ * @param inputSource the InputDevice.SOURCE_* sending the input event
+ * @param dx change in x coordinate due to move
+ * @param dy change in y coordinate due to move
+ */
+ private void sendMove(int inputSource, float dx, float dy) {
+ long now = SystemClock.uptimeMillis();
+ injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, dx, dy, 0.0f);
}
private void injectKeyEvent(KeyEvent event) {
- Log.i(TAG, "InjectKeyEvent: " + event);
+ Log.i(TAG, "injectKeyEvent: " + event);
InputManager.getInstance().injectInputEvent(event,
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
- private void injectPointerEvent(MotionEvent event) {
- event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
- Log.i("Input", "InjectPointerEvent: " + event);
+ /**
+ * Builds a MotionEvent and injects it into the event stream.
+ *
+ * @param inputSource the InputDevice.SOURCE_* sending the input event
+ * @param action the MotionEvent.ACTION_* for the event
+ * @param when the value of SystemClock.uptimeMillis() at which the event happened
+ * @param x x coordinate of event
+ * @param y y coordinate of event
+ * @param pressure pressure of event
+ */
+ private void injectMotionEvent(int inputSource, int action, long when, float x, float y, float pressure) {
+ final float DEFAULT_SIZE = 1.0f;
+ final int DEFAULT_META_STATE = 0;
+ final float DEFAULT_PRECISION_X = 1.0f;
+ final float DEFAULT_PRECISION_Y = 1.0f;
+ final int DEFAULT_DEVICE_ID = 0;
+ final int DEFAULT_EDGE_FLAGS = 0;
+ MotionEvent event = MotionEvent.obtain(when, when, action, x, y, pressure, DEFAULT_SIZE,
+ DEFAULT_META_STATE, DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y, DEFAULT_DEVICE_ID,
+ DEFAULT_EDGE_FLAGS);
+ event.setSource(inputSource);
+ Log.i("Input", "injectMotionEvent: " + event);
InputManager.getInstance().injectInputEvent(event,
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
}
@@ -166,7 +236,9 @@ public class Input {
System.err.println("usage: input ...");
System.err.println(" input text <string>");
System.err.println(" input keyevent <key code number or name>");
- System.err.println(" input tap <x> <y>");
- System.err.println(" input swipe <x1> <y1> <x2> <y2>");
+ System.err.println(" input [touchscreen|touchpad] tap <x> <y>");
+ System.err.println(" input [touchscreen|touchpad] swipe <x1> <y1> <x2> <y2>");
+ System.err.println(" input trackball press");
+ System.err.println(" input trackball roll <dx> <dy>");
}
}
diff --git a/core/java/android/inputmethodservice/AbstractInputMethodService.java b/core/java/android/inputmethodservice/AbstractInputMethodService.java
index 27af013..3c3182a 100644
--- a/core/java/android/inputmethodservice/AbstractInputMethodService.java
+++ b/core/java/android/inputmethodservice/AbstractInputMethodService.java
@@ -149,6 +149,17 @@ public abstract class AbstractInputMethodService extends Service
callback.finishedEvent(seq, handled);
}
}
+
+ /**
+ * Take care of dispatching incoming generic motion events to the appropriate
+ * callbacks on the service, and tell the client when this is done.
+ */
+ public void dispatchGenericMotionEvent(int seq, MotionEvent event, EventCallback callback) {
+ boolean handled = onGenericMotionEvent(event);
+ if (callback != null) {
+ callback.finishedEvent(seq, handled);
+ }
+ }
}
/**
@@ -189,7 +200,25 @@ public abstract class AbstractInputMethodService extends Service
return new IInputMethodWrapper(this, mInputMethod);
}
+ /**
+ * Implement this to handle trackball events on your input method.
+ *
+ * @param event The motion event being received.
+ * @return True if the event was handled in this function, false otherwise.
+ * @see View#onTrackballEvent
+ */
public boolean onTrackballEvent(MotionEvent event) {
return false;
}
+
+ /**
+ * Implement this to handle generic motion events on your input method.
+ *
+ * @param event The motion event being received.
+ * @return True if the event was handled in this function, false otherwise.
+ * @see View#onGenericMotionEvent
+ */
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ return false;
+ }
}
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index ce797d1..5324f81 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -43,6 +43,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
private static final int DO_UPDATE_EXTRACTED_TEXT = 67;
private static final int DO_DISPATCH_KEY_EVENT = 70;
private static final int DO_DISPATCH_TRACKBALL_EVENT = 80;
+ private static final int DO_DISPATCH_GENERIC_MOTION_EVENT = 85;
private static final int DO_UPDATE_SELECTION = 90;
private static final int DO_UPDATE_CURSOR = 95;
private static final int DO_APP_PRIVATE_COMMAND = 100;
@@ -109,6 +110,15 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
args.recycle();
return;
}
+ case DO_DISPATCH_GENERIC_MOTION_EVENT: {
+ SomeArgs args = (SomeArgs)msg.obj;
+ mInputMethodSession.dispatchGenericMotionEvent(msg.arg1,
+ (MotionEvent)args.arg1,
+ new InputMethodEventCallbackWrapper(
+ (IInputMethodCallback)args.arg2));
+ args.recycle();
+ return;
+ }
case DO_UPDATE_SELECTION: {
SomeArgs args = (SomeArgs)msg.obj;
mInputMethodSession.updateSelection(args.argi1, args.argi2,
@@ -167,6 +177,12 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
event, callback));
}
+ public void dispatchGenericMotionEvent(int seq, MotionEvent event,
+ IInputMethodCallback callback) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_DISPATCH_GENERIC_MOTION_EVENT, seq,
+ event, callback));
+ }
+
public void updateSelection(int oldSelStart, int oldSelEnd,
int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd) {
mCaller.executeOrSendMessage(mCaller.obtainMessageIIIIII(DO_UPDATE_SELECTION,
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index d5b9edc..cf3b802 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1773,7 +1773,7 @@ public class InputMethodService extends AbstractInputMethodService {
* Override this to intercept special key multiple events before they are
* processed by the
* application. If you return true, the application will not itself
- * process the event. If you return true, the normal application processing
+ * process the event. If you return false, the normal application processing
* will occur as if the IME had not seen the event at all.
*
* <p>The default implementation always returns false, except when
@@ -1788,7 +1788,7 @@ public class InputMethodService extends AbstractInputMethodService {
/**
* Override this to intercept key up events before they are processed by the
* application. If you return true, the application will not itself
- * process the event. If you return true, the normal application processing
+ * process the event. If you return false, the normal application processing
* will occur as if the IME had not seen the event at all.
*
* <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
@@ -1806,8 +1806,29 @@ public class InputMethodService extends AbstractInputMethodService {
return doMovementKey(keyCode, event, MOVEMENT_UP);
}
+ /**
+ * Override this to intercept trackball motion events before they are
+ * processed by the application.
+ * If you return true, the application will not itself process the event.
+ * If you return false, the normal application processing will occur as if
+ * the IME had not seen the event at all.
+ */
@Override
public boolean onTrackballEvent(MotionEvent event) {
+ if (DEBUG) Log.v(TAG, "onTrackballEvent: " + event);
+ return false;
+ }
+
+ /**
+ * Override this to intercept generic motion events before they are
+ * processed by the application.
+ * If you return true, the application will not itself process the event.
+ * If you return false, the normal application processing will occur as if
+ * the IME had not seen the event at all.
+ */
+ @Override
+ public boolean onGenericMotionEvent(MotionEvent event) {
+ if (DEBUG) Log.v(TAG, "onGenericMotionEvent(): event " + event);
return false;
}
diff --git a/core/java/android/view/InputEventConsistencyVerifier.java b/core/java/android/view/InputEventConsistencyVerifier.java
index fafe416..5dda934 100644
--- a/core/java/android/view/InputEventConsistencyVerifier.java
+++ b/core/java/android/view/InputEventConsistencyVerifier.java
@@ -322,7 +322,7 @@ public final class InputEventConsistencyVerifier {
final int action = event.getAction();
final boolean newStream = action == MotionEvent.ACTION_DOWN
- || action == MotionEvent.ACTION_CANCEL;
+ || action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_OUTSIDE;
if (newStream && (mTouchEventStreamIsTainted || mTouchEventStreamUnhandled)) {
mTouchEventStreamIsTainted = false;
mTouchEventStreamUnhandled = false;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index a4c0235..3006b5d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3211,6 +3211,33 @@ public final class ViewRootImpl implements ViewParent,
mInputEventConsistencyVerifier.onTrackballEvent(event, 0);
}
+ if (mView != null && mAdded && (q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) {
+ if (LOCAL_LOGV)
+ Log.v(TAG, "Dispatching trackball " + event + " to " + mView);
+
+ // Dispatch to the IME before propagating down the view hierarchy.
+ // The IME will eventually call back into handleImeFinishedEvent.
+ if (mLastWasImTarget) {
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null) {
+ final int seq = event.getSequenceNumber();
+ if (DEBUG_IMF)
+ Log.v(TAG, "Sending trackball event to IME: seq="
+ + seq + " event=" + event);
+ imm.dispatchTrackballEvent(mView.getContext(), seq, event,
+ mInputMethodCallback);
+ return;
+ }
+ }
+ }
+
+ // Not dispatching to IME, continue with post IME actions.
+ deliverTrackballEventPostIme(q);
+ }
+
+ private void deliverTrackballEventPostIme(QueuedInputEvent q) {
+ final MotionEvent event = (MotionEvent) q.mEvent;
+
// If there is no view, then the event will not be handled.
if (mView == null || !mAdded) {
finishInputEvent(q, false);
@@ -3344,8 +3371,33 @@ public final class ViewRootImpl implements ViewParent,
mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
}
- final int source = event.getSource();
- final boolean isJoystick = (source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0;
+ if (mView != null && mAdded && (q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) {
+ if (LOCAL_LOGV)
+ Log.v(TAG, "Dispatching generic motion " + event + " to " + mView);
+
+ // Dispatch to the IME before propagating down the view hierarchy.
+ // The IME will eventually call back into handleImeFinishedEvent.
+ if (mLastWasImTarget) {
+ InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null) {
+ final int seq = event.getSequenceNumber();
+ if (DEBUG_IMF)
+ Log.v(TAG, "Sending generic motion event to IME: seq="
+ + seq + " event=" + event);
+ imm.dispatchGenericMotionEvent(mView.getContext(), seq, event,
+ mInputMethodCallback);
+ return;
+ }
+ }
+ }
+
+ // Not dispatching to IME, continue with post IME actions.
+ deliverGenericMotionEventPostIme(q);
+ }
+
+ private void deliverGenericMotionEventPostIme(QueuedInputEvent q) {
+ final MotionEvent event = (MotionEvent) q.mEvent;
+ final boolean isJoystick = (event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0;
// If there is no view, then the event will not be handled.
if (mView == null || !mAdded) {
@@ -3366,7 +3418,8 @@ public final class ViewRootImpl implements ViewParent,
}
if (isJoystick) {
- // Translate the joystick event into DPAD keys and try to deliver those.
+ // Translate the joystick event into DPAD keys and try to deliver
+ // those.
updateJoystickDirection(event, true);
finishInputEvent(q, true);
} else {
@@ -3521,13 +3574,7 @@ public final class ViewRootImpl implements ViewParent,
mInputEventConsistencyVerifier.onKeyEvent(event, 0);
}
- if ((q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) {
- // If there is no view, then the event will not be handled.
- if (mView == null || !mAdded) {
- finishInputEvent(q, false);
- return;
- }
-
+ if (mView != null && mAdded && (q.mFlags & QueuedInputEvent.FLAG_DELIVER_POST_IME) == 0) {
if (LOCAL_LOGV) Log.v(TAG, "Dispatching key " + event + " to " + mView);
// Perform predispatching before the IME.
@@ -3557,15 +3604,23 @@ public final class ViewRootImpl implements ViewParent,
void handleImeFinishedEvent(int seq, boolean handled) {
final QueuedInputEvent q = mCurrentInputEvent;
if (q != null && q.mEvent.getSequenceNumber() == seq) {
- final KeyEvent event = (KeyEvent)q.mEvent;
if (DEBUG_IMF) {
Log.v(TAG, "IME finished event: seq=" + seq
- + " handled=" + handled + " event=" + event);
+ + " handled=" + handled + " event=" + q);
}
if (handled) {
finishInputEvent(q, true);
} else {
- deliverKeyEventPostIme(q);
+ if (q.mEvent instanceof KeyEvent) {
+ deliverKeyEventPostIme(q);
+ } else {
+ final int source = q.mEvent.getSource();
+ if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
+ deliverTrackballEventPostIme(q);
+ } else {
+ deliverGenericMotionEventPostIme(q);
+ }
+ }
}
} else {
if (DEBUG_IMF) {
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index e754adc..3ea6df3 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1593,7 +1593,7 @@ public final class InputMethodManager {
/**
* @hide
*/
- void dispatchTrackballEvent(Context context, int seq, MotionEvent motion,
+ public void dispatchTrackballEvent(Context context, int seq, MotionEvent motion,
FinishedEventCallback callback) {
synchronized (mH) {
if (DEBUG) Log.d(TAG, "dispatchTrackballEvent");
@@ -1614,6 +1614,30 @@ public final class InputMethodManager {
callback.finishedEvent(seq, false);
}
+ /**
+ * @hide
+ */
+ public void dispatchGenericMotionEvent(Context context, int seq, MotionEvent motion,
+ FinishedEventCallback callback) {
+ synchronized (mH) {
+ if (DEBUG) Log.d(TAG, "dispatchGenericMotionEvent");
+
+ if (mCurMethod != null && mCurrentTextBoxAttribute != null) {
+ try {
+ if (DEBUG) Log.v(TAG, "DISPATCH GENERIC MOTION: " + mCurMethod);
+ final long startTime = SystemClock.uptimeMillis();
+ enqueuePendingEventLocked(startTime, seq, mCurId, callback);
+ mCurMethod.dispatchGenericMotionEvent(seq, motion, mInputMethodCallback);
+ return;
+ } catch (RemoteException e) {
+ Log.w(TAG, "IME died: " + mCurId + " dropping generic motion: " + motion, e);
+ }
+ }
+ }
+
+ callback.finishedEvent(seq, false);
+ }
+
void finishedEvent(int seq, boolean handled) {
final FinishedEventCallback callback;
synchronized (mH) {
diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java
index ea6f5ee..6386299 100644
--- a/core/java/android/view/inputmethod/InputMethodSession.java
+++ b/core/java/android/view/inputmethod/InputMethodSession.java
@@ -138,6 +138,21 @@ public interface InputMethodSession {
public void dispatchTrackballEvent(int seq, MotionEvent event, EventCallback callback);
/**
+ * This method is called when there is a generic motion event.
+ *
+ * <p>
+ * If the input method wants to handle this event, return true, otherwise
+ * return false and the caller (i.e. the application) will handle the event.
+ *
+ * @param event The motion event.
+ *
+ * @return Whether the input method wants to handle this event.
+ *
+ * @see android.view.MotionEvent
+ */
+ public void dispatchGenericMotionEvent(int seq, MotionEvent event, EventCallback callback);
+
+ /**
* Process a private command sent from the application to the input method.
* This can be used to provide domain-specific features that are
* only known between certain input methods and their clients.
diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl
index f875cbd..cdec254 100644
--- a/core/java/com/android/internal/view/IInputMethodSession.aidl
+++ b/core/java/com/android/internal/view/IInputMethodSession.aidl
@@ -47,6 +47,8 @@ oneway interface IInputMethodSession {
void dispatchTrackballEvent(int seq, in MotionEvent event, IInputMethodCallback callback);
+ void dispatchGenericMotionEvent(int seq, in MotionEvent event, IInputMethodCallback callback);
+
void appPrivateCommand(String action, in Bundle data);
void toggleSoftInput(int showFlags, int hideFlags);