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 |