X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fcontent%2Fpublic%2Fandroid%2Fjava%2Fsrc%2Forg%2Fchromium%2Fcontent%2Fbrowser%2FContentViewCore.java;h=ec9d7562560d3e5ec0ff19c90ef419080ddd05a5;hb=004985e17e624662a4c85c76a7654039dc83f028;hp=39ab380fba4bd1308f1ce6b345546b0589249bb3;hpb=2f108dbacb161091e42a3479f4e171339b7e7623;p=platform%2Fframework%2Fweb%2Fcrosswalk.git diff --git a/src/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/src/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java index 39ab380..ec9d756 100644 --- a/src/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java +++ b/src/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java @@ -64,7 +64,9 @@ import org.chromium.content.browser.input.ImeAdapter; import org.chromium.content.browser.input.ImeAdapter.AdapterInputConnectionFactory; import org.chromium.content.browser.input.InputMethodManagerWrapper; import org.chromium.content.browser.input.InsertionHandleController; +import org.chromium.content.browser.input.SelectPopup; import org.chromium.content.browser.input.SelectPopupDialog; +import org.chromium.content.browser.input.SelectPopupDropdown; import org.chromium.content.browser.input.SelectPopupItem; import org.chromium.content.browser.input.SelectionHandleController; import org.chromium.content.common.ContentSwitches; @@ -209,98 +211,6 @@ public class ContentViewCore public void onSmartClipDataExtracted(String result); } - private VSyncManager.Provider mVSyncProvider; - private VSyncManager.Listener mVSyncListener; - private int mVSyncSubscriberCount; - private boolean mVSyncListenerRegistered; - - // To avoid IPC delay we use input events to directly trigger a vsync signal in the renderer. - // When we do this, we also need to avoid sending the real vsync signal for the current - // frame to avoid double-ticking. This flag is used to inhibit the next vsync notification. - private boolean mDidSignalVSyncUsingInputEvent; - - public VSyncManager.Listener getVSyncListener(VSyncManager.Provider vsyncProvider) { - if (mVSyncProvider != null && mVSyncListenerRegistered) { - mVSyncProvider.unregisterVSyncListener(mVSyncListener); - mVSyncListenerRegistered = false; - } - - mVSyncProvider = vsyncProvider; - mVSyncListener = new VSyncManager.Listener() { - @Override - public void updateVSync(long tickTimeMicros, long intervalMicros) { - if (mNativeContentViewCore != 0) { - nativeUpdateVSyncParameters(mNativeContentViewCore, tickTimeMicros, - intervalMicros); - } - } - - @Override - public void onVSync(long frameTimeMicros) { - animateIfNecessary(frameTimeMicros); - - if (mRequestedVSyncForInput) { - mRequestedVSyncForInput = false; - removeVSyncSubscriber(); - } - if (mNativeContentViewCore != 0) { - nativeOnVSync(mNativeContentViewCore, frameTimeMicros); - } - } - }; - - if (mVSyncSubscriberCount > 0) { - // addVSyncSubscriber() is called before getVSyncListener. - vsyncProvider.registerVSyncListener(mVSyncListener); - mVSyncListenerRegistered = true; - } - - return mVSyncListener; - } - - @CalledByNative - void addVSyncSubscriber() { - if (!isVSyncNotificationEnabled()) { - mDidSignalVSyncUsingInputEvent = false; - } - if (mVSyncProvider != null && !mVSyncListenerRegistered) { - mVSyncProvider.registerVSyncListener(mVSyncListener); - mVSyncListenerRegistered = true; - } - mVSyncSubscriberCount++; - } - - @CalledByNative - void removeVSyncSubscriber() { - if (mVSyncProvider != null && mVSyncSubscriberCount == 1) { - assert mVSyncListenerRegistered; - mVSyncProvider.unregisterVSyncListener(mVSyncListener); - mVSyncListenerRegistered = false; - } - mVSyncSubscriberCount--; - assert mVSyncSubscriberCount >= 0; - } - - @CalledByNative - private void resetVSyncNotification() { - while (isVSyncNotificationEnabled()) removeVSyncSubscriber(); - mVSyncSubscriberCount = 0; - mVSyncListenerRegistered = false; - mNeedAnimate = false; - } - - private boolean isVSyncNotificationEnabled() { - return mVSyncProvider != null && mVSyncListenerRegistered; - } - - @CalledByNative - private void setNeedsAnimate() { - if (!mNeedAnimate) { - mNeedAnimate = true; - addVSyncSubscriber(); - } - } - private final Context mContext; private ViewGroup mContainerView; private InternalAccessDelegate mContainerViewInternals; @@ -314,14 +224,12 @@ public class ContentViewCore // Native pointer to C++ ContentViewCoreImpl object which will be set by nativeInit(). private long mNativeContentViewCore = 0; - private boolean mInForeground = false; - private final ObserverList mGestureStateListeners; private final RewindableIterator mGestureStateListenersIterator; private ZoomControlsDelegate mZoomControlsDelegate; private PopupZoomer mPopupZoomer; - private SelectPopupDialog mSelectPopupDialog; + private SelectPopup mSelectPopup; private Runnable mFakeMouseMoveRunnable = null; @@ -396,16 +304,6 @@ public class ContentViewCore // Whether we received a new frame since consumePendingRendererFrame() was last called. private boolean mPendingRendererFrame = false; - // Whether we should animate at the next vsync tick. - private boolean mNeedAnimate = false; - - // Whether we requested a proactive vsync event in response to touch input. - // This reduces the latency of responding to input by ensuring the renderer - // is sent a BeginFrame for every touch event we receive. Otherwise the - // renderer's SetNeedsBeginFrame message would get serviced at the next - // vsync. - private boolean mRequestedVSyncForInput = false; - // On single tap this will store the x, y coordinates of the touch. private int mSingleTapX; private int mSingleTapY; @@ -427,7 +325,7 @@ public class ContentViewCore // a focused element. // Every time the user, IME, javascript (Blink), autofill etc. modifies the content, the new // state must be reflected to this to keep consistency. - private Editable mEditable; + private final Editable mEditable; /** * PID used to indicate an invalid render process. @@ -436,6 +334,10 @@ public class ContentViewCore // if there is no render process. public static final int INVALID_RENDER_PROCESS_PID = 0; + // Offsets for the events that passes through this ContentViewCore. + private float mCurrentTouchOffsetX; + private float mCurrentTouchOffsetY; + /** * Constructs a new ContentViewCore. Embedders must call initialize() after constructing * a ContentViewCore and before using it. @@ -615,11 +517,6 @@ public class ContentViewCore } @Override - public void onSetFieldValue() { - scrollFocusedEditableNodeIntoView(); - } - - @Override public void onDismissInput() { getContentViewClient().onImeStateChangeRequested(false); } @@ -722,10 +619,20 @@ public class ContentViewCore mContainerView.setContentDescription(contentDescription); mWebContentsObserver = new WebContentsObserverAndroid(this) { @Override - public void didStartLoading(String url) { - hidePopupDialog(); + public void didNavigateMainFrame(String url, String baseUrl, + boolean isNavigationToDifferentPage, boolean isNavigationInPage) { + if (!isNavigationToDifferentPage) return; + hidePopups(); + resetScrollInProgress(); + resetGestureDetection(); + } + + @Override + public void renderProcessGone(boolean wasOomProtected) { + hidePopups(); resetScrollInProgress(); - resetGestureDetectors(); + // No need to reset gesture detection as the detector will have + // been destroyed in the RenderWidgetHostView. } }; } @@ -759,7 +666,6 @@ public class ContentViewCore mContainerView.setClickable(true); mRenderCoordinates.reset(); - onRenderCoordinatesUpdated(); initPopupZoomer(mContext); mImeAdapter = createImeAdapter(mContext); @@ -832,8 +738,6 @@ public class ContentViewCore nativeOnJavaContentViewCoreDestroyed(mNativeContentViewCore); } mWebContents = null; - resetVSyncNotification(); - mVSyncProvider = null; if (mViewAndroid != null) mViewAndroid.destroy(); mNativeContentViewCore = 0; mContentSettings = null; @@ -877,7 +781,8 @@ public class ContentViewCore mContentViewClient = client; } - ContentViewClient getContentViewClient() { + @VisibleForTesting + public ContentViewClient getContentViewClient() { if (mContentViewClient == null) { // We use the Null Object pattern to avoid having to perform a null check in this class. // We create it lazily because most of the time a client will be set almost immediately @@ -916,6 +821,8 @@ public class ContentViewCore params.mUrl, params.mLoadUrlType, params.mTransitionType, + params.getReferrer() != null ? params.getReferrer().getUrl() : null, + params.getReferrer() != null ? params.getReferrer().getPolicy() : 0, params.mUaOverrideOption, params.getExtraHeadersString(), params.mPostData, @@ -928,7 +835,7 @@ public class ContentViewCore * Stops loading the current web contents. */ public void stopLoading() { - if (mNativeContentViewCore != 0) nativeStopLoading(mNativeContentViewCore); + if (mWebContents != null) mWebContents.stop(); } /** @@ -947,8 +854,7 @@ public class ContentViewCore * @return The title of the current page. */ public String getTitle() { - if (mNativeContentViewCore != 0) return nativeGetTitle(mNativeContentViewCore); - return null; + return mWebContents == null ? null : mWebContents.getTitle(); } /** @@ -1170,42 +1076,52 @@ public class ContentViewCore * @see View#onTouchEvent(MotionEvent) */ public boolean onTouchEvent(MotionEvent event) { - cancelRequestToScrollFocusedEditableNodeIntoView(); + TraceEvent.begin("onTouchEvent"); + try { + cancelRequestToScrollFocusedEditableNodeIntoView(); + + final int eventAction = event.getActionMasked(); + + // Only these actions have any effect on gesture detection. Other + // actions have no corresponding WebTouchEvent type and may confuse the + // touch pipline, so we ignore them entirely. + if (eventAction != MotionEvent.ACTION_DOWN + && eventAction != MotionEvent.ACTION_UP + && eventAction != MotionEvent.ACTION_CANCEL + && eventAction != MotionEvent.ACTION_MOVE + && eventAction != MotionEvent.ACTION_POINTER_DOWN + && eventAction != MotionEvent.ACTION_POINTER_UP) { + return false; + } - if (!mRequestedVSyncForInput) { - mRequestedVSyncForInput = true; - addVSyncSubscriber(); - } + if (mNativeContentViewCore == 0) return false; - final int eventAction = event.getActionMasked(); + // A zero offset is quite common, in which case the unnecessary copy should be avoided. + MotionEvent offset = null; + if (mCurrentTouchOffsetX != 0 || mCurrentTouchOffsetY != 0) { + offset = createOffsetMotionEvent(event); + event = offset; + } - // Only these actions have any effect on gesture detection. Other - // actions have no corresponding WebTouchEvent type and may confuse the - // touch pipline, so we ignore them entirely. - if (eventAction != MotionEvent.ACTION_DOWN - && eventAction != MotionEvent.ACTION_UP - && eventAction != MotionEvent.ACTION_CANCEL - && eventAction != MotionEvent.ACTION_MOVE - && eventAction != MotionEvent.ACTION_POINTER_DOWN - && eventAction != MotionEvent.ACTION_POINTER_UP) { - return false; + final int pointerCount = event.getPointerCount(); + final boolean consumed = nativeOnTouchEvent(mNativeContentViewCore, event, + event.getEventTime(), eventAction, + pointerCount, event.getHistorySize(), event.getActionIndex(), + event.getX(), event.getY(), + pointerCount > 1 ? event.getX(1) : 0, + pointerCount > 1 ? event.getY(1) : 0, + event.getPointerId(0), pointerCount > 1 ? event.getPointerId(1) : -1, + event.getTouchMajor(), pointerCount > 1 ? event.getTouchMajor(1) : 0); + + if (offset != null) offset.recycle(); + return consumed; + } finally { + TraceEvent.end("onTouchEvent"); } - - if (mNativeContentViewCore == 0) return false; - final int pointerCount = event.getPointerCount(); - return nativeOnTouchEvent(mNativeContentViewCore, event, - event.getEventTime(), eventAction, - pointerCount, event.getHistorySize(), event.getActionIndex(), - event.getX(), event.getY(), - pointerCount > 1 ? event.getX(1) : 0, - pointerCount > 1 ? event.getY(1) : 0, - event.getPointerId(0), pointerCount > 1 ? event.getPointerId(1) : -1, - event.getTouchMajor(), pointerCount > 1 ? event.getTouchMajor(1) : 0); } public void setIgnoreRemainingTouchEvents() { - if (mNativeContentViewCore == 0) return; - nativeIgnoreRemainingTouchEvents(mNativeContentViewCore); + resetGestureDetection(); } public boolean isScrollInProgress() { @@ -1283,6 +1199,15 @@ public class ContentViewCore @SuppressWarnings("unused") @CalledByNative + private void onTapEventNotConsumed(int x, int y) { + for (mGestureStateListenersIterator.rewind(); + mGestureStateListenersIterator.hasNext();) { + mGestureStateListenersIterator.next().onUnhandledTapEvent(x, y); + } + } + + @SuppressWarnings("unused") + @CalledByNative private void onDoubleTapEventAck() { temporarilyHideTextHandles(); } @@ -1315,6 +1240,15 @@ public class ContentViewCore } /** + * Cancel any fling gestures active. + * @param timeMs Current time (in milliseconds). + */ + public void cancelFling(long timeMs) { + if (mNativeContentViewCore == 0) return; + nativeFlingCancel(mNativeContentViewCore, timeMs); + } + + /** * Add a listener that gets alerted on gesture state changes. * @param listener Listener to add. */ @@ -1402,11 +1336,6 @@ public class ContentViewCore */ public void onShow() { assert mNativeContentViewCore != 0; - if (!mInForeground) { - ChildProcessLauncher.getBindingManager().setInForeground(getCurrentRenderProcessId(), - true); - } - mInForeground = true; nativeOnShow(mNativeContentViewCore); setAccessibilityState(mAccessibilityManager.isEnabled()); } @@ -1424,12 +1353,7 @@ public class ContentViewCore */ public void onHide() { assert mNativeContentViewCore != 0; - if (mInForeground) { - ChildProcessLauncher.getBindingManager().setInForeground(getCurrentRenderProcessId(), - false); - } - mInForeground = false; - hidePopupDialog(); + hidePopups(); setInjectedAccessibility(false); nativeOnHide(mNativeContentViewCore); } @@ -1444,28 +1368,13 @@ public class ContentViewCore return mContentSettings; } - private void onRenderCoordinatesUpdated() { - if (mNativeContentViewCore == 0) return; - - // We disable double tap zoom for pages that have a width=device-width - // or narrower viewport (indicating that this is a mobile-optimized or - // responsive web design, so text will be legible without zooming). - // We also disable it for pages that disallow the user from zooming in - // or out (even if they don't have a device-width or narrower viewport). - nativeSetDoubleTapSupportForPageEnabled(mNativeContentViewCore, - !mRenderCoordinates.hasMobileViewport() && !mRenderCoordinates.hasFixedPageScale()); - } - - private void hidePopupDialog() { - if (mSelectPopupDialog != null) { - mSelectPopupDialog.hide(); - mSelectPopupDialog = null; - } + private void hidePopups() { + hideSelectPopup(); hideHandles(); hideSelectActionBar(); } - void hideSelectActionBar() { + public void hideSelectActionBar() { if (mActionMode != null) { mActionMode.finish(); mActionMode = null; @@ -1476,9 +1385,9 @@ public class ContentViewCore return mActionMode != null; } - private void resetGestureDetectors() { + private void resetGestureDetection() { if (mNativeContentViewCore == 0) return; - nativeResetGestureDetectors(mNativeContentViewCore); + nativeResetGestureDetection(mNativeContentViewCore); } /** @@ -1498,7 +1407,7 @@ public class ContentViewCore @SuppressLint("MissingSuperCall") public void onDetachedFromWindow() { setInjectedAccessibility(false); - hidePopupDialog(); + hidePopups(); mZoomControlsDelegate.dismissZoomPicker(); unregisterAccessibilityContentObserver(); @@ -1554,8 +1463,10 @@ public class ContentViewCore TraceEvent.begin(); if (newConfig.keyboard != Configuration.KEYBOARD_NOKEYS) { - mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore), - ImeAdapter.getTextInputTypeNone()); + if (mNativeContentViewCore != 0) { + mImeAdapter.attach(nativeGetNativeImeAdapter(mNativeContentViewCore), + ImeAdapter.getTextInputTypeNone()); + } mInputMethodManagerWrapper.restartInput(mContainerView); } mContainerViewInternals.super_onConfigurationChanged(newConfig); @@ -1656,10 +1567,7 @@ public class ContentViewCore * @see View#onWindowFocusChanged(boolean) */ public void onWindowFocusChanged(boolean hasWindowFocus) { - if (!hasWindowFocus) { - if (mNativeContentViewCore == 0) return; - nativeOnWindowFocusLost(mNativeContentViewCore); - } + if (!hasWindowFocus) resetGestureDetection(); } public void onFocusChanged(boolean gainFocus) { @@ -1713,24 +1621,28 @@ public class ContentViewCore */ public boolean onHoverEvent(MotionEvent event) { TraceEvent.begin("onHoverEvent"); + MotionEvent offset = createOffsetMotionEvent(event); + try { + if (mBrowserAccessibilityManager != null) { + return mBrowserAccessibilityManager.onHoverEvent(offset); + } - if (mBrowserAccessibilityManager != null) { - return mBrowserAccessibilityManager.onHoverEvent(event); - } + // Work around Android bug where the x, y coordinates of a hover exit + // event are incorrect when touch exploration is on. + if (mTouchExplorationEnabled && offset.getAction() == MotionEvent.ACTION_HOVER_EXIT) { + return true; + } - // Work around Android bug where the x, y coordinates of a hover exit - // event are incorrect when touch exploration is on. - if (mTouchExplorationEnabled && event.getAction() == MotionEvent.ACTION_HOVER_EXIT) { + mContainerView.removeCallbacks(mFakeMouseMoveRunnable); + if (mNativeContentViewCore != 0) { + nativeSendMouseMoveEvent(mNativeContentViewCore, offset.getEventTime(), + offset.getX(), offset.getY()); + } return true; + } finally { + offset.recycle(); + TraceEvent.end("onHoverEvent"); } - - mContainerView.removeCallbacks(mFakeMouseMoveRunnable); - if (mNativeContentViewCore != 0) { - nativeSendMouseMoveEvent(mNativeContentViewCore, event.getEventTime(), - event.getX(), event.getY()); - } - TraceEvent.end("onHoverEvent"); - return true; } /** @@ -1740,6 +1652,8 @@ public class ContentViewCore if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { switch (event.getAction()) { case MotionEvent.ACTION_SCROLL: + if (mNativeContentViewCore == 0) return false; + nativeSendMouseWheelEvent(mNativeContentViewCore, event.getEventTime(), event.getX(), event.getY(), event.getAxisValue(MotionEvent.AXIS_VSCROLL)); @@ -1752,6 +1666,7 @@ public class ContentViewCore @Override public void run() { onHoverEvent(eventFakeMouseMove); + eventFakeMouseMove.recycle(); } }; mContainerView.postDelayed(mFakeMouseMoveRunnable, 250); @@ -1762,6 +1677,23 @@ public class ContentViewCore } /** + * Sets the current amount to offset incoming touch events by. This is used to handle content + * moving and not lining up properly with the android input system. + * @param dx The X offset in pixels to shift touch events. + * @param dy The Y offset in pixels to shift touch events. + */ + public void setCurrentMotionEventOffsets(float dx, float dy) { + mCurrentTouchOffsetX = dx; + mCurrentTouchOffsetY = dy; + } + + private MotionEvent createOffsetMotionEvent(MotionEvent src) { + MotionEvent dst = MotionEvent.obtain(src); + dst.offsetLocation(mCurrentTouchOffsetX, mCurrentTouchOffsetY); + return dst; + } + + /** * @see View#scrollBy(int, int) * Currently the ContentView scrolling happens in the native side. In * the Java view system, it is always pinned at (0, 0). scrollBy() and scrollTo() @@ -1933,7 +1865,7 @@ public class ContentViewCore if (mNativeContentViewCore != 0) { nativeSelectPopupMenuItems(mNativeContentViewCore, indices); } - mSelectPopupDialog = null; + mSelectPopup = null; } /** @@ -2196,7 +2128,7 @@ public class ContentViewCore } public void clearSslPreferences() { - nativeClearSslPreferences(mNativeContentViewCore); + if (mNativeContentViewCore != 0) nativeClearSslPreferences(mNativeContentViewCore); } private boolean isSelectionHandleShowing() { @@ -2333,7 +2265,6 @@ public class ContentViewCore viewportWidth, viewportHeight, pageScaleFactor, minPageScaleFactor, maxPageScaleFactor, contentOffsetYPix); - onRenderCoordinatesUpdated(); if (scrollChanged || contentOffsetChanged) { for (mGestureStateListenersIterator.rewind(); @@ -2363,17 +2294,19 @@ public class ContentViewCore @CalledByNative private void updateImeAdapter(long nativeImeAdapterAndroid, int textInputType, String text, int selectionStart, int selectionEnd, - int compositionStart, int compositionEnd, boolean showImeIfNeeded, boolean requireAck) { + int compositionStart, int compositionEnd, boolean showImeIfNeeded, + boolean isNonImeChange) { TraceEvent.begin(); mSelectionEditable = (textInputType != ImeAdapter.getTextInputTypeNone()); if (mActionMode != null) mActionMode.invalidate(); - mImeAdapter.attachAndShowIfNeeded(nativeImeAdapterAndroid, textInputType, showImeIfNeeded); + mImeAdapter.updateKeyboardVisibility( + nativeImeAdapterAndroid, textInputType, showImeIfNeeded); if (mInputConnection != null) { mInputConnection.updateState(text, selectionStart, selectionEnd, compositionStart, - compositionEnd, requireAck); + compositionEnd, isNonImeChange); } TraceEvent.end(); } @@ -2393,30 +2326,40 @@ public class ContentViewCore */ @SuppressWarnings("unused") @CalledByNative - private void showSelectPopup(String[] items, int[] enabled, boolean multiple, + private void showSelectPopup(Rect bounds, String[] items, int[] enabled, boolean multiple, int[] selectedIndices) { if (mContainerView.getParent() == null || mContainerView.getVisibility() != View.VISIBLE) { selectPopupMenuItems(null); return; } - if (mSelectPopupDialog != null) { - mSelectPopupDialog.hide(); - mSelectPopupDialog = null; - } assert items.length == enabled.length; List popupItems = new ArrayList(); for (int i = 0; i < items.length; i++) { popupItems.add(new SelectPopupItem(items[i], enabled[i])); } - mSelectPopupDialog = SelectPopupDialog.show(this, popupItems, multiple, selectedIndices); + hidePopups(); + if (DeviceUtils.isTablet(mContext) && !multiple) { + mSelectPopup = new SelectPopupDropdown(this, popupItems, bounds, selectedIndices); + } else { + mSelectPopup = new SelectPopupDialog(this, popupItems, multiple, selectedIndices); + } + mSelectPopup.show(); + } + + /** + * Called when the