private void enqueueUiEventUnbatchedLocked(DispatchEvent d) { if (DEBUG) { Log.d(TAG, "enqueueUiEventUnbatchedLocked: enqueued event " + d.mEvent); } mUiDispatchEventQueue.enqueue(d); scheduleUiDispatchLocked(); }
private void enqueueWebKitEventUnbatchedLocked(DispatchEvent d) { if (DEBUG) { Log.d(TAG, "enqueueWebKitEventUnbatchedLocked: enqueued event " + d.mEvent); } mWebKitDispatchEventQueue.enqueue(d); scheduleWebKitDispatchLocked(); updateWebKitTimeoutLocked(); }
private void enqueueUiCancelTouchEventIfNeededLocked() { // We want to cancel touch events that were delivered to the UI. // Enqueue a null event at the end of the queue if needed. if (mUiTouchStream.isCancelNeeded() || !mUiDispatchEventQueue.isEmpty()) { DispatchEvent d = obtainDispatchEventLocked(null, EVENT_TYPE_TOUCH, FLAG_PRIVATE, 0, 0, 1.0f); enqueueUiEventUnbatchedLocked(d); } }
private void enqueueWebKitCancelTouchEventIfNeededLocked() { // We want to cancel touch events that were delivered to web kit. // Enqueue a null event at the end of the queue if needed. if (mWebKitTouchStream.isCancelNeeded() || !mWebKitDispatchEventQueue.isEmpty()) { DispatchEvent d = obtainDispatchEventLocked(null, EVENT_TYPE_TOUCH, FLAG_PRIVATE, 0, 0, 1.0f); enqueueWebKitEventUnbatchedLocked(d); mPostDoNotSendTouchEventsToWebKitUntilNextGesture = true; } }
private void drainStaleWebKitEventsLocked() { DispatchEvent d = mWebKitDispatchEventQueue.mHead; while (d != null && d.mNext != null && isMoveEventLocked(d) && isMoveEventLocked(d.mNext)) { DispatchEvent next = d.mNext; skipWebKitEventLocked(d); d = next; } mWebKitDispatchEventQueue.mHead = d; }
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(); } } }
// Runs on UI thread in response to the web kit thread appearing to be unresponsive. private void handleWebKitTimeout() { synchronized (mLock) { if (!mWebKitTimeoutScheduled) { return; } mWebKitTimeoutScheduled = false; if (DEBUG) { Log.d(TAG, "handleWebKitTimeout: timeout occurred!"); } // Drain the web kit event queue. DispatchEvent d = mWebKitDispatchEventQueue.dequeueList(); // If web kit was processing an event (must be at the head of the list because // it can only do one at a time), then clone it or ignore it. if ((d.mFlags & FLAG_WEBKIT_IN_PROGRESS) != 0) { d.mFlags |= FLAG_WEBKIT_TIMEOUT; if ((d.mFlags & FLAG_PRIVATE) != 0) { d = d.mNext; // the event is private to web kit, ignore it } else { d = copyDispatchEventLocked(d); d.mFlags &= ~FLAG_WEBKIT_IN_PROGRESS; } } // Enqueue all non-private events for handling by the UI thread. while (d != null) { DispatchEvent next = d.mNext; skipWebKitEventLocked(d); d = next; } // Tell web kit to cancel all pending touches. // This also prevents us from sending web kit any more touches until the // next gesture begins. (As required to ensure touch event stream consistency.) enqueueWebKitCancelTouchEventIfNeededLocked(); } }
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(); } } } }