diff options
| -rw-r--r-- | core/java/android/service/wallpaper/WallpaperService.java | 12 | ||||
| -rw-r--r-- | core/java/android/view/InputHandler.java | 20 | ||||
| -rw-r--r-- | core/java/android/view/InputQueue.java | 13 | ||||
| -rw-r--r-- | core/java/android/view/ViewRootImpl.java | 625 | ||||
| -rw-r--r-- | core/java/com/android/internal/view/BaseInputHandler.java | 36 | ||||
| -rw-r--r-- | core/jni/android_view_InputQueue.cpp | 18 | ||||
| -rwxr-xr-x | policy/src/com/android/internal/policy/impl/PhoneWindowManager.java | 24 | ||||
| -rw-r--r-- | services/java/com/android/server/wm/WindowManagerService.java | 16 |
8 files changed, 322 insertions, 442 deletions
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 18167b601d32..133549bdf8a3 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -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 { diff --git a/core/java/android/view/InputHandler.java b/core/java/android/view/InputHandler.java index 14ce14c4b87a..192a42794f40 100644 --- a/core/java/android/view/InputHandler.java +++ b/core/java/android/view/InputHandler.java @@ -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); + } } diff --git a/core/java/android/view/InputQueue.java b/core/java/android/view/InputQueue.java index 5735b6397cf0..12065184ccda 100644 --- a/core/java/android/view/InputQueue.java +++ b/core/java/android/view/InputQueue.java @@ -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 diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 6686455c21fe..0e6533412379 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -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); - 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); + case IME_FINISHED_EVENT: + handleImeFinishedEvent(msg.arg1, msg.arg2 != 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); - } - - 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!"); - } - } + finishInputEvent(q, false); } - 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 ((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); + 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); + // 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); - } - - public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) { - startInputEvent(finishedCallback); - dispatchMotion(event, true); - } - }; - /** - * 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. + * 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. */ - static class InputEventMessage { - Message mMessage; - InputEventMessage mNext; + private static final class QueuedInputEvent { + public static final int FLAG_DELIVER_POST_IME = 1 << 0; - private static final Object sPoolSync = new Object(); - private static InputEventMessage sPool; - private static int sPoolSize = 0; + public QueuedInputEvent mNext; - private static final int MAX_POOL_SIZE = 10; + public InputEvent mEvent; + public InputQueue.FinishedCallback mFinishedCallback; + public int mFlags; + public int mSeq; - private InputEventMessage(Message m) { - mMessage = m; - mNext = null; - } + // Used for latency calculations. + public long mReceiveTimeNanos; + public long mDeliverTimeNanos; + public long mDeliverPostImeTimeNanos; + } - /** - * 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); + 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(); } - /** - * Return the message to the pool. - */ - public void recycle() { - mMessage.recycle(); - synchronized (sPoolSync) { - if (sPoolSize < MAX_POOL_SIZE) { - mNext = sPool; - sPool = this; - sPoolSize++; - } - } + 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; } } - /** - * 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; + 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 { - InputEventMessage currMessage = mPendingInputEvents; - while (currMessage.mNext != null) { - currMessage = currMessage.mNext; + while (last.mNext != null) { + last = last.mNext; } - currMessage.mNext = inputMessage; + last.mNext = q; } - sendEmptyMessageAtTime(PROCESS_INPUT_EVENTS, when); + + scheduleProcessInputEvents(); } - public void dispatchKey(KeyEvent event) { - dispatchKey(event, false); + private void scheduleProcessInputEvents() { + if (!mProcessInputEventsPending) { + mProcessInputEventsPending = true; + sendEmptyMessage(DO_PROCESS_INPUT_EVENTS); + } } - 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:"); + void processInputEvents() { + while (mCurrentInputEvent == null && mFirstPendingInputEvent != null) { + QueuedInputEvent q = mFirstPendingInputEvent; + mFirstPendingInputEvent = q.mNext; + q.mNext = null; + mCurrentInputEvent = q; + deliverInputEvent(q); + } - debug(); + // 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); + } + } - if (DBG) Log.d("keydisp", "==================================================="); - } + private void finishInputEvent(QueuedInputEvent q, boolean handled) { + if (q != mCurrentInputEvent) { + throw new IllegalStateException("finished input event out of order"); } - Message msg = obtainMessage(DISPATCH_KEY); - msg.obj = event; - msg.arg1 = sendDone ? 1 : 0; + 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 (LOCAL_LOGV) Log.v( - TAG, "sending key " + event + " to " + mView); + if (q.mFinishedCallback != null) { + q.mFinishedCallback.finished(handled); + } - 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); + 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(); } - } - private void dispatchPointer(MotionEvent event, boolean sendDone) { - Message msg = obtainMessage(DISPATCH_POINTER); - msg.obj = event; - msg.arg1 = sendDone ? 1 : 0; - enqueueInputEvent(msg, event.getEventTime()); - } + recycleQueuedInputEvent(q); - private void dispatchTrackball(MotionEvent event, boolean sendDone) { - Message msg = obtainMessage(DISPATCH_TRACKBALL); - msg.obj = event; - msg.arg1 = sendDone ? 1 : 0; - enqueueInputEvent(msg, event.getEventTime()); + mCurrentInputEvent = null; + if (mFirstPendingInputEvent != null) { + scheduleProcessInputEvents(); + } } - 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()); + private final InputHandler mInputHandler = new InputHandler() { + public void handleInputEvent(InputEvent event, + InputQueue.FinishedCallback finishedCallback) { + enqueueInputEvent(event, finishedCallback, 0); + } + }; + + public void dispatchKey(KeyEvent event) { + 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); } } diff --git a/core/java/com/android/internal/view/BaseInputHandler.java b/core/java/com/android/internal/view/BaseInputHandler.java deleted file mode 100644 index 74b4b06eaa25..000000000000 --- a/core/java/com/android/internal/view/BaseInputHandler.java +++ /dev/null @@ -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); - } -} diff --git a/core/jni/android_view_InputQueue.cpp b/core/jni/android_view_InputQueue.cpp index 300c04a03a03..549f5750c39b 100644 --- a/core/jni/android_view_InputQueue.cpp +++ b/core/jni/android_view_InputQueue.cpp @@ -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; } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 7684c34fc167..08cef011f57d 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -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) { diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index f5c2de912710..d7dcacb71df9 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -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"); |