use of android.webkit.WebViewCore.TouchHighlightData in project XobotOS by xamarin.
the class WebView method handleTouchEventCommon.
/*
* Common code for single touch and multi-touch.
* (x, y) denotes current focus point, which is the touch point for single touch
* and the middle point for multi-touch.
*/
private boolean handleTouchEventCommon(MotionEvent ev, int action, int x, int y) {
long eventTime = ev.getEventTime();
// Due to the touch screen edge effect, a touch closer to the edge
// always snapped to the edge. As getViewWidth() can be different from
// getWidth() due to the scrollbar, adjusting the point to match
// getViewWidth(). Same applied to the height.
x = Math.min(x, getViewWidth() - 1);
y = Math.min(y, getViewHeightWithTitle() - 1);
int deltaX = mLastTouchX - x;
int deltaY = mLastTouchY - y;
int contentX = viewToContentX(x + mScrollX);
int contentY = viewToContentY(y + mScrollY);
switch(action) {
case MotionEvent.ACTION_DOWN:
{
mPreventDefault = PREVENT_DEFAULT_NO;
mConfirmMove = false;
mInitialHitTestResult = null;
if (!mScroller.isFinished()) {
// stop the current scroll animation, but if this is
// the start of a fling, allow it to add to the current
// fling's velocity
mScroller.abortAnimation();
mTouchMode = TOUCH_DRAG_START_MODE;
mConfirmMove = true;
mPrivateHandler.removeMessages(RESUME_WEBCORE_PRIORITY);
} else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) {
mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP);
if (USE_WEBKIT_RINGS || getSettings().supportTouchOnly()) {
removeTouchHighlight();
}
if (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare) {
mTouchMode = TOUCH_DOUBLE_TAP_MODE;
} else {
// commit the short press action for the previous tap
doShortPress();
mTouchMode = TOUCH_INIT_MODE;
mDeferTouchProcess = !mBlockWebkitViewMessages && (!inFullScreenMode() && mForwardTouchEvents) ? hitFocusedPlugin(contentX, contentY) : false;
}
} else {
// the normal case
mTouchMode = TOUCH_INIT_MODE;
mDeferTouchProcess = !mBlockWebkitViewMessages && (!inFullScreenMode() && mForwardTouchEvents) ? hitFocusedPlugin(contentX, contentY) : false;
if (!mBlockWebkitViewMessages) {
mWebViewCore.sendMessage(EventHub.UPDATE_FRAME_CACHE_IF_LOADING);
}
if (USE_WEBKIT_RINGS || getSettings().supportTouchOnly()) {
TouchHighlightData data = new TouchHighlightData();
data.mX = contentX;
data.mY = contentY;
data.mNativeLayerRect = new Rect();
data.mNativeLayer = nativeScrollableLayer(contentX, contentY, data.mNativeLayerRect, null);
data.mSlop = viewToContentDimension(mNavSlop);
mTouchHighlightRegion.setEmpty();
if (!mBlockWebkitViewMessages) {
mTouchHighlightRequested = System.currentTimeMillis();
mWebViewCore.sendMessageAtFrontOfQueue(EventHub.GET_TOUCH_HIGHLIGHT_RECTS, data);
}
if (DEBUG_TOUCH_HIGHLIGHT) {
if (getSettings().getNavDump()) {
mTouchHighlightX = (int) x + mScrollX;
mTouchHighlightY = (int) y + mScrollY;
mPrivateHandler.postDelayed(new Runnable() {
public void run() {
mTouchHighlightX = mTouchHighlightY = 0;
invalidate();
}
}, TOUCH_HIGHLIGHT_ELAPSE_TIME);
}
}
}
if (mLogEvent && eventTime - mLastTouchUpTime < 1000) {
EventLog.writeEvent(EventLogTags.BROWSER_DOUBLE_TAP_DURATION, (eventTime - mLastTouchUpTime), eventTime);
}
if (mSelectingText) {
mDrawSelectionPointer = false;
mSelectionStarted = nativeStartSelection(contentX, contentY);
if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "select=" + contentX + "," + contentY);
}
invalidate();
}
}
// Trigger the link
if (!mSelectingText && (mTouchMode == TOUCH_INIT_MODE || mTouchMode == TOUCH_DOUBLE_TAP_MODE)) {
mPrivateHandler.sendEmptyMessageDelayed(SWITCH_TO_SHORTPRESS, TAP_TIMEOUT);
mPrivateHandler.sendEmptyMessageDelayed(SWITCH_TO_LONGPRESS, LONG_PRESS_TIMEOUT);
if (inFullScreenMode() || mDeferTouchProcess) {
mPreventDefault = PREVENT_DEFAULT_YES;
} else if (!mBlockWebkitViewMessages && mForwardTouchEvents) {
mPreventDefault = PREVENT_DEFAULT_MAYBE_YES;
} else {
mPreventDefault = PREVENT_DEFAULT_NO;
}
// pass the touch events from UI thread to WebCore thread
if (shouldForwardTouchEvent()) {
TouchEventData ted = new TouchEventData();
ted.mAction = action;
ted.mIds = new int[1];
ted.mIds[0] = ev.getPointerId(0);
ted.mPoints = new Point[1];
ted.mPoints[0] = new Point(contentX, contentY);
ted.mPointsInView = new Point[1];
ted.mPointsInView[0] = new Point(x, y);
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
ted.mNativeLayer = nativeScrollableLayer(contentX, contentY, ted.mNativeLayerRect, null);
ted.mSequence = mTouchEventQueue.nextTouchSequence();
mTouchEventQueue.preQueueTouchEventData(ted);
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
if (mDeferTouchProcess) {
// still needs to set them for compute deltaX/Y
mLastTouchX = x;
mLastTouchY = y;
break;
}
if (!inFullScreenMode()) {
mPrivateHandler.removeMessages(PREVENT_DEFAULT_TIMEOUT);
mPrivateHandler.sendMessageDelayed(mPrivateHandler.obtainMessage(PREVENT_DEFAULT_TIMEOUT, action, 0), TAP_TIMEOUT);
}
}
}
startTouch(x, y, eventTime);
break;
}
case MotionEvent.ACTION_MOVE:
{
boolean firstMove = false;
if (!mConfirmMove && (deltaX * deltaX + deltaY * deltaY) >= mTouchSlopSquare) {
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
mConfirmMove = true;
firstMove = true;
if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) {
mTouchMode = TOUCH_INIT_MODE;
}
if (USE_WEBKIT_RINGS || getSettings().supportTouchOnly()) {
removeTouchHighlight();
}
}
// pass the touch events from UI thread to WebCore thread
if (shouldForwardTouchEvent() && mConfirmMove && (firstMove || eventTime - mLastSentTouchTime > mCurrentTouchInterval)) {
TouchEventData ted = new TouchEventData();
ted.mAction = action;
ted.mIds = new int[1];
ted.mIds[0] = ev.getPointerId(0);
ted.mPoints = new Point[1];
ted.mPoints[0] = new Point(contentX, contentY);
ted.mPointsInView = new Point[1];
ted.mPointsInView[0] = new Point(x, y);
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
ted.mNativeLayer = mScrollingLayer;
ted.mNativeLayerRect.set(mScrollingLayerRect);
ted.mSequence = mTouchEventQueue.nextTouchSequence();
mTouchEventQueue.preQueueTouchEventData(ted);
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
mLastSentTouchTime = eventTime;
if (mDeferTouchProcess) {
break;
}
if (firstMove && !inFullScreenMode()) {
mPrivateHandler.sendMessageDelayed(mPrivateHandler.obtainMessage(PREVENT_DEFAULT_TIMEOUT, action, 0), TAP_TIMEOUT);
}
}
if (mTouchMode == TOUCH_DONE_MODE || mPreventDefault == PREVENT_DEFAULT_YES) {
// default is yes
break;
}
if (mVelocityTracker == null) {
Log.e(LOGTAG, "Got null mVelocityTracker when " + "mPreventDefault = " + mPreventDefault + " mDeferTouchProcess = " + mDeferTouchProcess + " mTouchMode = " + mTouchMode);
} else {
mVelocityTracker.addMovement(ev);
}
if (mSelectingText && mSelectionStarted) {
if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "extend=" + contentX + "," + contentY);
}
ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
mAutoScrollX = x <= mMinAutoScrollX ? -SELECT_SCROLL : x >= mMaxAutoScrollX ? SELECT_SCROLL : 0;
mAutoScrollY = y <= mMinAutoScrollY ? -SELECT_SCROLL : y >= mMaxAutoScrollY ? SELECT_SCROLL : 0;
if ((mAutoScrollX != 0 || mAutoScrollY != 0) && !mSentAutoScrollMessage) {
mSentAutoScrollMessage = true;
mPrivateHandler.sendEmptyMessageDelayed(SCROLL_SELECT_TEXT, SELECT_SCROLL_INTERVAL);
}
if (deltaX != 0 || deltaY != 0) {
nativeExtendSelection(contentX, contentY);
invalidate();
}
break;
}
if (mTouchMode != TOUCH_DRAG_MODE && mTouchMode != TOUCH_DRAG_LAYER_MODE) {
if (!mConfirmMove) {
break;
}
if (mPreventDefault == PREVENT_DEFAULT_MAYBE_YES || mPreventDefault == PREVENT_DEFAULT_NO_FROM_TOUCH_DOWN) {
// track mLastTouchTime as we may need to do fling at
// ACTION_UP
mLastTouchTime = eventTime;
break;
}
// Only lock dragging to one axis if we don't have a scale in progress.
// Scaling implies free-roaming movement. Note this is only ever a question
// if mZoomManager.supportsPanDuringZoom() is true.
final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector();
mAverageAngle = calculateDragAngle(deltaX, deltaY);
if (detector == null || !detector.isInProgress()) {
// if it starts nearly horizontal or vertical, enforce it
if (mAverageAngle < HSLOPE_TO_START_SNAP) {
mSnapScrollMode = SNAP_X;
mSnapPositive = deltaX > 0;
mAverageAngle = ANGLE_HORIZ;
} else if (mAverageAngle > VSLOPE_TO_START_SNAP) {
mSnapScrollMode = SNAP_Y;
mSnapPositive = deltaY > 0;
mAverageAngle = ANGLE_VERT;
}
}
mTouchMode = TOUCH_DRAG_MODE;
mLastTouchX = x;
mLastTouchY = y;
deltaX = 0;
deltaY = 0;
startScrollingLayer(x, y);
startDrag();
}
// do pan
boolean done = false;
boolean keepScrollBarsVisible = false;
if (deltaX == 0 && deltaY == 0) {
keepScrollBarsVisible = done = true;
} else {
mAverageAngle += (calculateDragAngle(deltaX, deltaY) - mAverageAngle) / MMA_WEIGHT_N;
if (mSnapScrollMode != SNAP_NONE) {
if (mSnapScrollMode == SNAP_Y) {
// radical change means getting out of snap mode
if (mAverageAngle < VSLOPE_TO_BREAK_SNAP) {
mSnapScrollMode = SNAP_NONE;
}
}
if (mSnapScrollMode == SNAP_X) {
// radical change means getting out of snap mode
if (mAverageAngle > HSLOPE_TO_BREAK_SNAP) {
mSnapScrollMode = SNAP_NONE;
}
}
} else {
if (mAverageAngle < HSLOPE_TO_START_SNAP) {
mSnapScrollMode = SNAP_X;
mSnapPositive = deltaX > 0;
mAverageAngle = (mAverageAngle + ANGLE_HORIZ) / 2;
} else if (mAverageAngle > VSLOPE_TO_START_SNAP) {
mSnapScrollMode = SNAP_Y;
mSnapPositive = deltaY > 0;
mAverageAngle = (mAverageAngle + ANGLE_VERT) / 2;
}
}
if (mSnapScrollMode != SNAP_NONE) {
if ((mSnapScrollMode & SNAP_X) == SNAP_X) {
deltaY = 0;
} else {
deltaX = 0;
}
}
mLastTouchX = x;
mLastTouchY = y;
if ((deltaX | deltaY) != 0) {
mHeldMotionless = MOTIONLESS_FALSE;
}
mLastTouchTime = eventTime;
}
doDrag(deltaX, deltaY);
// Turn off scrollbars when dragging a layer.
if (keepScrollBarsVisible && mTouchMode != TOUCH_DRAG_LAYER_MODE) {
if (mHeldMotionless != MOTIONLESS_TRUE) {
mHeldMotionless = MOTIONLESS_TRUE;
invalidate();
}
// keep the scrollbar on the screen even there is no scroll
awakenScrollBars(ViewConfiguration.getScrollDefaultDelay(), false);
// view space
return !done;
}
break;
}
case MotionEvent.ACTION_UP:
{
if (!isFocused())
requestFocus();
// pass the touch events from UI thread to WebCore thread
if (shouldForwardTouchEvent()) {
TouchEventData ted = new TouchEventData();
ted.mIds = new int[1];
ted.mIds[0] = ev.getPointerId(0);
ted.mAction = action;
ted.mPoints = new Point[1];
ted.mPoints[0] = new Point(contentX, contentY);
ted.mPointsInView = new Point[1];
ted.mPointsInView[0] = new Point(x, y);
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
ted.mNativeLayer = mScrollingLayer;
ted.mNativeLayerRect.set(mScrollingLayerRect);
ted.mSequence = mTouchEventQueue.nextTouchSequence();
mTouchEventQueue.preQueueTouchEventData(ted);
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
}
mLastTouchUpTime = eventTime;
if (mSentAutoScrollMessage) {
mAutoScrollX = mAutoScrollY = 0;
}
switch(mTouchMode) {
case // double tap
TOUCH_DOUBLE_TAP_MODE:
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
if (inFullScreenMode() || mDeferTouchProcess) {
TouchEventData ted = new TouchEventData();
ted.mIds = new int[1];
ted.mIds[0] = ev.getPointerId(0);
ted.mAction = WebViewCore.ACTION_DOUBLETAP;
ted.mPoints = new Point[1];
ted.mPoints[0] = new Point(contentX, contentY);
ted.mPointsInView = new Point[1];
ted.mPointsInView[0] = new Point(x, y);
ted.mMetaState = ev.getMetaState();
ted.mReprocess = mDeferTouchProcess;
ted.mNativeLayer = nativeScrollableLayer(contentX, contentY, ted.mNativeLayerRect, null);
ted.mSequence = mTouchEventQueue.nextTouchSequence();
mTouchEventQueue.preQueueTouchEventData(ted);
mWebViewCore.sendMessage(EventHub.TOUCH_EVENT, ted);
} else if (mPreventDefault != PREVENT_DEFAULT_YES) {
mZoomManager.handleDoubleTap(mLastTouchX, mLastTouchY);
mTouchMode = TOUCH_DONE_MODE;
}
break;
// tap
case TOUCH_INIT_MODE:
case TOUCH_SHORTPRESS_START_MODE:
case TOUCH_SHORTPRESS_MODE:
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
if (mConfirmMove) {
Log.w(LOGTAG, "Miss a drag as we are waiting for" + " WebCore's response for touch down.");
if (mPreventDefault != PREVENT_DEFAULT_YES && (computeMaxScrollX() > 0 || computeMaxScrollY() > 0)) {
// If the user has performed a very quick touch
// sequence it is possible that we may get here
// before WebCore has had a chance to process the events.
// In this case, any call to preventDefault in the
// JS touch handler will not have been executed yet.
// Hence we will see both the UI (now) and WebCore
// (when context switches) handling the event,
// regardless of whether the web developer actually
// doeses preventDefault in their touch handler. This
// is the nature of our asynchronous touch model.
// we will not rewrite drag code here, but we
// will try fling if it applies.
WebViewCore.reducePriority();
// to get better performance, pause updating the
// picture
WebViewCore.pauseUpdatePicture(mWebViewCore);
// fall through to TOUCH_DRAG_MODE
} else {
// WebKit may consume the touch event and modify
// DOM. drawContentPicture() will be called with
// animateSroll as true for better performance.
// Force redraw in high-quality.
invalidate();
break;
}
} else {
if (mSelectingText) {
// tapping on selection or controls does nothing
if (!nativeHitSelection(contentX, contentY)) {
selectionDone();
}
break;
}
// scalable
if (mTouchMode == TOUCH_INIT_MODE && (canZoomIn() || canZoomOut())) {
mPrivateHandler.sendEmptyMessageDelayed(RELEASE_SINGLE_TAP, ViewConfiguration.getDoubleTapTimeout());
} else {
doShortPress();
}
break;
}
case TOUCH_DRAG_MODE:
case TOUCH_DRAG_LAYER_MODE:
mPrivateHandler.removeMessages(DRAG_HELD_MOTIONLESS);
mPrivateHandler.removeMessages(AWAKEN_SCROLL_BARS);
// up, we don't want to do a fling
if (eventTime - mLastTouchTime <= MIN_FLING_TIME) {
if (mVelocityTracker == null) {
Log.e(LOGTAG, "Got null mVelocityTracker when " + "mPreventDefault = " + mPreventDefault + " mDeferTouchProcess = " + mDeferTouchProcess);
} else {
mVelocityTracker.addMovement(ev);
}
// set to MOTIONLESS_IGNORE so that it won't keep
// removing and sending message in
// drawCoreAndCursorRing()
mHeldMotionless = MOTIONLESS_IGNORE;
doFling();
break;
} else {
if (mScroller.springBack(mScrollX, mScrollY, 0, computeMaxScrollX(), 0, computeMaxScrollY())) {
invalidate();
}
}
// redraw in high-quality, as we're done dragging
mHeldMotionless = MOTIONLESS_TRUE;
invalidate();
// fall through
case TOUCH_DRAG_START_MODE:
// TOUCH_DRAG_START_MODE should not happen for the real
// device as we almost certain will get a MOVE. But this
// is possible on emulator.
mLastVelocity = 0;
WebViewCore.resumePriority();
if (!mSelectingText) {
WebViewCore.resumeUpdatePicture(mWebViewCore);
}
break;
}
stopTouch();
break;
}
case MotionEvent.ACTION_CANCEL:
{
if (mTouchMode == TOUCH_DRAG_MODE) {
mScroller.springBack(mScrollX, mScrollY, 0, computeMaxScrollX(), 0, computeMaxScrollY());
invalidate();
}
cancelWebCoreTouchEvent(contentX, contentY, false);
cancelTouch();
break;
}
}
return true;
}
Aggregations