Merge "Ensure input events are processed in-order in the application."
This commit is contained in:
@@ -18,7 +18,6 @@ package android.service.wallpaper;
|
||||
|
||||
import com.android.internal.os.HandlerCaller;
|
||||
import com.android.internal.view.BaseIWindow;
|
||||
import com.android.internal.view.BaseInputHandler;
|
||||
import com.android.internal.view.BaseSurfaceHolder;
|
||||
|
||||
import android.annotation.SdkConstant;
|
||||
@@ -45,6 +44,7 @@ import android.view.Gravity;
|
||||
import android.view.IWindowSession;
|
||||
import android.view.InputChannel;
|
||||
import android.view.InputDevice;
|
||||
import android.view.InputEvent;
|
||||
import android.view.InputHandler;
|
||||
import android.view.InputQueue;
|
||||
import android.view.MotionEvent;
|
||||
@@ -229,15 +229,15 @@ public abstract class WallpaperService extends Service {
|
||||
|
||||
};
|
||||
|
||||
final InputHandler mInputHandler = new BaseInputHandler() {
|
||||
final InputHandler mInputHandler = new InputHandler() {
|
||||
@Override
|
||||
public void handleMotion(MotionEvent event,
|
||||
public void handleInputEvent(InputEvent event,
|
||||
InputQueue.FinishedCallback finishedCallback) {
|
||||
boolean handled = false;
|
||||
try {
|
||||
int source = event.getSource();
|
||||
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
|
||||
dispatchPointer(event);
|
||||
if (event instanceof MotionEvent
|
||||
&& (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
|
||||
dispatchPointer((MotionEvent)event);
|
||||
handled = true;
|
||||
}
|
||||
} finally {
|
||||
|
||||
@@ -20,24 +20,16 @@ package android.view;
|
||||
* Handles input messages that arrive on an input channel.
|
||||
* @hide
|
||||
*/
|
||||
public interface InputHandler {
|
||||
public class InputHandler {
|
||||
/**
|
||||
* Handle a key event.
|
||||
* Handle an input event.
|
||||
* It is the responsibility of the callee to ensure that the finished callback is
|
||||
* eventually invoked when the event processing is finished and the input system
|
||||
* can send the next event.
|
||||
* @param event The key event data.
|
||||
* @param event The input event.
|
||||
* @param finishedCallback The callback to invoke when event processing is finished.
|
||||
*/
|
||||
public void handleKey(KeyEvent event, InputQueue.FinishedCallback finishedCallback);
|
||||
|
||||
/**
|
||||
* Handle a motion event.
|
||||
* It is the responsibility of the callee to ensure that the finished callback is
|
||||
* eventually invoked when the event processing is finished and the input system
|
||||
* can send the next event.
|
||||
* @param event The motion event data.
|
||||
* @param finishedCallback The callback to invoke when event processing is finished.
|
||||
*/
|
||||
public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback);
|
||||
public void handleInputEvent(InputEvent event, InputQueue.FinishedCallback finishedCallback) {
|
||||
finishedCallback.finished(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,19 +114,12 @@ public final class InputQueue {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static void dispatchKeyEvent(InputHandler inputHandler,
|
||||
KeyEvent event, long finishedToken) {
|
||||
private static void dispatchInputEvent(InputHandler inputHandler,
|
||||
InputEvent event, long finishedToken) {
|
||||
FinishedCallback finishedCallback = FinishedCallback.obtain(finishedToken);
|
||||
inputHandler.handleKey(event, finishedCallback);
|
||||
inputHandler.handleInputEvent(event, finishedCallback);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static void dispatchMotionEvent(InputHandler inputHandler,
|
||||
MotionEvent event, long finishedToken) {
|
||||
FinishedCallback finishedCallback = FinishedCallback.obtain(finishedToken);
|
||||
inputHandler.handleMotion(event, finishedCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback that must be invoked to when finished processing an event.
|
||||
* @hide
|
||||
|
||||
@@ -154,9 +154,6 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
final TypedValue mTmpValue = new TypedValue();
|
||||
|
||||
final InputMethodCallback mInputMethodCallback;
|
||||
final SparseArray<Object> mPendingEvents = new SparseArray<Object>();
|
||||
int mPendingEventSeq = 0;
|
||||
|
||||
final Thread mThread;
|
||||
|
||||
final WindowLeaked mLocation;
|
||||
@@ -219,7 +216,17 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
boolean mNewSurfaceNeeded;
|
||||
boolean mHasHadWindowFocus;
|
||||
boolean mLastWasImTarget;
|
||||
InputEventMessage mPendingInputEvents = null;
|
||||
|
||||
// Pool of queued input events.
|
||||
private static final int MAX_QUEUED_INPUT_EVENT_POOL_SIZE = 10;
|
||||
private QueuedInputEvent mQueuedInputEventPool;
|
||||
private int mQueuedInputEventPoolSize;
|
||||
private int mQueuedInputEventNextSeq;
|
||||
|
||||
// Input event queue.
|
||||
QueuedInputEvent mFirstPendingInputEvent;
|
||||
QueuedInputEvent mCurrentInputEvent;
|
||||
boolean mProcessInputEventsPending;
|
||||
|
||||
boolean mWindowAttributesChanged = false;
|
||||
int mWindowAttributesChangesFlag = 0;
|
||||
@@ -841,23 +848,11 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
}
|
||||
}
|
||||
|
||||
private void processInputEvents(boolean outOfOrder) {
|
||||
while (mPendingInputEvents != null) {
|
||||
handleMessage(mPendingInputEvents.mMessage);
|
||||
InputEventMessage tmpMessage = mPendingInputEvents;
|
||||
mPendingInputEvents = mPendingInputEvents.mNext;
|
||||
tmpMessage.recycle();
|
||||
if (outOfOrder) {
|
||||
removeMessages(PROCESS_INPUT_EVENTS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void performTraversals() {
|
||||
// cache mView since it is used so much below...
|
||||
final View host = mView;
|
||||
|
||||
processInputEvents(true);
|
||||
processInputEvents();
|
||||
|
||||
if (DBG) {
|
||||
System.out.println("======================================");
|
||||
@@ -2366,7 +2361,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
public final static int DISPATCH_TRACKBALL = 1007;
|
||||
public final static int DISPATCH_APP_VISIBILITY = 1008;
|
||||
public final static int DISPATCH_GET_NEW_SURFACE = 1009;
|
||||
public final static int FINISHED_EVENT = 1010;
|
||||
public final static int IME_FINISHED_EVENT = 1010;
|
||||
public final static int DISPATCH_KEY_FROM_IME = 1011;
|
||||
public final static int FINISH_INPUT_CONNECTION = 1012;
|
||||
public final static int CHECK_FOCUS = 1013;
|
||||
@@ -2380,7 +2375,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID = 1021;
|
||||
public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID = 1022;
|
||||
public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT = 1023;
|
||||
public final static int PROCESS_INPUT_EVENTS = 1024;
|
||||
public final static int DO_PROCESS_INPUT_EVENTS = 1024;
|
||||
|
||||
@Override
|
||||
public String getMessageName(Message message) {
|
||||
@@ -2405,8 +2400,8 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
return "DISPATCH_APP_VISIBILITY";
|
||||
case DISPATCH_GET_NEW_SURFACE:
|
||||
return "DISPATCH_GET_NEW_SURFACE";
|
||||
case FINISHED_EVENT:
|
||||
return "FINISHED_EVENT";
|
||||
case IME_FINISHED_EVENT:
|
||||
return "IME_FINISHED_EVENT";
|
||||
case DISPATCH_KEY_FROM_IME:
|
||||
return "DISPATCH_KEY_FROM_IME";
|
||||
case FINISH_INPUT_CONNECTION:
|
||||
@@ -2433,8 +2428,8 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID";
|
||||
case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT:
|
||||
return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT";
|
||||
case PROCESS_INPUT_EVENTS:
|
||||
return "PROCESS_INPUT_EVENTS";
|
||||
case DO_PROCESS_INPUT_EVENTS:
|
||||
return "DO_PROCESS_INPUT_EVENTS";
|
||||
}
|
||||
return super.getMessageName(message);
|
||||
}
|
||||
@@ -2483,23 +2478,12 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
mProfile = false;
|
||||
}
|
||||
break;
|
||||
case FINISHED_EVENT:
|
||||
handleFinishedEvent(msg.arg1, msg.arg2 != 0);
|
||||
case IME_FINISHED_EVENT:
|
||||
handleImeFinishedEvent(msg.arg1, msg.arg2 != 0);
|
||||
break;
|
||||
case DISPATCH_KEY:
|
||||
deliverKeyEvent((KeyEvent)msg.obj, msg.arg1 != 0);
|
||||
break;
|
||||
case DISPATCH_POINTER:
|
||||
deliverPointerEvent((MotionEvent) msg.obj, msg.arg1 != 0);
|
||||
break;
|
||||
case DISPATCH_TRACKBALL:
|
||||
deliverTrackballEvent((MotionEvent) msg.obj, msg.arg1 != 0);
|
||||
break;
|
||||
case DISPATCH_GENERIC_MOTION:
|
||||
deliverGenericMotionEvent((MotionEvent) msg.obj, msg.arg1 != 0);
|
||||
break;
|
||||
case PROCESS_INPUT_EVENTS:
|
||||
processInputEvents(false);
|
||||
case DO_PROCESS_INPUT_EVENTS:
|
||||
mProcessInputEventsPending = false;
|
||||
processInputEvents();
|
||||
break;
|
||||
case DISPATCH_APP_VISIBILITY:
|
||||
handleAppVisibility(msg.arg1 != 0);
|
||||
@@ -2621,7 +2605,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
//noinspection UnusedAssignment
|
||||
event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
|
||||
}
|
||||
deliverKeyEventPostIme((KeyEvent)msg.obj, false);
|
||||
enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME);
|
||||
} break;
|
||||
case FINISH_INPUT_CONNECTION: {
|
||||
InputMethodManager imm = InputMethodManager.peekInstance();
|
||||
@@ -2683,70 +2667,6 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
}
|
||||
}
|
||||
|
||||
private void startInputEvent(InputQueue.FinishedCallback finishedCallback) {
|
||||
if (mFinishedCallback != null) {
|
||||
Slog.w(TAG, "Received a new input event from the input queue but there is "
|
||||
+ "already an unfinished input event in progress.");
|
||||
}
|
||||
|
||||
if (ViewDebug.DEBUG_LATENCY) {
|
||||
mInputEventReceiveTimeNanos = System.nanoTime();
|
||||
mInputEventDeliverTimeNanos = 0;
|
||||
mInputEventDeliverPostImeTimeNanos = 0;
|
||||
}
|
||||
|
||||
mFinishedCallback = finishedCallback;
|
||||
}
|
||||
|
||||
private void finishInputEvent(InputEvent event, boolean handled) {
|
||||
if (LOCAL_LOGV) Log.v(TAG, "Telling window manager input event is finished");
|
||||
|
||||
if (mFinishedCallback == null) {
|
||||
Slog.w(TAG, "Attempted to tell the input queue that the current input event "
|
||||
+ "is finished but there is no input event actually in progress.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ViewDebug.DEBUG_LATENCY) {
|
||||
final long now = System.nanoTime();
|
||||
final long eventTime = event.getEventTimeNano();
|
||||
final StringBuilder msg = new StringBuilder();
|
||||
msg.append("Latency: Spent ");
|
||||
msg.append((now - mInputEventReceiveTimeNanos) * 0.000001f);
|
||||
msg.append("ms processing ");
|
||||
if (event instanceof KeyEvent) {
|
||||
final KeyEvent keyEvent = (KeyEvent)event;
|
||||
msg.append("key event, action=");
|
||||
msg.append(KeyEvent.actionToString(keyEvent.getAction()));
|
||||
} else {
|
||||
final MotionEvent motionEvent = (MotionEvent)event;
|
||||
msg.append("motion event, action=");
|
||||
msg.append(MotionEvent.actionToString(motionEvent.getAction()));
|
||||
msg.append(", historySize=");
|
||||
msg.append(motionEvent.getHistorySize());
|
||||
}
|
||||
msg.append(", handled=");
|
||||
msg.append(handled);
|
||||
msg.append(", received at +");
|
||||
msg.append((mInputEventReceiveTimeNanos - eventTime) * 0.000001f);
|
||||
if (mInputEventDeliverTimeNanos != 0) {
|
||||
msg.append("ms, delivered at +");
|
||||
msg.append((mInputEventDeliverTimeNanos - eventTime) * 0.000001f);
|
||||
}
|
||||
if (mInputEventDeliverPostImeTimeNanos != 0) {
|
||||
msg.append("ms, delivered post IME at +");
|
||||
msg.append((mInputEventDeliverPostImeTimeNanos - eventTime) * 0.000001f);
|
||||
}
|
||||
msg.append("ms, finished at +");
|
||||
msg.append((now - eventTime) * 0.000001f);
|
||||
msg.append("ms.");
|
||||
Log.d(TAG, msg.toString());
|
||||
}
|
||||
|
||||
mFinishedCallback.finished(handled);
|
||||
mFinishedCallback = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Something in the current window tells us we need to change the touch mode. For
|
||||
* example, we are not in touch mode, and the user touches the screen.
|
||||
@@ -2868,11 +2788,27 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
return false;
|
||||
}
|
||||
|
||||
private void deliverPointerEvent(MotionEvent event, boolean sendDone) {
|
||||
private void deliverInputEvent(QueuedInputEvent q) {
|
||||
if (ViewDebug.DEBUG_LATENCY) {
|
||||
mInputEventDeliverTimeNanos = System.nanoTime();
|
||||
q.mDeliverTimeNanos = System.nanoTime();
|
||||
}
|
||||
|
||||
if (q.mEvent instanceof KeyEvent) {
|
||||
deliverKeyEvent(q);
|
||||
} else {
|
||||
final int source = q.mEvent.getSource();
|
||||
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
|
||||
deliverPointerEvent(q);
|
||||
} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
|
||||
deliverTrackballEvent(q);
|
||||
} else {
|
||||
deliverGenericMotionEvent(q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void deliverPointerEvent(QueuedInputEvent q) {
|
||||
final MotionEvent event = (MotionEvent)q.mEvent;
|
||||
final boolean isTouchEvent = event.isTouchEvent();
|
||||
if (mInputEventConsistencyVerifier != null) {
|
||||
if (isTouchEvent) {
|
||||
@@ -2884,7 +2820,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
|
||||
// If there is no view, then the event will not be handled.
|
||||
if (mView == null || !mAdded) {
|
||||
finishMotionEvent(event, sendDone, false);
|
||||
finishInputEvent(q, false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2919,41 +2855,23 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
lt.sample("B Dispatched PointerEvents ", System.nanoTime() - event.getEventTimeNano());
|
||||
}
|
||||
if (handled) {
|
||||
finishMotionEvent(event, sendDone, true);
|
||||
finishInputEvent(q, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Pointer event was unhandled.
|
||||
finishMotionEvent(event, sendDone, false);
|
||||
finishInputEvent(q, false);
|
||||
}
|
||||
|
||||
private void finishMotionEvent(MotionEvent event, boolean sendDone, boolean handled) {
|
||||
event.recycle();
|
||||
if (sendDone) {
|
||||
finishInputEvent(event, handled);
|
||||
}
|
||||
//noinspection ConstantConditions
|
||||
if (LOCAL_LOGV || WATCH_POINTER) {
|
||||
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
|
||||
Log.i(TAG, "Done dispatching!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void deliverTrackballEvent(MotionEvent event, boolean sendDone) {
|
||||
if (ViewDebug.DEBUG_LATENCY) {
|
||||
mInputEventDeliverTimeNanos = System.nanoTime();
|
||||
}
|
||||
|
||||
if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event);
|
||||
|
||||
private void deliverTrackballEvent(QueuedInputEvent q) {
|
||||
final MotionEvent event = (MotionEvent)q.mEvent;
|
||||
if (mInputEventConsistencyVerifier != null) {
|
||||
mInputEventConsistencyVerifier.onTrackballEvent(event, 0);
|
||||
}
|
||||
|
||||
// If there is no view, then the event will not be handled.
|
||||
if (mView == null || !mAdded) {
|
||||
finishMotionEvent(event, sendDone, false);
|
||||
finishInputEvent(q, false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2965,7 +2883,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
// touch mode here.
|
||||
ensureTouchMode(false);
|
||||
|
||||
finishMotionEvent(event, sendDone, true);
|
||||
finishInputEvent(q, true);
|
||||
mLastTrackballTime = Integer.MIN_VALUE;
|
||||
return;
|
||||
}
|
||||
@@ -2989,18 +2907,18 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
x.reset(2);
|
||||
y.reset(2);
|
||||
deliverKeyEvent(new KeyEvent(curTime, curTime,
|
||||
dispatchKey(new KeyEvent(curTime, curTime,
|
||||
KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
|
||||
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
|
||||
InputDevice.SOURCE_KEYBOARD), false);
|
||||
InputDevice.SOURCE_KEYBOARD));
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
x.reset(2);
|
||||
y.reset(2);
|
||||
deliverKeyEvent(new KeyEvent(curTime, curTime,
|
||||
dispatchKey(new KeyEvent(curTime, curTime,
|
||||
KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
|
||||
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
|
||||
InputDevice.SOURCE_KEYBOARD), false);
|
||||
InputDevice.SOURCE_KEYBOARD));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3051,38 +2969,35 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
+ keycode);
|
||||
movement--;
|
||||
int repeatCount = accelMovement - movement;
|
||||
deliverKeyEvent(new KeyEvent(curTime, curTime,
|
||||
dispatchKey(new KeyEvent(curTime, curTime,
|
||||
KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
|
||||
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
|
||||
InputDevice.SOURCE_KEYBOARD), false);
|
||||
InputDevice.SOURCE_KEYBOARD));
|
||||
}
|
||||
while (movement > 0) {
|
||||
if (DEBUG_TRACKBALL) Log.v("foo", "Delivering fake DPAD: "
|
||||
+ keycode);
|
||||
movement--;
|
||||
curTime = SystemClock.uptimeMillis();
|
||||
deliverKeyEvent(new KeyEvent(curTime, curTime,
|
||||
dispatchKey(new KeyEvent(curTime, curTime,
|
||||
KeyEvent.ACTION_DOWN, keycode, 0, metaState,
|
||||
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
|
||||
InputDevice.SOURCE_KEYBOARD), false);
|
||||
deliverKeyEvent(new KeyEvent(curTime, curTime,
|
||||
InputDevice.SOURCE_KEYBOARD));
|
||||
dispatchKey(new KeyEvent(curTime, curTime,
|
||||
KeyEvent.ACTION_UP, keycode, 0, metaState,
|
||||
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
|
||||
InputDevice.SOURCE_KEYBOARD), false);
|
||||
}
|
||||
InputDevice.SOURCE_KEYBOARD));
|
||||
}
|
||||
mLastTrackballTime = curTime;
|
||||
}
|
||||
|
||||
// Unfortunately we can't tell whether the application consumed the keys, so
|
||||
// we always consider the trackball event handled.
|
||||
finishMotionEvent(event, sendDone, true);
|
||||
finishInputEvent(q, true);
|
||||
}
|
||||
|
||||
private void deliverGenericMotionEvent(MotionEvent event, boolean sendDone) {
|
||||
if (ViewDebug.DEBUG_LATENCY) {
|
||||
mInputEventDeliverTimeNanos = System.nanoTime();
|
||||
}
|
||||
|
||||
private void deliverGenericMotionEvent(QueuedInputEvent q) {
|
||||
final MotionEvent event = (MotionEvent)q.mEvent;
|
||||
if (mInputEventConsistencyVerifier != null) {
|
||||
mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0);
|
||||
}
|
||||
@@ -3095,7 +3010,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
if (isJoystick) {
|
||||
updateJoystickDirection(event, false);
|
||||
}
|
||||
finishMotionEvent(event, sendDone, false);
|
||||
finishInputEvent(q, false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3104,16 +3019,16 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
if (isJoystick) {
|
||||
updateJoystickDirection(event, false);
|
||||
}
|
||||
finishMotionEvent(event, sendDone, true);
|
||||
finishInputEvent(q, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isJoystick) {
|
||||
// Translate the joystick event into DPAD keys and try to deliver those.
|
||||
updateJoystickDirection(event, true);
|
||||
finishMotionEvent(event, sendDone, true);
|
||||
finishInputEvent(q, true);
|
||||
} else {
|
||||
finishMotionEvent(event, sendDone, false);
|
||||
finishInputEvent(q, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3135,9 +3050,9 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
|
||||
if (xDirection != mLastJoystickXDirection) {
|
||||
if (mLastJoystickXKeyCode != 0) {
|
||||
deliverKeyEvent(new KeyEvent(time, time,
|
||||
dispatchKey(new KeyEvent(time, time,
|
||||
KeyEvent.ACTION_UP, mLastJoystickXKeyCode, 0, metaState,
|
||||
deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false);
|
||||
deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
|
||||
mLastJoystickXKeyCode = 0;
|
||||
}
|
||||
|
||||
@@ -3146,17 +3061,17 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
if (xDirection != 0 && synthesizeNewKeys) {
|
||||
mLastJoystickXKeyCode = xDirection > 0
|
||||
? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
|
||||
deliverKeyEvent(new KeyEvent(time, time,
|
||||
dispatchKey(new KeyEvent(time, time,
|
||||
KeyEvent.ACTION_DOWN, mLastJoystickXKeyCode, 0, metaState,
|
||||
deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false);
|
||||
deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
|
||||
}
|
||||
}
|
||||
|
||||
if (yDirection != mLastJoystickYDirection) {
|
||||
if (mLastJoystickYKeyCode != 0) {
|
||||
deliverKeyEvent(new KeyEvent(time, time,
|
||||
dispatchKey(new KeyEvent(time, time,
|
||||
KeyEvent.ACTION_UP, mLastJoystickYKeyCode, 0, metaState,
|
||||
deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false);
|
||||
deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
|
||||
mLastJoystickYKeyCode = 0;
|
||||
}
|
||||
|
||||
@@ -3165,9 +3080,9 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
if (yDirection != 0 && synthesizeNewKeys) {
|
||||
mLastJoystickYKeyCode = yDirection > 0
|
||||
? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
|
||||
deliverKeyEvent(new KeyEvent(time, time,
|
||||
dispatchKey(new KeyEvent(time, time,
|
||||
KeyEvent.ACTION_DOWN, mLastJoystickYKeyCode, 0, metaState,
|
||||
deviceId, 0, KeyEvent.FLAG_FALLBACK, source), false);
|
||||
deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3258,91 +3173,80 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
return false;
|
||||
}
|
||||
|
||||
int enqueuePendingEvent(Object event, boolean sendDone) {
|
||||
int seq = mPendingEventSeq+1;
|
||||
if (seq < 0) seq = 0;
|
||||
mPendingEventSeq = seq;
|
||||
mPendingEvents.put(seq, event);
|
||||
return sendDone ? seq : -seq;
|
||||
}
|
||||
|
||||
Object retrievePendingEvent(int seq) {
|
||||
if (seq < 0) seq = -seq;
|
||||
Object event = mPendingEvents.get(seq);
|
||||
if (event != null) {
|
||||
mPendingEvents.remove(seq);
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
private void deliverKeyEvent(KeyEvent event, boolean sendDone) {
|
||||
if (ViewDebug.DEBUG_LATENCY) {
|
||||
mInputEventDeliverTimeNanos = System.nanoTime();
|
||||
}
|
||||
|
||||
private void deliverKeyEvent(QueuedInputEvent q) {
|
||||
final KeyEvent event = (KeyEvent)q.mEvent;
|
||||
if (mInputEventConsistencyVerifier != null) {
|
||||
mInputEventConsistencyVerifier.onKeyEvent(event, 0);
|
||||
}
|
||||
|
||||
// If there is no view, then the event will not be handled.
|
||||
if (mView == null || !mAdded) {
|
||||
finishKeyEvent(event, sendDone, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOCAL_LOGV) Log.v(TAG, "Dispatching key " + event + " to " + mView);
|
||||
|
||||
// Perform predispatching before the IME.
|
||||
if (mView.dispatchKeyEventPreIme(event)) {
|
||||
finishKeyEvent(event, sendDone, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Dispatch to the IME before propagating down the view hierarchy.
|
||||
// The IME will eventually call back into handleFinishedEvent.
|
||||
if (mLastWasImTarget) {
|
||||
InputMethodManager imm = InputMethodManager.peekInstance();
|
||||
if (imm != null) {
|
||||
int seq = enqueuePendingEvent(event, sendDone);
|
||||
if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="
|
||||
+ seq + " event=" + event);
|
||||
imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback);
|
||||
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 (LOCAL_LOGV) Log.v(TAG, "Dispatching key " + event + " to " + mView);
|
||||
|
||||
// Perform predispatching before the IME.
|
||||
if (mView.dispatchKeyEventPreIme(event)) {
|
||||
finishInputEvent(q, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if (DEBUG_IMF) Log.v(TAG, "Sending key event to IME: seq="
|
||||
+ q.mSeq + " event=" + event);
|
||||
imm.dispatchKeyEvent(mView.getContext(), q.mSeq, event, mInputMethodCallback);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not dispatching to IME, continue with post IME actions.
|
||||
deliverKeyEventPostIme(event, sendDone);
|
||||
deliverKeyEventPostIme(q);
|
||||
}
|
||||
|
||||
private void handleFinishedEvent(int seq, boolean handled) {
|
||||
final KeyEvent event = (KeyEvent)retrievePendingEvent(seq);
|
||||
if (DEBUG_IMF) Log.v(TAG, "IME finished event: seq=" + seq
|
||||
+ " handled=" + handled + " event=" + event);
|
||||
if (event != null) {
|
||||
final boolean sendDone = seq >= 0;
|
||||
void handleImeFinishedEvent(int seq, boolean handled) {
|
||||
final QueuedInputEvent q = mCurrentInputEvent;
|
||||
if (q != null && q.mSeq == seq) {
|
||||
final KeyEvent event = (KeyEvent)q.mEvent;
|
||||
if (DEBUG_IMF) {
|
||||
Log.v(TAG, "IME finished event: seq=" + seq
|
||||
+ " handled=" + handled + " event=" + event);
|
||||
}
|
||||
if (handled) {
|
||||
finishKeyEvent(event, sendDone, true);
|
||||
finishInputEvent(q, true);
|
||||
} else {
|
||||
deliverKeyEventPostIme(event, sendDone);
|
||||
deliverKeyEventPostIme(q);
|
||||
}
|
||||
} else {
|
||||
if (DEBUG_IMF) {
|
||||
Log.v(TAG, "IME finished event: seq=" + seq
|
||||
+ " handled=" + handled + ", event not found!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void deliverKeyEventPostIme(KeyEvent event, boolean sendDone) {
|
||||
private void deliverKeyEventPostIme(QueuedInputEvent q) {
|
||||
final KeyEvent event = (KeyEvent)q.mEvent;
|
||||
if (ViewDebug.DEBUG_LATENCY) {
|
||||
mInputEventDeliverPostImeTimeNanos = System.nanoTime();
|
||||
q.mDeliverPostImeTimeNanos = System.nanoTime();
|
||||
}
|
||||
|
||||
// If the view went away, then the event will not be handled.
|
||||
if (mView == null || !mAdded) {
|
||||
finishKeyEvent(event, sendDone, false);
|
||||
finishInputEvent(q, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the key's purpose is to exit touch mode then we consume it and consider it handled.
|
||||
if (checkForLeavingTouchModeAndConsume(event)) {
|
||||
finishKeyEvent(event, sendDone, true);
|
||||
finishInputEvent(q, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3352,7 +3256,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
|
||||
// Deliver the key to the view hierarchy.
|
||||
if (mView.dispatchKeyEvent(event)) {
|
||||
finishKeyEvent(event, sendDone, true);
|
||||
finishInputEvent(q, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3361,14 +3265,14 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
&& event.isCtrlPressed()
|
||||
&& !KeyEvent.isModifierKey(event.getKeyCode())) {
|
||||
if (mView.dispatchKeyShortcutEvent(event)) {
|
||||
finishKeyEvent(event, sendDone, true);
|
||||
finishInputEvent(q, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the fallback event policy.
|
||||
if (mFallbackEventHandler.dispatchKeyEvent(event)) {
|
||||
finishKeyEvent(event, sendDone, true);
|
||||
finishInputEvent(q, true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3423,14 +3327,14 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
if (v.requestFocus(direction, mTempRect)) {
|
||||
playSoundEffect(
|
||||
SoundEffectConstants.getContantForFocusDirection(direction));
|
||||
finishKeyEvent(event, sendDone, true);
|
||||
finishInputEvent(q, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Give the focused view a last chance to handle the dpad key.
|
||||
if (mView.dispatchUnhandledMove(focused, direction)) {
|
||||
finishKeyEvent(event, sendDone, true);
|
||||
finishInputEvent(q, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -3438,13 +3342,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
}
|
||||
|
||||
// Key was unhandled.
|
||||
finishKeyEvent(event, sendDone, false);
|
||||
}
|
||||
|
||||
private void finishKeyEvent(KeyEvent event, boolean sendDone, boolean handled) {
|
||||
if (sendDone) {
|
||||
finishInputEvent(event, handled);
|
||||
}
|
||||
finishInputEvent(q, false);
|
||||
}
|
||||
|
||||
/* drag/drop */
|
||||
@@ -3769,8 +3667,8 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
}
|
||||
}
|
||||
|
||||
public void dispatchFinishedEvent(int seq, boolean handled) {
|
||||
Message msg = obtainMessage(FINISHED_EVENT);
|
||||
void dispatchImeFinishedEvent(int seq, boolean handled) {
|
||||
Message msg = obtainMessage(IME_FINISHED_EVENT);
|
||||
msg.arg1 = seq;
|
||||
msg.arg2 = handled ? 1 : 0;
|
||||
sendMessage(msg);
|
||||
@@ -3799,152 +3697,185 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
sendMessage(msg);
|
||||
}
|
||||
|
||||
private long mInputEventReceiveTimeNanos;
|
||||
private long mInputEventDeliverTimeNanos;
|
||||
private long mInputEventDeliverPostImeTimeNanos;
|
||||
private InputQueue.FinishedCallback mFinishedCallback;
|
||||
|
||||
private final InputHandler mInputHandler = new InputHandler() {
|
||||
public void handleKey(KeyEvent event, InputQueue.FinishedCallback finishedCallback) {
|
||||
startInputEvent(finishedCallback);
|
||||
dispatchKey(event, true);
|
||||
/**
|
||||
* Represents a pending input event that is waiting in a queue.
|
||||
*
|
||||
* Input events are processed in serial order by the timestamp specified by
|
||||
* {@link InputEvent#getEventTime()}. In general, the input dispatcher delivers
|
||||
* one input event to the application at a time and waits for the application
|
||||
* to finish handling it before delivering the next one.
|
||||
*
|
||||
* However, because the application or IME can synthesize and inject multiple
|
||||
* key events at a time without going through the input dispatcher, we end up
|
||||
* needing a queue on the application's side.
|
||||
*/
|
||||
private static final class QueuedInputEvent {
|
||||
public static final int FLAG_DELIVER_POST_IME = 1 << 0;
|
||||
|
||||
public QueuedInputEvent mNext;
|
||||
|
||||
public InputEvent mEvent;
|
||||
public InputQueue.FinishedCallback mFinishedCallback;
|
||||
public int mFlags;
|
||||
public int mSeq;
|
||||
|
||||
// Used for latency calculations.
|
||||
public long mReceiveTimeNanos;
|
||||
public long mDeliverTimeNanos;
|
||||
public long mDeliverPostImeTimeNanos;
|
||||
}
|
||||
|
||||
private QueuedInputEvent obtainQueuedInputEvent(InputEvent event,
|
||||
InputQueue.FinishedCallback finishedCallback, int flags) {
|
||||
QueuedInputEvent q = mQueuedInputEventPool;
|
||||
if (q != null) {
|
||||
mQueuedInputEventPoolSize -= 1;
|
||||
mQueuedInputEventPool = q.mNext;
|
||||
q.mNext = null;
|
||||
} else {
|
||||
q = new QueuedInputEvent();
|
||||
}
|
||||
|
||||
public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) {
|
||||
startInputEvent(finishedCallback);
|
||||
dispatchMotion(event, true);
|
||||
q.mEvent = event;
|
||||
q.mFinishedCallback = finishedCallback;
|
||||
q.mFlags = flags;
|
||||
q.mSeq = mQueuedInputEventNextSeq++;
|
||||
return q;
|
||||
}
|
||||
|
||||
private void recycleQueuedInputEvent(QueuedInputEvent q) {
|
||||
q.mEvent = null;
|
||||
q.mFinishedCallback = null;
|
||||
|
||||
if (mQueuedInputEventPoolSize < MAX_QUEUED_INPUT_EVENT_POOL_SIZE) {
|
||||
mQueuedInputEventPoolSize += 1;
|
||||
q.mNext = mQueuedInputEventPool;
|
||||
mQueuedInputEventPool = q;
|
||||
}
|
||||
}
|
||||
|
||||
void enqueueInputEvent(InputEvent event,
|
||||
InputQueue.FinishedCallback finishedCallback, int flags) {
|
||||
QueuedInputEvent q = obtainQueuedInputEvent(event, finishedCallback, flags);
|
||||
|
||||
if (ViewDebug.DEBUG_LATENCY) {
|
||||
q.mReceiveTimeNanos = System.nanoTime();
|
||||
q.mDeliverTimeNanos = 0;
|
||||
q.mDeliverPostImeTimeNanos = 0;
|
||||
}
|
||||
|
||||
// Always enqueue the input event in order, regardless of its time stamp.
|
||||
// We do this because the application or the IME may inject key events
|
||||
// in response to touch events and we want to ensure that the injected keys
|
||||
// are processed in the order they were received and we cannot trust that
|
||||
// the time stamp of injected events are monotonic.
|
||||
QueuedInputEvent last = mFirstPendingInputEvent;
|
||||
if (last == null) {
|
||||
mFirstPendingInputEvent = q;
|
||||
} else {
|
||||
while (last.mNext != null) {
|
||||
last = last.mNext;
|
||||
}
|
||||
last.mNext = q;
|
||||
}
|
||||
|
||||
scheduleProcessInputEvents();
|
||||
}
|
||||
|
||||
private void scheduleProcessInputEvents() {
|
||||
if (!mProcessInputEventsPending) {
|
||||
mProcessInputEventsPending = true;
|
||||
sendEmptyMessage(DO_PROCESS_INPUT_EVENTS);
|
||||
}
|
||||
}
|
||||
|
||||
void processInputEvents() {
|
||||
while (mCurrentInputEvent == null && mFirstPendingInputEvent != null) {
|
||||
QueuedInputEvent q = mFirstPendingInputEvent;
|
||||
mFirstPendingInputEvent = q.mNext;
|
||||
q.mNext = null;
|
||||
mCurrentInputEvent = q;
|
||||
deliverInputEvent(q);
|
||||
}
|
||||
|
||||
// We are done processing all input events that we can process right now
|
||||
// so we can clear the pending flag immediately.
|
||||
if (mProcessInputEventsPending) {
|
||||
mProcessInputEventsPending = false;
|
||||
removeMessages(DO_PROCESS_INPUT_EVENTS);
|
||||
}
|
||||
}
|
||||
|
||||
private void finishInputEvent(QueuedInputEvent q, boolean handled) {
|
||||
if (q != mCurrentInputEvent) {
|
||||
throw new IllegalStateException("finished input event out of order");
|
||||
}
|
||||
|
||||
if (ViewDebug.DEBUG_LATENCY) {
|
||||
final long now = System.nanoTime();
|
||||
final long eventTime = q.mEvent.getEventTimeNano();
|
||||
final StringBuilder msg = new StringBuilder();
|
||||
msg.append("Spent ");
|
||||
msg.append((now - q.mReceiveTimeNanos) * 0.000001f);
|
||||
msg.append("ms processing ");
|
||||
if (q.mEvent instanceof KeyEvent) {
|
||||
final KeyEvent keyEvent = (KeyEvent)q.mEvent;
|
||||
msg.append("key event, action=");
|
||||
msg.append(KeyEvent.actionToString(keyEvent.getAction()));
|
||||
} else {
|
||||
final MotionEvent motionEvent = (MotionEvent)q.mEvent;
|
||||
msg.append("motion event, action=");
|
||||
msg.append(MotionEvent.actionToString(motionEvent.getAction()));
|
||||
msg.append(", historySize=");
|
||||
msg.append(motionEvent.getHistorySize());
|
||||
}
|
||||
msg.append(", handled=");
|
||||
msg.append(handled);
|
||||
msg.append(", received at +");
|
||||
msg.append((q.mReceiveTimeNanos - eventTime) * 0.000001f);
|
||||
if (q.mDeliverTimeNanos != 0) {
|
||||
msg.append("ms, delivered at +");
|
||||
msg.append((q.mDeliverTimeNanos - eventTime) * 0.000001f);
|
||||
}
|
||||
if (q.mDeliverPostImeTimeNanos != 0) {
|
||||
msg.append("ms, delivered post IME at +");
|
||||
msg.append((q.mDeliverPostImeTimeNanos - eventTime) * 0.000001f);
|
||||
}
|
||||
msg.append("ms, finished at +");
|
||||
msg.append((now - eventTime) * 0.000001f);
|
||||
msg.append("ms.");
|
||||
Log.d(ViewDebug.DEBUG_LATENCY_TAG, msg.toString());
|
||||
}
|
||||
|
||||
if (q.mFinishedCallback != null) {
|
||||
q.mFinishedCallback.finished(handled);
|
||||
}
|
||||
|
||||
if (q.mEvent instanceof MotionEvent) {
|
||||
// Event though key events are also recyclable, we only recycle motion events.
|
||||
// Historically, key events were not recyclable and applications expect
|
||||
// them to be immutable. We only ever recycle key events behind the
|
||||
// scenes where an application never sees them (so, not here).
|
||||
q.mEvent.recycle();
|
||||
}
|
||||
|
||||
recycleQueuedInputEvent(q);
|
||||
|
||||
mCurrentInputEvent = null;
|
||||
if (mFirstPendingInputEvent != null) {
|
||||
scheduleProcessInputEvents();
|
||||
}
|
||||
}
|
||||
|
||||
private final InputHandler mInputHandler = new InputHandler() {
|
||||
public void handleInputEvent(InputEvent event,
|
||||
InputQueue.FinishedCallback finishedCallback) {
|
||||
enqueueInputEvent(event, finishedCallback, 0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility class used to queue up input events which are then handled during
|
||||
* performTraversals(). Doing it this way allows us to ensure that we are up to date with
|
||||
* all input events just prior to drawing, instead of placing those events on the regular
|
||||
* handler queue, potentially behind a drawing event.
|
||||
*/
|
||||
static class InputEventMessage {
|
||||
Message mMessage;
|
||||
InputEventMessage mNext;
|
||||
|
||||
private static final Object sPoolSync = new Object();
|
||||
private static InputEventMessage sPool;
|
||||
private static int sPoolSize = 0;
|
||||
|
||||
private static final int MAX_POOL_SIZE = 10;
|
||||
|
||||
private InputEventMessage(Message m) {
|
||||
mMessage = m;
|
||||
mNext = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new Message instance from the global pool. Allows us to
|
||||
* avoid allocating new objects in many cases.
|
||||
*/
|
||||
public static InputEventMessage obtain(Message msg) {
|
||||
synchronized (sPoolSync) {
|
||||
if (sPool != null) {
|
||||
InputEventMessage m = sPool;
|
||||
sPool = m.mNext;
|
||||
m.mNext = null;
|
||||
sPoolSize--;
|
||||
m.mMessage = msg;
|
||||
return m;
|
||||
}
|
||||
}
|
||||
return new InputEventMessage(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the message to the pool.
|
||||
*/
|
||||
public void recycle() {
|
||||
mMessage.recycle();
|
||||
synchronized (sPoolSync) {
|
||||
if (sPoolSize < MAX_POOL_SIZE) {
|
||||
mNext = sPool;
|
||||
sPool = this;
|
||||
sPoolSize++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Place the input event message at the end of the current pending list
|
||||
*/
|
||||
private void enqueueInputEvent(Message msg, long when) {
|
||||
InputEventMessage inputMessage = InputEventMessage.obtain(msg);
|
||||
if (mPendingInputEvents == null) {
|
||||
mPendingInputEvents = inputMessage;
|
||||
} else {
|
||||
InputEventMessage currMessage = mPendingInputEvents;
|
||||
while (currMessage.mNext != null) {
|
||||
currMessage = currMessage.mNext;
|
||||
}
|
||||
currMessage.mNext = inputMessage;
|
||||
}
|
||||
sendEmptyMessageAtTime(PROCESS_INPUT_EVENTS, when);
|
||||
}
|
||||
|
||||
public void dispatchKey(KeyEvent event) {
|
||||
dispatchKey(event, false);
|
||||
}
|
||||
|
||||
private void dispatchKey(KeyEvent event, boolean sendDone) {
|
||||
//noinspection ConstantConditions
|
||||
if (false && event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||
if (event.getKeyCode() == KeyEvent.KEYCODE_CAMERA) {
|
||||
if (DBG) Log.d("keydisp", "===================================================");
|
||||
if (DBG) Log.d("keydisp", "Focused view Hierarchy is:");
|
||||
|
||||
debug();
|
||||
|
||||
if (DBG) Log.d("keydisp", "===================================================");
|
||||
}
|
||||
}
|
||||
|
||||
Message msg = obtainMessage(DISPATCH_KEY);
|
||||
msg.obj = event;
|
||||
msg.arg1 = sendDone ? 1 : 0;
|
||||
|
||||
if (LOCAL_LOGV) Log.v(
|
||||
TAG, "sending key " + event + " to " + mView);
|
||||
|
||||
enqueueInputEvent(msg, event.getEventTime());
|
||||
}
|
||||
|
||||
private void dispatchMotion(MotionEvent event, boolean sendDone) {
|
||||
int source = event.getSource();
|
||||
if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
|
||||
dispatchPointer(event, sendDone);
|
||||
} else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
|
||||
dispatchTrackball(event, sendDone);
|
||||
} else {
|
||||
dispatchGenericMotion(event, sendDone);
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchPointer(MotionEvent event, boolean sendDone) {
|
||||
Message msg = obtainMessage(DISPATCH_POINTER);
|
||||
msg.obj = event;
|
||||
msg.arg1 = sendDone ? 1 : 0;
|
||||
enqueueInputEvent(msg, event.getEventTime());
|
||||
}
|
||||
|
||||
private void dispatchTrackball(MotionEvent event, boolean sendDone) {
|
||||
Message msg = obtainMessage(DISPATCH_TRACKBALL);
|
||||
msg.obj = event;
|
||||
msg.arg1 = sendDone ? 1 : 0;
|
||||
enqueueInputEvent(msg, event.getEventTime());
|
||||
}
|
||||
|
||||
private void dispatchGenericMotion(MotionEvent event, boolean sendDone) {
|
||||
Message msg = obtainMessage(DISPATCH_GENERIC_MOTION);
|
||||
msg.obj = event;
|
||||
msg.arg1 = sendDone ? 1 : 0;
|
||||
enqueueInputEvent(msg, event.getEventTime());
|
||||
enqueueInputEvent(event, null, 0);
|
||||
}
|
||||
|
||||
public void dispatchAppVisibility(boolean visible) {
|
||||
@@ -4126,7 +4057,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
public void finishedEvent(int seq, boolean handled) {
|
||||
final ViewRootImpl viewAncestor = mViewAncestor.get();
|
||||
if (viewAncestor != null) {
|
||||
viewAncestor.dispatchFinishedEvent(seq, handled);
|
||||
viewAncestor.dispatchImeFinishedEvent(seq, handled);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.internal.view;
|
||||
|
||||
import android.view.InputHandler;
|
||||
import android.view.InputQueue;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
/**
|
||||
* Base do-nothing implementation of an input handler.
|
||||
* @hide
|
||||
*/
|
||||
public abstract class BaseInputHandler implements InputHandler {
|
||||
public void handleKey(KeyEvent event, InputQueue.FinishedCallback finishedCallback) {
|
||||
finishedCallback.finished(false);
|
||||
}
|
||||
|
||||
public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) {
|
||||
finishedCallback.finished(false);
|
||||
}
|
||||
}
|
||||
@@ -45,8 +45,7 @@ namespace android {
|
||||
static struct {
|
||||
jclass clazz;
|
||||
|
||||
jmethodID dispatchKeyEvent;
|
||||
jmethodID dispatchMotionEvent;
|
||||
jmethodID dispatchInputEvent;
|
||||
} gInputQueueClassInfo;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -365,7 +364,6 @@ int NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* dat
|
||||
int32_t inputEventType = inputEvent->getType();
|
||||
|
||||
jobject inputEventObj;
|
||||
jmethodID dispatchMethodId;
|
||||
switch (inputEventType) {
|
||||
case AINPUT_EVENT_TYPE_KEY:
|
||||
#if DEBUG_DISPATCH_CYCLE
|
||||
@@ -373,7 +371,6 @@ int NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* dat
|
||||
#endif
|
||||
inputEventObj = android_view_KeyEvent_fromNative(env,
|
||||
static_cast<KeyEvent*>(inputEvent));
|
||||
dispatchMethodId = gInputQueueClassInfo.dispatchKeyEvent;
|
||||
break;
|
||||
|
||||
case AINPUT_EVENT_TYPE_MOTION:
|
||||
@@ -382,7 +379,6 @@ int NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* dat
|
||||
#endif
|
||||
inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
|
||||
static_cast<MotionEvent*>(inputEvent));
|
||||
dispatchMethodId = gInputQueueClassInfo.dispatchMotionEvent;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -402,7 +398,7 @@ int NativeInputQueue::handleReceiveCallback(int receiveFd, int events, void* dat
|
||||
LOGD("Invoking input handler.");
|
||||
#endif
|
||||
env->CallStaticVoidMethod(gInputQueueClassInfo.clazz,
|
||||
dispatchMethodId, inputHandlerObjLocal, inputEventObj,
|
||||
gInputQueueClassInfo.dispatchInputEvent, inputHandlerObjLocal, inputEventObj,
|
||||
jlong(finishedToken));
|
||||
#if DEBUG_DISPATCH_CYCLE
|
||||
LOGD("Returned from input handler.");
|
||||
@@ -517,13 +513,9 @@ int register_android_view_InputQueue(JNIEnv* env) {
|
||||
|
||||
FIND_CLASS(gInputQueueClassInfo.clazz, "android/view/InputQueue");
|
||||
|
||||
GET_STATIC_METHOD_ID(gInputQueueClassInfo.dispatchKeyEvent, gInputQueueClassInfo.clazz,
|
||||
"dispatchKeyEvent",
|
||||
"(Landroid/view/InputHandler;Landroid/view/KeyEvent;J)V");
|
||||
|
||||
GET_STATIC_METHOD_ID(gInputQueueClassInfo.dispatchMotionEvent, gInputQueueClassInfo.clazz,
|
||||
"dispatchMotionEvent",
|
||||
"(Landroid/view/InputHandler;Landroid/view/MotionEvent;J)V");
|
||||
GET_STATIC_METHOD_ID(gInputQueueClassInfo.dispatchInputEvent, gInputQueueClassInfo.clazz,
|
||||
"dispatchInputEvent",
|
||||
"(Landroid/view/InputHandler;Landroid/view/InputEvent;J)V");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@ import com.android.internal.app.ShutdownThread;
|
||||
import com.android.internal.policy.PolicyManager;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.internal.telephony.ITelephony;
|
||||
import com.android.internal.view.BaseInputHandler;
|
||||
import com.android.internal.widget.PointerLocationView;
|
||||
|
||||
import android.util.DisplayMetrics;
|
||||
@@ -75,6 +74,7 @@ import android.view.IApplicationToken;
|
||||
import android.view.IWindowManager;
|
||||
import android.view.InputChannel;
|
||||
import android.view.InputDevice;
|
||||
import android.view.InputEvent;
|
||||
import android.view.InputQueue;
|
||||
import android.view.InputHandler;
|
||||
import android.view.KeyCharacterMap;
|
||||
@@ -345,15 +345,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
WindowState mFocusedWindow;
|
||||
IApplicationToken mFocusedApp;
|
||||
|
||||
private final InputHandler mPointerLocationInputHandler = new BaseInputHandler() {
|
||||
private final InputHandler mPointerLocationInputHandler = new InputHandler() {
|
||||
@Override
|
||||
public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) {
|
||||
public void handleInputEvent(InputEvent event,
|
||||
InputQueue.FinishedCallback finishedCallback) {
|
||||
boolean handled = false;
|
||||
try {
|
||||
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
|
||||
if (event instanceof MotionEvent
|
||||
&& (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
|
||||
final MotionEvent motionEvent = (MotionEvent)event;
|
||||
synchronized (mLock) {
|
||||
if (mPointerLocationView != null) {
|
||||
mPointerLocationView.addPointerEvent(event);
|
||||
mPointerLocationView.addPointerEvent(motionEvent);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
@@ -1836,13 +1839,16 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
* to determine when the nav bar should be shown and prevent applications from
|
||||
* receiving those touches.
|
||||
*/
|
||||
final InputHandler mHideNavInputHandler = new BaseInputHandler() {
|
||||
final InputHandler mHideNavInputHandler = new InputHandler() {
|
||||
@Override
|
||||
public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) {
|
||||
public void handleInputEvent(InputEvent event,
|
||||
InputQueue.FinishedCallback finishedCallback) {
|
||||
boolean handled = false;
|
||||
try {
|
||||
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
if (event instanceof MotionEvent
|
||||
&& (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
|
||||
final MotionEvent motionEvent = (MotionEvent)event;
|
||||
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
// When the user taps down, we re-show the nav bar.
|
||||
boolean changed = false;
|
||||
synchronized (mLock) {
|
||||
|
||||
@@ -36,7 +36,6 @@ import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
|
||||
import com.android.internal.app.IBatteryStats;
|
||||
import com.android.internal.policy.PolicyManager;
|
||||
import com.android.internal.policy.impl.PhoneWindowManager;
|
||||
import com.android.internal.view.BaseInputHandler;
|
||||
import com.android.internal.view.IInputContext;
|
||||
import com.android.internal.view.IInputMethodClient;
|
||||
import com.android.internal.view.IInputMethodManager;
|
||||
@@ -571,18 +570,21 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
boolean mTurnOnScreen;
|
||||
|
||||
DragState mDragState = null;
|
||||
final InputHandler mDragInputHandler = new BaseInputHandler() {
|
||||
final InputHandler mDragInputHandler = new InputHandler() {
|
||||
@Override
|
||||
public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) {
|
||||
public void handleInputEvent(InputEvent event,
|
||||
InputQueue.FinishedCallback finishedCallback) {
|
||||
boolean handled = false;
|
||||
try {
|
||||
if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0
|
||||
if (event instanceof MotionEvent
|
||||
&& (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0
|
||||
&& mDragState != null) {
|
||||
final MotionEvent motionEvent = (MotionEvent)event;
|
||||
boolean endDrag = false;
|
||||
final float newX = event.getRawX();
|
||||
final float newY = event.getRawY();
|
||||
final float newX = motionEvent.getRawX();
|
||||
final float newY = motionEvent.getRawY();
|
||||
|
||||
switch (event.getAction()) {
|
||||
switch (motionEvent.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN: {
|
||||
if (DEBUG_DRAG) {
|
||||
Slog.w(TAG, "Unexpected ACTION_DOWN in drag layer");
|
||||
|
||||
Reference in New Issue
Block a user