private void skipWebKitEventLocked(DispatchEvent d) { d.mNext = null; if ((d.mFlags & FLAG_PRIVATE) != 0) { recycleDispatchEventLocked(d); } else { d.mFlags |= FLAG_WEBKIT_TIMEOUT; enqueueUiEventUnbatchedLocked(d); } }
private DispatchEvent obtainUninitializedDispatchEventLocked() { DispatchEvent d = mDispatchEventPool; if (d != null) { mDispatchEventPoolSize -= 1; mDispatchEventPool = d.mNext; d.mNext = null; } else { d = new DispatchEvent(); } return d; }
private void recycleDispatchEventLocked(DispatchEvent d) { if (d.mEvent != null) { d.mEvent.recycle(); d.mEvent = null; } if (mDispatchEventPoolSize < MAX_DISPATCH_EVENT_POOL_SIZE) { mDispatchEventPoolSize += 1; d.mNext = mDispatchEventPool; mDispatchEventPool = 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(); } } }
public DispatchEvent dequeue() { DispatchEvent d = mHead; if (d != null) { DispatchEvent next = d.mNext; if (next == null) { mHead = null; mTail = null; } else { mHead = next; d.mNext = null; } } return d; }
private DispatchEvent copyDispatchEventLocked(DispatchEvent d) { DispatchEvent copy = obtainUninitializedDispatchEventLocked(); if (d.mEvent != null) { copy.mEvent = d.mEvent.copy(); } copy.mEventType = d.mEventType; copy.mFlags = d.mFlags; copy.mTimeoutTime = d.mTimeoutTime; copy.mWebKitXOffset = d.mWebKitXOffset; copy.mWebKitYOffset = d.mWebKitYOffset; copy.mWebKitScale = d.mWebKitScale; copy.mNext = d.mNext; return copy; }
public void enqueue(DispatchEvent d) { if (mHead == null) { mHead = d; mTail = d; } else { mTail.mNext = d; mTail = d; } }
// 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 DispatchEvent obtainDispatchEventLocked( MotionEvent event, int eventType, int flags, int webKitXOffset, int webKitYOffset, float webKitScale) { DispatchEvent d = obtainUninitializedDispatchEventLocked(); d.mEvent = event; d.mEventType = eventType; d.mFlags = flags; d.mTimeoutTime = SystemClock.uptimeMillis() + WEBKIT_TIMEOUT_MILLIS; d.mWebKitXOffset = webKitXOffset; d.mWebKitYOffset = webKitYOffset; d.mWebKitScale = webKitScale; if (DEBUG) { Log.d(TAG, "Timeout time: " + (d.mTimeoutTime - SystemClock.uptimeMillis())); } return d; }
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(); } } } }