private void dispatchUiEvents(boolean calledFromHandler) { for (; ; ) { MotionEvent event; final int eventType; final int flags; synchronized (mLock) { DispatchEvent d = mUiDispatchEventQueue.dequeue(); if (d == null) { if (mUiDispatchScheduled) { mUiDispatchScheduled = false; if (!calledFromHandler) { mUiHandler.removeMessages(UiHandler.MSG_DISPATCH_UI_EVENTS); } } return; } event = d.mEvent; if (event != null && (d.mFlags & FLAG_WEBKIT_TRANSFORMED_EVENT) != 0) { event.scale(1.0f / d.mWebKitScale); event.offsetLocation(-d.mWebKitXOffset, -d.mWebKitYOffset); d.mFlags &= ~FLAG_WEBKIT_TRANSFORMED_EVENT; } eventType = d.mEventType; if (eventType == EVENT_TYPE_TOUCH) { event = mUiTouchStream.update(event); if (DEBUG && event == null && d.mEvent != null) { Log.d(TAG, "dispatchUiEvents: dropped event " + d.mEvent); } } flags = d.mFlags; if (event == d.mEvent) { d.mEvent = null; // retain ownership of event, don't recycle it yet } recycleDispatchEventLocked(d); if (eventType == EVENT_TYPE_CLICK) { scheduleHideTapHighlightLocked(); } } // Handle the event. if (event != null) { dispatchUiEvent(event, eventType, flags); event.recycle(); } } }
private void dispatchWebKitEvents(boolean calledFromHandler) { for (; ; ) { // Get the next event, but leave it in the queue so we can move it to the UI // queue if a timeout occurs. DispatchEvent d; MotionEvent event; final int eventType; int flags; synchronized (mLock) { if (!ENABLE_EVENT_BATCHING) { drainStaleWebKitEventsLocked(); } d = mWebKitDispatchEventQueue.mHead; if (d == null) { if (mWebKitDispatchScheduled) { mWebKitDispatchScheduled = false; if (!calledFromHandler) { mWebKitHandler.removeMessages(WebKitHandler.MSG_DISPATCH_WEBKIT_EVENTS); } } return; } event = d.mEvent; if (event != null) { event.offsetLocation(d.mWebKitXOffset, d.mWebKitYOffset); event.scale(d.mWebKitScale); d.mFlags |= FLAG_WEBKIT_TRANSFORMED_EVENT; } eventType = d.mEventType; if (eventType == EVENT_TYPE_TOUCH) { event = mWebKitTouchStream.update(event); if (DEBUG && event == null && d.mEvent != null) { Log.d(TAG, "dispatchWebKitEvents: dropped event " + d.mEvent); } } d.mFlags |= FLAG_WEBKIT_IN_PROGRESS; flags = d.mFlags; } // Handle the event. final boolean preventDefault; if (event == null) { preventDefault = false; } else { preventDefault = dispatchWebKitEvent(event, eventType, flags); } synchronized (mLock) { /// M: update last event prevent status. @ { boolean lastPreventDefault = false; if (d.mEventType == EVENT_TYPE_TOUCH) { lastPreventDefault = mWebKitPreventTouchStream.update(event, preventDefault); } /// @ } flags = d.mFlags; d.mFlags = flags & ~FLAG_WEBKIT_IN_PROGRESS; boolean recycleEvent = event != d.mEvent; if ((flags & FLAG_WEBKIT_TIMEOUT) != 0) { // A timeout occurred! recycleDispatchEventLocked(d); } else { // Web kit finished in a timely manner. Dequeue the event. assert mWebKitDispatchEventQueue.mHead == d; mWebKitDispatchEventQueue.dequeue(); updateWebKitTimeoutLocked(); if ((flags & FLAG_PRIVATE) != 0) { // Event was intended for web kit only. All done. recycleDispatchEventLocked(d); } else if (preventDefault) { // Web kit has decided to consume the event! if (d.mEventType == EVENT_TYPE_TOUCH) { /// M: Consider two consistent events is preventDefault. @ { if (lastPreventDefault) { Log.d(TAG, "Webkit prevent current and last event, cancel ui event"); enqueueUiCancelTouchEventIfNeededLocked(); } else { Log.d(TAG, "Webkit prevent current but not last event, enqueue ui event"); /// Only one event is preventDefault, Ui also handle this touch event. enqueueUiEventUnbatchedLocked(d); } unscheduleLongPressLocked(); /// @ } } } else { // Web kit is being friendly. Pass the event to the UI. enqueueUiEventUnbatchedLocked(d); } } if (event != null && recycleEvent) { event.recycle(); } if (eventType == EVENT_TYPE_CLICK) { scheduleHideTapHighlightLocked(); } } } }
/** * Posts a pointer event to the dispatch queue. * * @param event The event to post. * @param webKitXOffset X offset to apply to events before dispatching them to web kit. * @param webKitYOffset Y offset to apply to events before dispatching them to web kit. * @param webKitScale The scale factor to apply to translated events before dispatching them to * web kit. * @return True if the dispatcher will handle the event, false if the event is unsupported. */ public boolean postPointerEvent( MotionEvent event, int webKitXOffset, int webKitYOffset, float webKitScale) { if (event == null) { throw new IllegalArgumentException("event cannot be null"); } if (DEBUG) { Log.d(TAG, "postPointerEvent: " + event); } final int action = event.getActionMasked(); final int eventType; switch (action) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: case MotionEvent.ACTION_UP: case MotionEvent.ACTION_POINTER_DOWN: case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_CANCEL: eventType = EVENT_TYPE_TOUCH; break; case MotionEvent.ACTION_SCROLL: eventType = EVENT_TYPE_SCROLL; break; case MotionEvent.ACTION_HOVER_ENTER: case MotionEvent.ACTION_HOVER_MOVE: case MotionEvent.ACTION_HOVER_EXIT: eventType = EVENT_TYPE_HOVER; break; default: return false; // currently unsupported event type } synchronized (mLock) { // Ensure that the event is consistent and should be delivered. MotionEvent eventToEnqueue = event; if (eventType == EVENT_TYPE_TOUCH) { eventToEnqueue = mPostTouchStream.update(event); if (eventToEnqueue == null) { if (DEBUG) { Log.d(TAG, "postPointerEvent: dropped event " + event); } unscheduleLongPressLocked(); unscheduleClickLocked(); hideTapCandidateLocked(); return false; } if (action == MotionEvent.ACTION_DOWN && mPostSendTouchEventsToWebKit) { if (mUiCallbacks.shouldInterceptTouchEvent(eventToEnqueue)) { mPostDoNotSendTouchEventsToWebKitUntilNextGesture = true; } else if (mPostDoNotSendTouchEventsToWebKitUntilNextGesture) { // Recover from a previous web kit timeout. mPostDoNotSendTouchEventsToWebKitUntilNextGesture = false; } } } // Copy the event because we need to retain ownership. if (eventToEnqueue == event) { eventToEnqueue = event.copy(); } DispatchEvent d = obtainDispatchEventLocked( eventToEnqueue, eventType, 0, webKitXOffset, webKitYOffset, webKitScale); updateStateTrackersLocked(d, event); enqueueEventLocked(d); } return true; }