Skip to content

Commit d7f5a51

Browse files
Victoria LeaseAndroid (Google) Code Review
authored andcommitted
Merge "IME support for trackball and generic motion events" into jb-mr1-dev
2 parents e11dc0d + b38070c commit d7f5a51

File tree

10 files changed

+271
-34
lines changed

10 files changed

+271
-34
lines changed

api/current.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10217,6 +10217,7 @@ package android.inputmethodservice {
1021710217
method public final android.os.IBinder onBind(android.content.Intent);
1021810218
method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl onCreateInputMethodInterface();
1021910219
method public abstract android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodSessionImpl onCreateInputMethodSessionInterface();
10220+
method public boolean onGenericMotionEvent(android.view.MotionEvent);
1022010221
method public boolean onTrackballEvent(android.view.MotionEvent);
1022110222
}
1022210223

@@ -10229,6 +10230,7 @@ package android.inputmethodservice {
1022910230

1023010231
public abstract class AbstractInputMethodService.AbstractInputMethodSessionImpl implements android.view.inputmethod.InputMethodSession {
1023110232
ctor public AbstractInputMethodService.AbstractInputMethodSessionImpl();
10233+
method public void dispatchGenericMotionEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback);
1023210234
method public void dispatchKeyEvent(int, android.view.KeyEvent, android.view.inputmethod.InputMethodSession.EventCallback);
1023310235
method public void dispatchTrackballEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback);
1023410236
method public boolean isEnabled();
@@ -26697,6 +26699,7 @@ package android.view.inputmethod {
2669726699

2669826700
public abstract interface InputMethodSession {
2669926701
method public abstract void appPrivateCommand(java.lang.String, android.os.Bundle);
26702+
method public abstract void dispatchGenericMotionEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback);
2670026703
method public abstract void dispatchKeyEvent(int, android.view.KeyEvent, android.view.inputmethod.InputMethodSession.EventCallback);
2670126704
method public abstract void dispatchTrackballEvent(int, android.view.MotionEvent, android.view.inputmethod.InputMethodSession.EventCallback);
2670226705
method public abstract void displayCompletions(android.view.inputmethod.CompletionInfo[]);

cmds/input/src/com/android/commands/input/Input.java

Lines changed: 89 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,54 @@ private void run(String[] args) {
6666
}
6767
} else if (command.equals("tap")) {
6868
if (args.length == 3) {
69-
sendTap(Float.parseFloat(args[1]), Float.parseFloat(args[2]));
69+
sendTap(InputDevice.SOURCE_TOUCHSCREEN, Float.parseFloat(args[1]), Float.parseFloat(args[2]));
7070
return;
7171
}
7272
} else if (command.equals("swipe")) {
7373
if (args.length == 5) {
74-
sendSwipe(Float.parseFloat(args[1]), Float.parseFloat(args[2]),
74+
sendSwipe(InputDevice.SOURCE_TOUCHSCREEN, Float.parseFloat(args[1]), Float.parseFloat(args[2]),
7575
Float.parseFloat(args[3]), Float.parseFloat(args[4]));
7676
return;
7777
}
78+
} else if (command.equals("touchscreen") || command.equals("touchpad")) {
79+
// determine input source
80+
int inputSource = InputDevice.SOURCE_TOUCHSCREEN;
81+
if (command.equals("touchpad")) {
82+
inputSource = InputDevice.SOURCE_TOUCHPAD;
83+
}
84+
// determine subcommand
85+
if (args.length > 1) {
86+
String subcommand = args[1];
87+
if (subcommand.equals("tap")) {
88+
if (args.length == 4) {
89+
sendTap(inputSource, Float.parseFloat(args[2]),
90+
Float.parseFloat(args[3]));
91+
return;
92+
}
93+
} else if (subcommand.equals("swipe")) {
94+
if (args.length == 6) {
95+
sendSwipe(inputSource, Float.parseFloat(args[2]),
96+
Float.parseFloat(args[3]), Float.parseFloat(args[4]),
97+
Float.parseFloat(args[5]));
98+
return;
99+
}
100+
}
101+
}
102+
} else if (command.equals("trackball")) {
103+
// determine subcommand
104+
if (args.length > 1) {
105+
String subcommand = args[1];
106+
if (subcommand.equals("press")) {
107+
sendTap(InputDevice.SOURCE_TRACKBALL, 0.0f, 0.0f);
108+
return;
109+
} else if (subcommand.equals("roll")) {
110+
if (args.length == 4) {
111+
sendMove(InputDevice.SOURCE_TRACKBALL, Float.parseFloat(args[2]),
112+
Float.parseFloat(args[3]));
113+
return;
114+
}
115+
}
116+
}
78117
} else {
79118
System.err.println("Error: Unknown command: " + command);
80119
showUsage();
@@ -127,33 +166,64 @@ private void sendKeyEvent(int keyCode) {
127166
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
128167
}
129168

130-
private void sendTap(float x, float y) {
169+
private void sendTap(int inputSource, float x, float y) {
131170
long now = SystemClock.uptimeMillis();
132-
injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, x, y, 0));
133-
injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, x, y, 0));
171+
injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x, y, 1.0f);
172+
injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x, y, 0.0f);
134173
}
135174

136-
private void sendSwipe(float x1, float y1, float x2, float y2) {
175+
private void sendSwipe(int inputSource, float x1, float y1, float x2, float y2) {
137176
final int NUM_STEPS = 11;
138177
long now = SystemClock.uptimeMillis();
139-
injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, x1, y1, 0));
178+
injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f);
140179
for (int i = 1; i < NUM_STEPS; i++) {
141-
float alpha = (float)i / NUM_STEPS;
142-
injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_MOVE,
143-
lerp(x1, x2, alpha), lerp(y1, y2, alpha), 0));
180+
float alpha = (float) i / NUM_STEPS;
181+
injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha),
182+
lerp(y1, y2, alpha), 1.0f);
144183
}
145-
injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, x2, y2, 0));
184+
injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x1, y1, 0.0f);
185+
}
186+
187+
/**
188+
* Sends a simple zero-pressure move event.
189+
*
190+
* @param inputSource the InputDevice.SOURCE_* sending the input event
191+
* @param dx change in x coordinate due to move
192+
* @param dy change in y coordinate due to move
193+
*/
194+
private void sendMove(int inputSource, float dx, float dy) {
195+
long now = SystemClock.uptimeMillis();
196+
injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, dx, dy, 0.0f);
146197
}
147198

148199
private void injectKeyEvent(KeyEvent event) {
149-
Log.i(TAG, "InjectKeyEvent: " + event);
200+
Log.i(TAG, "injectKeyEvent: " + event);
150201
InputManager.getInstance().injectInputEvent(event,
151202
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
152203
}
153204

154-
private void injectPointerEvent(MotionEvent event) {
155-
event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
156-
Log.i("Input", "InjectPointerEvent: " + event);
205+
/**
206+
* Builds a MotionEvent and injects it into the event stream.
207+
*
208+
* @param inputSource the InputDevice.SOURCE_* sending the input event
209+
* @param action the MotionEvent.ACTION_* for the event
210+
* @param when the value of SystemClock.uptimeMillis() at which the event happened
211+
* @param x x coordinate of event
212+
* @param y y coordinate of event
213+
* @param pressure pressure of event
214+
*/
215+
private void injectMotionEvent(int inputSource, int action, long when, float x, float y, float pressure) {
216+
final float DEFAULT_SIZE = 1.0f;
217+
final int DEFAULT_META_STATE = 0;
218+
final float DEFAULT_PRECISION_X = 1.0f;
219+
final float DEFAULT_PRECISION_Y = 1.0f;
220+
final int DEFAULT_DEVICE_ID = 0;
221+
final int DEFAULT_EDGE_FLAGS = 0;
222+
MotionEvent event = MotionEvent.obtain(when, when, action, x, y, pressure, DEFAULT_SIZE,
223+
DEFAULT_META_STATE, DEFAULT_PRECISION_X, DEFAULT_PRECISION_Y, DEFAULT_DEVICE_ID,
224+
DEFAULT_EDGE_FLAGS);
225+
event.setSource(inputSource);
226+
Log.i("Input", "injectMotionEvent: " + event);
157227
InputManager.getInstance().injectInputEvent(event,
158228
InputManager.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH);
159229
}
@@ -166,7 +236,9 @@ private void showUsage() {
166236
System.err.println("usage: input ...");
167237
System.err.println(" input text <string>");
168238
System.err.println(" input keyevent <key code number or name>");
169-
System.err.println(" input tap <x> <y>");
170-
System.err.println(" input swipe <x1> <y1> <x2> <y2>");
239+
System.err.println(" input [touchscreen|touchpad] tap <x> <y>");
240+
System.err.println(" input [touchscreen|touchpad] swipe <x1> <y1> <x2> <y2>");
241+
System.err.println(" input trackball press");
242+
System.err.println(" input trackball roll <dx> <dy>");
171243
}
172244
}

core/java/android/inputmethodservice/AbstractInputMethodService.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,17 @@ public void dispatchTrackballEvent(int seq, MotionEvent event, EventCallback cal
149149
callback.finishedEvent(seq, handled);
150150
}
151151
}
152+
153+
/**
154+
* Take care of dispatching incoming generic motion events to the appropriate
155+
* callbacks on the service, and tell the client when this is done.
156+
*/
157+
public void dispatchGenericMotionEvent(int seq, MotionEvent event, EventCallback callback) {
158+
boolean handled = onGenericMotionEvent(event);
159+
if (callback != null) {
160+
callback.finishedEvent(seq, handled);
161+
}
162+
}
152163
}
153164

154165
/**
@@ -189,7 +200,25 @@ final public IBinder onBind(Intent intent) {
189200
return new IInputMethodWrapper(this, mInputMethod);
190201
}
191202

203+
/**
204+
* Implement this to handle trackball events on your input method.
205+
*
206+
* @param event The motion event being received.
207+
* @return True if the event was handled in this function, false otherwise.
208+
* @see View#onTrackballEvent
209+
*/
192210
public boolean onTrackballEvent(MotionEvent event) {
193211
return false;
194212
}
213+
214+
/**
215+
* Implement this to handle generic motion events on your input method.
216+
*
217+
* @param event The motion event being received.
218+
* @return True if the event was handled in this function, false otherwise.
219+
* @see View#onGenericMotionEvent
220+
*/
221+
public boolean onGenericMotionEvent(MotionEvent event) {
222+
return false;
223+
}
195224
}

core/java/android/inputmethodservice/IInputMethodSessionWrapper.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
4343
private static final int DO_UPDATE_EXTRACTED_TEXT = 67;
4444
private static final int DO_DISPATCH_KEY_EVENT = 70;
4545
private static final int DO_DISPATCH_TRACKBALL_EVENT = 80;
46+
private static final int DO_DISPATCH_GENERIC_MOTION_EVENT = 85;
4647
private static final int DO_UPDATE_SELECTION = 90;
4748
private static final int DO_UPDATE_CURSOR = 95;
4849
private static final int DO_APP_PRIVATE_COMMAND = 100;
@@ -109,6 +110,15 @@ public void executeMessage(Message msg) {
109110
args.recycle();
110111
return;
111112
}
113+
case DO_DISPATCH_GENERIC_MOTION_EVENT: {
114+
SomeArgs args = (SomeArgs)msg.obj;
115+
mInputMethodSession.dispatchGenericMotionEvent(msg.arg1,
116+
(MotionEvent)args.arg1,
117+
new InputMethodEventCallbackWrapper(
118+
(IInputMethodCallback)args.arg2));
119+
args.recycle();
120+
return;
121+
}
112122
case DO_UPDATE_SELECTION: {
113123
SomeArgs args = (SomeArgs)msg.obj;
114124
mInputMethodSession.updateSelection(args.argi1, args.argi2,
@@ -167,6 +177,12 @@ public void dispatchTrackballEvent(int seq, MotionEvent event, IInputMethodCallb
167177
event, callback));
168178
}
169179

180+
public void dispatchGenericMotionEvent(int seq, MotionEvent event,
181+
IInputMethodCallback callback) {
182+
mCaller.executeOrSendMessage(mCaller.obtainMessageIOO(DO_DISPATCH_GENERIC_MOTION_EVENT, seq,
183+
event, callback));
184+
}
185+
170186
public void updateSelection(int oldSelStart, int oldSelEnd,
171187
int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd) {
172188
mCaller.executeOrSendMessage(mCaller.obtainMessageIIIIII(DO_UPDATE_SELECTION,

core/java/android/inputmethodservice/InputMethodService.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1773,7 +1773,7 @@ public boolean onKeyLongPress(int keyCode, KeyEvent event) {
17731773
* Override this to intercept special key multiple events before they are
17741774
* processed by the
17751775
* application. If you return true, the application will not itself
1776-
* process the event. If you return true, the normal application processing
1776+
* process the event. If you return false, the normal application processing
17771777
* will occur as if the IME had not seen the event at all.
17781778
*
17791779
* <p>The default implementation always returns false, except when
@@ -1788,7 +1788,7 @@ public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
17881788
/**
17891789
* Override this to intercept key up events before they are processed by the
17901790
* application. If you return true, the application will not itself
1791-
* process the event. If you return true, the normal application processing
1791+
* process the event. If you return false, the normal application processing
17921792
* will occur as if the IME had not seen the event at all.
17931793
*
17941794
* <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
@@ -1806,8 +1806,29 @@ public boolean onKeyUp(int keyCode, KeyEvent event) {
18061806
return doMovementKey(keyCode, event, MOVEMENT_UP);
18071807
}
18081808

1809+
/**
1810+
* Override this to intercept trackball motion events before they are
1811+
* processed by the application.
1812+
* If you return true, the application will not itself process the event.
1813+
* If you return false, the normal application processing will occur as if
1814+
* the IME had not seen the event at all.
1815+
*/
18091816
@Override
18101817
public boolean onTrackballEvent(MotionEvent event) {
1818+
if (DEBUG) Log.v(TAG, "onTrackballEvent: " + event);
1819+
return false;
1820+
}
1821+
1822+
/**
1823+
* Override this to intercept generic motion events before they are
1824+
* processed by the application.
1825+
* If you return true, the application will not itself process the event.
1826+
* If you return false, the normal application processing will occur as if
1827+
* the IME had not seen the event at all.
1828+
*/
1829+
@Override
1830+
public boolean onGenericMotionEvent(MotionEvent event) {
1831+
if (DEBUG) Log.v(TAG, "onGenericMotionEvent(): event " + event);
18111832
return false;
18121833
}
18131834

core/java/android/view/InputEventConsistencyVerifier.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ public void onTouchEvent(MotionEvent event, int nestingLevel) {
322322

323323
final int action = event.getAction();
324324
final boolean newStream = action == MotionEvent.ACTION_DOWN
325-
|| action == MotionEvent.ACTION_CANCEL;
325+
|| action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_OUTSIDE;
326326
if (newStream && (mTouchEventStreamIsTainted || mTouchEventStreamUnhandled)) {
327327
mTouchEventStreamIsTainted = false;
328328
mTouchEventStreamUnhandled = false;

0 commit comments

Comments
 (0)