Chromium Code Reviews

Unified Diff: content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java

Issue 1242613002: [Android] Supporting floating select ActionModes for web content (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
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

Powered by Google App Engine