diff options
Diffstat (limited to 'core/java/android/view/ViewRoot.java')
-rw-r--r-- | core/java/android/view/ViewRoot.java | 433 |
1 files changed, 234 insertions, 199 deletions
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 5b18715..fa7fe80 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -53,6 +53,7 @@ import android.util.EventLog; import android.util.Log; import android.util.Slog; import android.util.SparseArray; +import android.view.InputQueue.FinishedCallback; import android.view.View.MeasureSpec; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; @@ -1742,34 +1743,14 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn handleFinishedEvent(msg.arg1, msg.arg2 != 0); break; case DISPATCH_KEY: - if (LOCAL_LOGV) Log.v( - TAG, "Dispatching key " - + msg.obj + " to " + mView); deliverKeyEvent((KeyEvent)msg.obj, msg.arg1 != 0); break; - case DISPATCH_POINTER: { - MotionEvent event = (MotionEvent) msg.obj; - try { - deliverPointerEvent(event); - } finally { - event.recycle(); - if (msg.arg1 != 0) { - finishInputEvent(); - } - if (LOCAL_LOGV || WATCH_POINTER) Log.i(TAG, "Done dispatching!"); - } - } break; - case DISPATCH_TRACKBALL: { - MotionEvent event = (MotionEvent) msg.obj; - try { - deliverTrackballEvent(event); - } finally { - event.recycle(); - if (msg.arg1 != 0) { - finishInputEvent(); - } - } - } 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_APP_VISIBILITY: handleAppVisibility(msg.arg1 != 0); break; @@ -1871,7 +1852,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn // system! Bad bad bad! event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM); } - deliverKeyEventToViewHierarchy((KeyEvent)msg.obj, false); + deliverKeyEventPostIme((KeyEvent)msg.obj, false); } break; case FINISH_INPUT_CONNECTION: { InputMethodManager imm = InputMethodManager.peekInstance(); @@ -1897,7 +1878,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn } } - private void startInputEvent(Runnable finishedCallback) { + 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."); @@ -1906,11 +1887,11 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn mFinishedCallback = finishedCallback; } - private void finishInputEvent() { + private void finishInputEvent(boolean handled) { if (LOCAL_LOGV) Log.v(TAG, "Telling window manager input event is finished"); if (mFinishedCallback != null) { - mFinishedCallback.run(); + mFinishedCallback.finished(handled); mFinishedCallback = null; } else { Slog.w(TAG, "Attempted to tell the input queue that the current input event " @@ -2039,105 +2020,134 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn return false; } - private void deliverPointerEvent(MotionEvent event) { + private void deliverPointerEvent(MotionEvent event, boolean sendDone) { + // If there is no view, then the event will not be handled. + if (mView == null || !mAdded) { + finishPointerEvent(event, sendDone, false); + return; + } + + // Translate the pointer event for compatibility, if needed. if (mTranslator != null) { mTranslator.translateEventInScreenToAppWindow(event); } - - boolean handled; - if (mView != null && mAdded) { - // enter touch mode on the down - boolean isDown = event.getAction() == MotionEvent.ACTION_DOWN; - if (isDown) { - ensureTouchMode(true); - } - if(Config.LOGV) { - captureMotionLog("captureDispatchPointer", event); - } - if (mCurScrollY != 0) { - event.offsetLocation(0, mCurScrollY); - } - if (MEASURE_LATENCY) { - lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano()); - } - // cache for possible drag-initiation - mLastTouchPoint.x = event.getRawX(); - mLastTouchPoint.y = event.getRawY(); - handled = mView.dispatchTouchEvent(event); - if (MEASURE_LATENCY) { - lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano()); - } - if (!handled && isDown) { - int edgeSlop = mViewConfiguration.getScaledEdgeSlop(); - - final int edgeFlags = event.getEdgeFlags(); - int direction = View.FOCUS_UP; - int x = (int)event.getX(); - int y = (int)event.getY(); - final int[] deltas = new int[2]; - - if ((edgeFlags & MotionEvent.EDGE_TOP) != 0) { - direction = View.FOCUS_DOWN; - if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) { - deltas[0] = edgeSlop; - x += edgeSlop; - } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) { - deltas[0] = -edgeSlop; - x -= edgeSlop; - } - } else if ((edgeFlags & MotionEvent.EDGE_BOTTOM) != 0) { - direction = View.FOCUS_UP; - if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) { - deltas[0] = edgeSlop; - x += edgeSlop; - } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) { - deltas[0] = -edgeSlop; - x -= edgeSlop; - } - } else if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) { - direction = View.FOCUS_RIGHT; - } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) { - direction = View.FOCUS_LEFT; - } + // Enter touch mode on the down. + boolean isDown = event.getAction() == MotionEvent.ACTION_DOWN; + if (isDown) { + ensureTouchMode(true); + } + if(Config.LOGV) { + captureMotionLog("captureDispatchPointer", event); + } - if (edgeFlags != 0 && mView instanceof ViewGroup) { - View nearest = FocusFinder.getInstance().findNearestTouchable( - ((ViewGroup) mView), x, y, direction, deltas); - if (nearest != null) { - event.offsetLocation(deltas[0], deltas[1]); - event.setEdgeFlags(0); - mView.dispatchTouchEvent(event); - } + // Offset the scroll position. + if (mCurScrollY != 0) { + event.offsetLocation(0, mCurScrollY); + } + if (MEASURE_LATENCY) { + lt.sample("A Dispatching TouchEvents", System.nanoTime() - event.getEventTimeNano()); + } + + // Remember the touch position for possible drag-initiation. + mLastTouchPoint.x = event.getRawX(); + mLastTouchPoint.y = event.getRawY(); + + // Dispatch touch to view hierarchy. + boolean handled = mView.dispatchTouchEvent(event); + if (MEASURE_LATENCY) { + lt.sample("B Dispatched TouchEvents ", System.nanoTime() - event.getEventTimeNano()); + } + if (handled) { + finishPointerEvent(event, sendDone, true); + return; + } + + // Apply edge slop and try again, if appropriate. + final int edgeFlags = event.getEdgeFlags(); + if (edgeFlags != 0 && mView instanceof ViewGroup) { + final int edgeSlop = mViewConfiguration.getScaledEdgeSlop(); + int direction = View.FOCUS_UP; + int x = (int)event.getX(); + int y = (int)event.getY(); + final int[] deltas = new int[2]; + + if ((edgeFlags & MotionEvent.EDGE_TOP) != 0) { + direction = View.FOCUS_DOWN; + if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) { + deltas[0] = edgeSlop; + x += edgeSlop; + } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) { + deltas[0] = -edgeSlop; + x -= edgeSlop; + } + } else if ((edgeFlags & MotionEvent.EDGE_BOTTOM) != 0) { + direction = View.FOCUS_UP; + if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) { + deltas[0] = edgeSlop; + x += edgeSlop; + } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) { + deltas[0] = -edgeSlop; + x -= edgeSlop; + } + } else if ((edgeFlags & MotionEvent.EDGE_LEFT) != 0) { + direction = View.FOCUS_RIGHT; + } else if ((edgeFlags & MotionEvent.EDGE_RIGHT) != 0) { + direction = View.FOCUS_LEFT; + } + + View nearest = FocusFinder.getInstance().findNearestTouchable( + ((ViewGroup) mView), x, y, direction, deltas); + if (nearest != null) { + event.offsetLocation(deltas[0], deltas[1]); + event.setEdgeFlags(0); + if (mView.dispatchTouchEvent(event)) { + finishPointerEvent(event, sendDone, true); + return; } } } + + // Pointer event was unhandled. + finishPointerEvent(event, sendDone, false); } - private void deliverTrackballEvent(MotionEvent event) { + private void finishPointerEvent(MotionEvent event, boolean sendDone, boolean handled) { + event.recycle(); + if (sendDone) { + finishInputEvent(handled); + } + if (LOCAL_LOGV || WATCH_POINTER) Log.i(TAG, "Done dispatching!"); + } + + private void deliverTrackballEvent(MotionEvent event, boolean sendDone) { if (DEBUG_TRACKBALL) Log.v(TAG, "Motion event:" + event); - boolean handled = false; - if (mView != null && mAdded) { - handled = mView.dispatchTrackballEvent(event); - if (handled) { - // If we reach this, we delivered a trackball event to mView and - // mView consumed it. Because we will not translate the trackball - // event into a key event, touch mode will not exit, so we exit - // touch mode here. - ensureTouchMode(false); - return; - } - - // Otherwise we could do something here, like changing the focus - // or something? + // If there is no view, then the event will not be handled. + if (mView == null || !mAdded) { + finishTrackballEvent(event, sendDone, false); + return; + } + + // Deliver the trackball event to the view. + if (mView.dispatchTrackballEvent(event)) { + // If we reach this, we delivered a trackball event to mView and + // mView consumed it. Because we will not translate the trackball + // event into a key event, touch mode will not exit, so we exit + // touch mode here. + ensureTouchMode(false); + + finishTrackballEvent(event, sendDone, true); + mLastTrackballTime = Integer.MIN_VALUE; + return; } + // Translate the trackball event into DPAD keys and try to deliver those. final TrackballAxis x = mTrackballAxisX; final TrackballAxis y = mTrackballAxisY; long curTime = SystemClock.uptimeMillis(); - if ((mLastTrackballTime+MAX_TRACKBALL_DELAY) < curTime) { + if ((mLastTrackballTime + MAX_TRACKBALL_DELAY) < curTime) { // It has been too long since the last movement, // so restart at the beginning. x.reset(0); @@ -2226,6 +2236,17 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn } mLastTrackballTime = curTime; } + + // Unfortunately we can't tell whether the application consumed the keys, so + // we always consider the trackball event handled. + finishTrackballEvent(event, sendDone, true); + } + + private void finishTrackballEvent(MotionEvent event, boolean sendDone, boolean handled) { + event.recycle(); + if (sendDone) { + finishInputEvent(handled); + } } /** @@ -2371,123 +2392,137 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn } private void deliverKeyEvent(KeyEvent event, boolean sendDone) { - // If mView is null, we just consume the key event because it doesn't - // make sense to do anything else with it. - boolean handled = mView == null || mView.dispatchKeyEventPreIme(event); - if (handled) { - if (sendDone) { - finishInputEvent(); - } + // 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; } - // If it is possible for this window to interact with the input - // method window, then we want to first dispatch our key events - // to the input method. + + // 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 && mView != null) { + 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); + imm.dispatchKeyEvent(mView.getContext(), seq, event, mInputMethodCallback); return; } } - deliverKeyEventToViewHierarchy(event, sendDone); + + // Not dispatching to IME, continue with post IME actions. + deliverKeyEventPostIme(event, sendDone); } - void handleFinishedEvent(int seq, boolean handled) { + 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; - if (!handled) { - deliverKeyEventToViewHierarchy(event, sendDone); - } else if (sendDone) { - finishInputEvent(); + if (handled) { + finishKeyEvent(event, sendDone, true); } else { - Log.w(TAG, "handleFinishedEvent(seq=" + seq - + " handled=" + handled + " ev=" + event - + ") neither delivering nor finishing key"); + deliverKeyEventPostIme(event, sendDone); } } } - private void deliverKeyEventToViewHierarchy(KeyEvent event, boolean sendDone) { - try { - if (mView != null && mAdded) { - final int action = event.getAction(); - boolean isDown = (action == KeyEvent.ACTION_DOWN); + private void deliverKeyEventPostIme(KeyEvent event, boolean sendDone) { + // If the view went away, then the event will not be handled. + if (mView == null || !mAdded) { + finishKeyEvent(event, sendDone, false); + return; + } - if (checkForLeavingTouchModeAndConsume(event)) { - 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); + return; + } - if (Config.LOGV) { - captureKeyLog("captureDispatchKeyEvent", event); - } - mFallbackEventHandler.preDispatchKeyEvent(event); - boolean keyHandled = mView.dispatchKeyEvent(event); + if (Config.LOGV) { + captureKeyLog("captureDispatchKeyEvent", event); + } - if (!keyHandled) { - mFallbackEventHandler.dispatchKeyEvent(event); - } + // Deliver the key to the view hierarchy. + if (mView.dispatchKeyEvent(event)) { + finishKeyEvent(event, sendDone, true); + return; + } - if (!keyHandled && isDown) { - int direction = 0; - switch (event.getKeyCode()) { - case KeyEvent.KEYCODE_DPAD_LEFT: - direction = View.FOCUS_LEFT; - break; - case KeyEvent.KEYCODE_DPAD_RIGHT: - direction = View.FOCUS_RIGHT; - break; - case KeyEvent.KEYCODE_DPAD_UP: - direction = View.FOCUS_UP; - break; - case KeyEvent.KEYCODE_DPAD_DOWN: - direction = View.FOCUS_DOWN; - break; - } + // Apply the fallback event policy. + if (mFallbackEventHandler.dispatchKeyEvent(event)) { + finishKeyEvent(event, sendDone, true); + return; + } - if (direction != 0) { - - View focused = mView != null ? mView.findFocus() : null; - if (focused != null) { - View v = focused.focusSearch(direction); - boolean focusPassed = false; - if (v != null && v != focused) { - // do the math the get the interesting rect - // of previous focused into the coord system of - // newly focused view - focused.getFocusedRect(mTempRect); - if (mView instanceof ViewGroup) { - ((ViewGroup) mView).offsetDescendantRectToMyCoords( - focused, mTempRect); - ((ViewGroup) mView).offsetRectIntoDescendantCoords( - v, mTempRect); - } - focusPassed = v.requestFocus(direction, mTempRect); - } + // Handle automatic focus changes. + if (event.getAction() == KeyEvent.ACTION_DOWN) { + int direction = 0; + switch (event.getKeyCode()) { + case KeyEvent.KEYCODE_DPAD_LEFT: + direction = View.FOCUS_LEFT; + break; + case KeyEvent.KEYCODE_DPAD_RIGHT: + direction = View.FOCUS_RIGHT; + break; + case KeyEvent.KEYCODE_DPAD_UP: + direction = View.FOCUS_UP; + break; + case KeyEvent.KEYCODE_DPAD_DOWN: + direction = View.FOCUS_DOWN; + break; + } - if (!focusPassed) { - mView.dispatchUnhandledMove(focused, direction); - } else { - playSoundEffect(SoundEffectConstants.getContantForFocusDirection(direction)); - } + if (direction != 0) { + View focused = mView != null ? mView.findFocus() : null; + if (focused != null) { + View v = focused.focusSearch(direction); + if (v != null && v != focused) { + // do the math the get the interesting rect + // of previous focused into the coord system of + // newly focused view + focused.getFocusedRect(mTempRect); + if (mView instanceof ViewGroup) { + ((ViewGroup) mView).offsetDescendantRectToMyCoords( + focused, mTempRect); + ((ViewGroup) mView).offsetRectIntoDescendantCoords( + v, mTempRect); + } + if (v.requestFocus(direction, mTempRect)) { + playSoundEffect( + SoundEffectConstants.getContantForFocusDirection(direction)); + finishKeyEvent(event, sendDone, true); + return; } } + + // Give the focused view a last chance to handle the dpad key. + if (mView.dispatchUnhandledMove(focused, direction)) { + finishKeyEvent(event, sendDone, true); + return; + } } } + } - } finally { - if (sendDone) { - finishInputEvent(); - } - // Let the exception fall through -- the looper will catch - // it and take care of the bad app for us. + // Key was unhandled. + finishKeyEvent(event, sendDone, false); + } + + private void finishKeyEvent(KeyEvent event, boolean sendDone, boolean handled) { + if (sendDone) { + finishInputEvent(handled); } } @@ -2759,15 +2794,15 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn sendMessage(msg); } - private Runnable mFinishedCallback; + private InputQueue.FinishedCallback mFinishedCallback; private final InputHandler mInputHandler = new InputHandler() { - public void handleKey(KeyEvent event, Runnable finishedCallback) { + public void handleKey(KeyEvent event, InputQueue.FinishedCallback finishedCallback) { startInputEvent(finishedCallback); dispatchKey(event, true); } - public void handleMotion(MotionEvent event, Runnable finishedCallback) { + public void handleMotion(MotionEvent event, InputQueue.FinishedCallback finishedCallback) { startInputEvent(finishedCallback); dispatchMotion(event, true); } @@ -2814,7 +2849,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn // TODO Log.v(TAG, "Dropping unsupported motion event (unimplemented): " + event); if (sendDone) { - finishInputEvent(); + finishInputEvent(false); } } } |