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();
        }
      }
    }
  }