| Index: content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
|
| diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
|
| index 9920c9d9da33889d487627919b5275260cf1aab6..63b0de8c3a9a2c8f29ea0c9232c736f23769e200 100644
|
| --- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
|
| +++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
|
| @@ -29,6 +29,7 @@ import android.text.Selection;
|
| import android.text.TextUtils;
|
| import android.util.Pair;
|
| import android.util.TypedValue;
|
| +import android.view.ActionMode;
|
| import android.view.HapticFeedbackConstants;
|
| import android.view.InputDevice;
|
| import android.view.KeyEvent;
|
| @@ -519,8 +520,10 @@ public class ContentViewCore implements
|
| // whether the last selected text is still highlighted.
|
| private boolean mHasSelection;
|
| private boolean mHasInsertion;
|
| + private boolean mDraggingSelection;
|
| private String mLastSelectedText;
|
| private boolean mFocusedNodeEditable;
|
| + private boolean mFocusedNodeIsPassword;
|
| private WebActionMode mActionMode;
|
| private boolean mFloatingActionModeCreationFailed;
|
| private boolean mUnselectAllOnActionModeDismiss;
|
| @@ -1273,6 +1276,7 @@ public class ContentViewCore implements
|
| mGestureStateListenersIterator.next().onFlingStartGesture(
|
| vx, vy, computeVerticalScrollOffset(), computeVerticalScrollExtent());
|
| }
|
| + updateActionModeVisibility();
|
| }
|
|
|
| @SuppressWarnings("unused")
|
| @@ -1294,6 +1298,7 @@ public class ContentViewCore implements
|
| hidePastePopup();
|
| mZoomControlsDelegate.invokeZoomPicker();
|
| updateGestureStateListener(GestureEventType.SCROLL_START);
|
| + updateActionModeVisibility();
|
| }
|
|
|
| @SuppressWarnings("unused")
|
| @@ -1312,6 +1317,7 @@ public class ContentViewCore implements
|
| if (!mTouchScrollInProgress) return;
|
| mTouchScrollInProgress = false;
|
| updateGestureStateListener(GestureEventType.SCROLL_END);
|
| + updateActionModeVisibility();
|
| }
|
|
|
| @SuppressWarnings("unused")
|
| @@ -1678,6 +1684,7 @@ public class ContentViewCore implements
|
| */
|
| public void onWindowFocusChanged(boolean hasWindowFocus) {
|
| if (!hasWindowFocus) resetGestureDetection();
|
| + if (mActionMode != null) mActionMode.onWindowFocusChanged(hasWindowFocus);
|
| }
|
|
|
| public void onFocusChanged(boolean gainFocus) {
|
| @@ -2095,7 +2102,7 @@ public class ContentViewCore implements
|
|
|
| @Override
|
| public boolean isSelectionPassword() {
|
| - return mImeAdapter.isSelectionPassword();
|
| + return mFocusedNodeIsPassword;
|
| }
|
|
|
| @Override
|
| @@ -2120,7 +2127,10 @@ public class ContentViewCore implements
|
|
|
| @Override
|
| public void onGetContentRect(Rect outRect) {
|
| + // The selection coordinates are relative to the content viewport, but we need
|
| + // coordinates relative to the containing View.
|
| outRect.set(mSelectionRect);
|
| + outRect.offset(0, (int) mRenderCoordinates.getContentOffsetYPix());
|
| }
|
|
|
| @Override
|
| @@ -2150,15 +2160,8 @@ public class ContentViewCore implements
|
| // On ICS, startActionMode throws an NPE when getParent() is null.
|
| if (mContainerView.getParent() != null) {
|
| assert mWebContents != null;
|
| - boolean tryCreateFloatingActionMode = supportsFloatingActionMode();
|
| - mActionMode = getContentViewClient().startActionMode(
|
| - mContainerView, mActionHandler, tryCreateFloatingActionMode);
|
| - if (tryCreateFloatingActionMode && mActionMode == null) {
|
| - mFloatingActionModeCreationFailed = true;
|
| - if (!allowFallbackIfFloatingActionModeCreationFails) return;
|
| - mActionMode = getContentViewClient().startActionMode(
|
| - mContainerView, mActionHandler, false);
|
| - }
|
| + ActionMode actionMode = startActionMode(allowFallbackIfFloatingActionModeCreationFails);
|
| + if (actionMode != null) mActionMode = new WebActionMode(actionMode, mContainerView);
|
| }
|
| mUnselectAllOnActionModeDismiss = true;
|
| if (mActionMode == null) {
|
| @@ -2170,14 +2173,44 @@ public class ContentViewCore implements
|
| }
|
|
|
| private boolean supportsFloatingActionMode() {
|
| - return !mFloatingActionModeCreationFailed
|
| - && getContentViewClient().supportsFloatingActionMode();
|
| + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false;
|
| + return !mFloatingActionModeCreationFailed;
|
| + }
|
| +
|
| + private ActionMode startActionMode(boolean allowFallbackIfFloatingActionModeCreationFails) {
|
| + WebActionModeCallback callback = getContentViewClient().getWebActionModeCallback(
|
| + mContainerView.getContext(), mActionHandler);
|
| + if (supportsFloatingActionMode()) {
|
| + ActionMode actionMode = startFloatingActionMode(callback);
|
| + if (actionMode != null) return actionMode;
|
| + mFloatingActionModeCreationFailed = true;
|
| + if (!allowFallbackIfFloatingActionModeCreationFails) return null;
|
| + }
|
| + return startDefaultActionMode(callback);
|
| + }
|
| +
|
| + private ActionMode startDefaultActionMode(WebActionModeCallback callback) {
|
| + return mContainerView.startActionMode(callback);
|
| + }
|
| +
|
| + @TargetApi(Build.VERSION_CODES.M)
|
| + private ActionMode startFloatingActionMode(WebActionModeCallback callback) {
|
| + ActionMode.Callback2 callback2 = new FloatingWebActionModeCallback(callback);
|
| + return mContainerView.startActionMode(callback2, ActionMode.TYPE_FLOATING);
|
| }
|
|
|
| private void invalidateActionModeContentRect() {
|
| if (mActionMode != null) mActionMode.invalidateContentRect();
|
| }
|
|
|
| + private void updateActionModeVisibility() {
|
| + if (mActionMode == null) return;
|
| + // The active fling count isn't reliable with WebView, so only use the
|
| + // active touch scroll signal for hiding. The fling animation movement
|
| + // will naturally hide the ActionMode by invalidating its content rect.
|
| + mActionMode.hide(mDraggingSelection || mTouchScrollInProgress);
|
| + }
|
| +
|
| /**
|
| * Clears the current text selection.
|
| */
|
| @@ -2234,15 +2267,20 @@ public class ContentViewCore implements
|
|
|
| case SelectionEventType.SELECTION_HANDLES_CLEARED:
|
| mHasSelection = false;
|
| + mDraggingSelection = false;
|
| mUnselectAllOnActionModeDismiss = false;
|
| hideSelectActionMode();
|
| mSelectionRect.setEmpty();
|
| break;
|
|
|
| case SelectionEventType.SELECTION_HANDLE_DRAG_STARTED:
|
| + mDraggingSelection = true;
|
| + updateActionModeVisibility();
|
| break;
|
|
|
| case SelectionEventType.SELECTION_HANDLE_DRAG_STOPPED:
|
| + mDraggingSelection = false;
|
| + updateActionModeVisibility();
|
| break;
|
|
|
| case SelectionEventType.INSERTION_HANDLE_SHOWN:
|
| @@ -2400,6 +2438,7 @@ public class ContentViewCore implements
|
| try {
|
| TraceEvent.begin("ContentViewCore.updateImeAdapter");
|
| boolean focusedNodeEditable = (textInputType != TextInputType.NONE);
|
| + boolean focusedNodeIsPassword = (textInputType == TextInputType.PASSWORD);
|
| if (!focusedNodeEditable) hidePastePopup();
|
|
|
| mImeAdapter.updateKeyboardVisibility(
|
| @@ -2410,8 +2449,14 @@ public class ContentViewCore implements
|
| compositionEnd, isNonImeChange);
|
| }
|
|
|
| - if (mActionMode != null) mActionMode.invalidate();
|
| + if (mActionMode != null) {
|
| + final boolean actionModeConfigurationChanged =
|
| + focusedNodeEditable != mFocusedNodeEditable
|
| + || focusedNodeIsPassword != mFocusedNodeIsPassword;
|
| + if (actionModeConfigurationChanged) mActionMode.invalidate();
|
| + }
|
|
|
| + mFocusedNodeIsPassword = focusedNodeIsPassword;
|
| if (focusedNodeEditable != mFocusedNodeEditable) {
|
| mFocusedNodeEditable = focusedNodeEditable;
|
| mJoystickScrollProvider.setEnabled(!mFocusedNodeEditable);
|
| @@ -2580,9 +2625,11 @@ public class ContentViewCore implements
|
| }
|
| }
|
|
|
| - private boolean isPastePopupShowing() {
|
| - if (supportsFloatingActionMode()) return mActionMode != null;
|
| - return mPastePopupMenu != null && mPastePopupMenu.isShowing();
|
| + @VisibleForTesting
|
| + public boolean isPastePopupShowing() {
|
| + if (mPastePopupMenu != null) return mPastePopupMenu.isShowing();
|
| + if (mHasInsertion && mActionMode != null) return true;
|
| + return false;
|
| }
|
|
|
| private boolean showPastePopup(int x, int y) {
|
| @@ -2606,6 +2653,8 @@ public class ContentViewCore implements
|
| }
|
|
|
| private void hidePastePopup() {
|
| + // TODO(jdduke): Create a generic interface for the legacy PastePopupMenu and the
|
| + // new ActionMode-based paste popup menu.
|
| if (mPastePopupMenu != null) {
|
| assert !supportsFloatingActionMode();
|
| mPastePopupMenu.hide();
|
| @@ -2632,11 +2681,6 @@ public class ContentViewCore implements
|
| return mPastePopupMenu;
|
| }
|
|
|
| - @VisibleForTesting
|
| - public PastePopupMenu getPastePopupForTest() {
|
| - return getPastePopup();
|
| - }
|
| -
|
| private boolean canPaste() {
|
| if (!mFocusedNodeEditable) return false;
|
| return ((ClipboardManager) mContext.getSystemService(
|
| @@ -3156,6 +3200,7 @@ public class ContentViewCore implements
|
|
|
| if (touchScrollInProgress) updateGestureStateListener(GestureEventType.SCROLL_END);
|
| if (potentiallyActiveFlingCount > 0) updateGestureStateListener(GestureEventType.FLING_END);
|
| + updateActionModeVisibility();
|
| }
|
|
|
| private float getWheelScrollFactorInPixels() {
|
| @@ -3192,6 +3237,7 @@ public class ContentViewCore implements
|
| if (mPotentiallyActiveFlingCount <= 0) return;
|
| mPotentiallyActiveFlingCount--;
|
| updateGestureStateListener(GestureEventType.FLING_END);
|
| + updateActionModeVisibility();
|
| }
|
|
|
| @Override
|
|
|