Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(575)

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

Issue 2407303005: Let embedder provide select action mode (Closed)
Patch Set: Move FloatingPaste into WebActionMode Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 0a5293ba55910c06f9f875e7fbe0115e5489ad2b..e6a621f95e04e0a0be61ea0d946162b1c6c3dfd0 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
@@ -6,16 +6,12 @@ package org.chromium.content.browser;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
-import android.app.Activity;
-import android.app.SearchManager;
import android.app.assist.AssistStructure.ViewNode;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ClipboardManager;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Rect;
@@ -24,8 +20,6 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
import android.os.SystemClock;
-import android.provider.Browser;
-import android.text.TextUtils;
import android.util.Pair;
import android.view.ActionMode;
import android.view.DragEvent;
@@ -37,7 +31,6 @@ import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewStructure;
-import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
@@ -48,29 +41,21 @@ import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import org.chromium.base.CommandLine;
-import org.chromium.base.Log;
import org.chromium.base.ObserverList;
import org.chromium.base.ObserverList.RewindableIterator;
import org.chromium.base.TraceEvent;
import org.chromium.base.VisibleForTesting;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
-import org.chromium.base.metrics.RecordUserAction;
-import org.chromium.content.R;
import org.chromium.content.browser.accessibility.BrowserAccessibilityManager;
import org.chromium.content.browser.accessibility.captioning.CaptioningBridgeFactory;
import org.chromium.content.browser.accessibility.captioning.SystemCaptioningBridge;
import org.chromium.content.browser.accessibility.captioning.TextTrackSettings;
import org.chromium.content.browser.input.AnimationIntervalProvider;
-import org.chromium.content.browser.input.FloatingPastePopupMenu;
import org.chromium.content.browser.input.ImeAdapter;
import org.chromium.content.browser.input.InputMethodManagerWrapper;
import org.chromium.content.browser.input.JoystickScrollProvider;
import org.chromium.content.browser.input.JoystickZoomProvider;
-import org.chromium.content.browser.input.LGEmailActionModeWorkaround;
-import org.chromium.content.browser.input.LegacyPastePopupMenu;
-import org.chromium.content.browser.input.PastePopupMenu;
-import org.chromium.content.browser.input.PastePopupMenu.PastePopupMenuDelegate;
import org.chromium.content.browser.input.SelectPopup;
import org.chromium.content.browser.input.SelectPopupDialog;
import org.chromium.content.browser.input.SelectPopupDropdown;
@@ -345,11 +330,6 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
// Only valid when focused on a text / password field.
private ImeAdapter mImeAdapter;
- // Lazily created paste popup menu, triggered either via long press in an
- // editable region or from tapping the insertion handle.
- private PastePopupMenu mPastePopupMenu;
- private boolean mWasPastePopupShowingOnInsertionDragStart;
-
// Size of the viewport in physical pixels as set from onSizeChanged.
private int mViewportWidthPix;
private int mViewportHeightPix;
@@ -370,22 +350,9 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
private boolean mIsMobileOptimizedHint;
- // Tracks whether a selection is currently active. When applied to selected text, indicates
- // 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;
+ private boolean mDraggingSelection;
private boolean mPreserveSelectionOnNextLossOfFocus;
- private WebActionModeCallback.ActionHandler mActionHandler;
-
- // Selection rectangle in DIP.
- private final Rect mSelectionRect = new Rect();
// Whether native accessibility, i.e. without any script injection, is allowed.
private boolean mNativeAccessibilityAllowed;
@@ -497,6 +464,7 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
mGestureStateListenersIterator = mGestureStateListeners.rewindableIterator();
mWindowAndroidChangedObservers = new ObserverList<WindowAndroidChangedObserver>();
+ mActionMode = WebActionMode.EMPTY;
boliu 2016/10/26 00:20:57 I think this is probably overkill. CVC is not cons
Jinsuk Kim 2016/10/26 06:11:39 Done.
}
/**
@@ -530,6 +498,14 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
return nativeGetJavaWindowAndroid(mNativeContentViewCore);
}
+ /**
+ * @return The WebActionMode that handles select action mode on web contents.
+ */
+ @VisibleForTesting
+ public WebActionMode getActionMode() {
boliu 2016/10/26 00:20:57 can you rename this to getWebActionModeForTesting?
Jinsuk Kim 2016/10/26 06:11:39 Done.
+ return mActionMode;
+ }
+
@Override
public void addWindowAndroidChangedObserver(WindowAndroidChangedObserver observer) {
mWindowAndroidChangedObservers.addObserver(observer);
@@ -584,7 +560,7 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
public void onImeEvent() {
mPopupZoomer.hide(true);
getContentViewClient().onImeEvent();
- if (mFocusedNodeEditable) dismissTextHandles();
+ if (isFocusedNodeEditable()) mWebContents.dismissTextHandles();
}
@Override
@@ -633,6 +609,7 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
* containerView.
* @param webContents A WebContents instance to connect to.
* @param windowAndroid An instance of the WindowAndroid.
+ * @param actionMode WebActionMode instance that handles select action mode.
boliu 2016/10/26 00:20:57 comment out of date now
Jinsuk Kim 2016/10/26 06:11:39 Done.
*/
// Perform important post-construction set up of the ContentViewCore.
// We do not require the containing view in the constructor to allow embedders to create a
@@ -645,8 +622,10 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
// deleting it after destroying the ContentViewCore.
public void initialize(ViewAndroidDelegate viewDelegate,
InternalAccessDelegate internalDispatcher, WebContents webContents,
- WindowAndroid windowAndroid) {
+ WindowAndroid windowAndroid, ActionMode.Callback actionModeCallback) {
mViewAndroidDelegate = viewDelegate;
+ mActionMode = new WebActionMode(mContext, windowAndroid, webContents,
+ viewDelegate.getContainerView(), mRenderCoordinates, actionModeCallback);
setContainerView(viewDelegate.getContainerView());
long windowNativePointer = windowAndroid.getNativePointer();
assert windowNativePointer != 0;
@@ -681,7 +660,7 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
// TODO(yusufo): Rename this call to be general for tab reparenting.
// Clean up cached popups that may have been created with an old activity.
mSelectPopup = null;
- mPastePopupMenu = null;
+ destroyPastePopup();
boliu 2016/10/26 00:20:57 I'll ask yusufo later why this isn't going through
Jinsuk Kim 2016/10/26 06:11:39 Acknowledged.
addDisplayAndroidObserverIfNeeded();
@@ -730,12 +709,14 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
TraceEvent.begin("ContentViewCore.setContainerView");
if (mContainerView != null) {
assert mOverscrollRefreshHandler == null;
- mPastePopupMenu = null;
- hidePopupsAndClearSelection();
+ hideSelectPopupWithCancelMessage();
+ mPopupZoomer.hide(false);
+ destroyPastePopup();
boliu 2016/10/26 00:20:57 this should be handled inside WebActionMode.setCon
Jinsuk Kim 2016/10/26 06:11:39 Done.
}
mContainerView = containerView;
mContainerView.setClickable(true);
+ mActionMode.setContainerView(containerView);
} finally {
TraceEvent.end("ContentViewCore.setContainerView");
}
@@ -857,7 +838,7 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
}
mGestureStateListeners.clear();
hidePopupsAndPreserveSelection();
- mPastePopupMenu = null;
+ destroyPastePopup();
// See warning in javadoc before adding more clean up code here.
}
@@ -989,21 +970,14 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
*/
@VisibleForTesting
public String getSelectedText() {
- return mHasSelection ? mLastSelectedText : "";
- }
-
- /**
- * @return Whether the current selection is editable (false if no text selected).
- */
- public boolean isSelectionEditable() {
- return mHasSelection ? mFocusedNodeEditable : false;
+ return mActionMode.getSelectedText();
}
/**
* @return Whether the current focused node is editable.
*/
public boolean isFocusedNodeEditable() {
- return mFocusedNodeEditable;
+ return mActionMode.isSelectionEditable();
}
/**
@@ -1013,8 +987,6 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
return GamepadList.isGamepadAPIActive();
}
- // End FrameLayout overrides.
-
/**
* @see View#onTouchEvent(MotionEvent)
*/
@@ -1317,37 +1289,40 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
}
private void hidePopupsAndClearSelection() {
- mUnselectAllOnActionModeDismiss = true;
+ setUnselectAllOnDismiss(true);
hidePopups();
}
@CalledByNative
private void hidePopupsAndPreserveSelection() {
- mUnselectAllOnActionModeDismiss = false;
+ setUnselectAllOnDismiss(false);
hidePopups();
}
+ private void setUnselectAllOnDismiss(boolean flag) {
+ mActionMode.setUnselectAllOnDismiss(flag);
+ }
+
private void hidePopups() {
- hideSelectActionMode();
+ destroySelectActionMode();
hidePastePopup();
- hideSelectPopupWithCancelMesage();
+ hideSelectPopupWithCancelMessage();
mPopupZoomer.hide(false);
- if (mUnselectAllOnActionModeDismiss) dismissTextHandles();
}
private void restoreSelectionPopupsIfNecessary() {
- if (mHasSelection && mActionMode == null) showSelectActionMode(true);
+ if (hasSelection()) showSelectActionMode(true);
}
- public void hideSelectActionMode() {
- if (mActionMode != null) {
- mActionMode.finish();
- mActionMode = null;
- }
+ /**
+ * Hide action mode and put into destroyed state.
+ */
+ public void destroySelectActionMode() {
+ mActionMode.finishActionMode();
}
public boolean isSelectActionBarShowing() {
- return mActionMode != null;
+ return mActionMode.isValid();
}
private void resetGestureDetection() {
@@ -1511,7 +1486,7 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
public void onWindowFocusChanged(boolean hasWindowFocus) {
mImeAdapter.onWindowFocusChanged(hasWindowFocus);
if (!hasWindowFocus) resetGestureDetection();
- if (mActionMode != null) mActionMode.onWindowFocusChanged(hasWindowFocus);
+ mActionMode.onWindowFocusChanged(hasWindowFocus);
for (mGestureStateListenersIterator.rewind(); mGestureStateListenersIterator.hasNext();) {
mGestureStateListenersIterator.next().onWindowFocusChanged(hasWindowFocus);
}
@@ -1519,7 +1494,7 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
public void onFocusChanged(boolean gainFocus) {
mImeAdapter.onViewFocusChanged(gainFocus);
- mJoystickScrollProvider.setEnabled(gainFocus && !mFocusedNodeEditable);
+ mJoystickScrollProvider.setEnabled(gainFocus && !isFocusedNodeEditable());
if (gainFocus) {
restoreSelectionPopupsIfNecessary();
@@ -1836,267 +1811,25 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
nativeSendOrientationChangeEvent(mNativeContentViewCore, orientation);
}
- @VisibleForTesting
- public WebActionModeCallback.ActionHandler getSelectActionHandler() {
- return mActionHandler;
+ public WebActionModeDelegate getActionModeDelegate() {
+ return mActionMode;
}
- private void showSelectActionMode(boolean allowFallbackIfFloatingActionModeCreationFails) {
- if (mActionMode != null) {
+ private void showSelectActionMode(boolean allowFallback) {
+ // Just refreshes the view if it is already showing.
+ if (mActionMode.isValid()) {
mActionMode.invalidate();
return;
}
-
- // Start a new action mode with a WebActionModeCallback.
- if (mActionHandler == null) {
- mActionHandler = new WebActionModeCallback.ActionHandler() {
- /**
- * Android Intent size limitations prevent sending over a megabyte of data. Limit
- * query lengths to 100kB because other things may be added to the Intent.
- */
- private static final int MAX_SHARE_QUERY_LENGTH = 100000;
-
- /** Google search doesn't support requests slightly larger than this. */
- private static final int MAX_SEARCH_QUERY_LENGTH = 1000;
-
- // All WebContents actions record a user action internally.
- @Override
- public void selectAll() {
- mWebContents.selectAll();
- // Even though the above statement logged a SelectAll user action, we want to
- // track whether the focus was in an editable field, so log that too.
- if (isFocusedNodeEditable()) {
- RecordUserAction.record("MobileActionMode.SelectAllWasEditable");
- } else {
- RecordUserAction.record("MobileActionMode.SelectAllWasNonEditable");
- }
- }
-
- @Override
- public void cut() {
- mWebContents.cut();
- }
-
- @Override
- public void copy() {
- mWebContents.copy();
- }
-
- @Override
- public void paste() {
- mWebContents.paste();
- }
-
- @Override
- public void share() {
- RecordUserAction.record("MobileActionMode.Share");
- final String query = sanitizeQuery(getSelectedText(), MAX_SHARE_QUERY_LENGTH);
- if (TextUtils.isEmpty(query)) return;
-
- Intent send = new Intent(Intent.ACTION_SEND);
- send.setType("text/plain");
- send.putExtra(Intent.EXTRA_TEXT, query);
- try {
- Intent i = Intent.createChooser(send, getContext().getString(
- R.string.actionbar_share));
- i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- getContext().startActivity(i);
- } catch (android.content.ActivityNotFoundException ex) {
- // If no app handles it, do nothing.
- }
- }
-
- @Override
- public void processText(Intent intent) {
- RecordUserAction.record("MobileActionMode.ProcessTextIntent");
- assert Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
-
- final String query = sanitizeQuery(getSelectedText(), MAX_SEARCH_QUERY_LENGTH);
- if (TextUtils.isEmpty(query)) return;
-
- intent.putExtra(Intent.EXTRA_PROCESS_TEXT, query);
- try {
- if (getContentViewClient().doesPerformProcessText()) {
- getContentViewClient().startProcessTextIntent(intent);
- } else {
- getWindowAndroid().showIntent(
- intent, new WindowAndroid.IntentCallback() {
- @Override
- public void onIntentCompleted(WindowAndroid window,
- int resultCode, ContentResolver contentResolver,
- Intent data) {
- onReceivedProcessTextResult(resultCode, data);
- }
- }, null);
- }
- } catch (android.content.ActivityNotFoundException ex) {
- // If no app handles it, do nothing.
- }
- }
-
- @Override
- public void search() {
- RecordUserAction.record("MobileActionMode.WebSearch");
- final String query = sanitizeQuery(getSelectedText(), MAX_SEARCH_QUERY_LENGTH);
- if (TextUtils.isEmpty(query)) return;
-
- // See if ContentViewClient wants to override.
- if (getContentViewClient().doesPerformWebSearch()) {
- getContentViewClient().performWebSearch(query);
- return;
- }
-
- Intent i = new Intent(Intent.ACTION_WEB_SEARCH);
- i.putExtra(SearchManager.EXTRA_NEW_SEARCH, true);
- i.putExtra(SearchManager.QUERY, query);
- i.putExtra(Browser.EXTRA_APPLICATION_ID, getContext().getPackageName());
- i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- try {
- getContext().startActivity(i);
- } catch (android.content.ActivityNotFoundException ex) {
- // If no app handles it, do nothing.
- }
- }
-
- @Override
- public boolean isSelectionPassword() {
- return mFocusedNodeIsPassword;
- }
-
- @Override
- public boolean isSelectionEditable() {
- return mFocusedNodeEditable;
- }
-
- @Override
- public boolean isInsertion() {
- return mHasInsertion;
- }
-
- @Override
- public void onDestroyActionMode() {
- mActionMode = null;
- if (mUnselectAllOnActionModeDismiss) {
- dismissTextHandles();
- clearSelection();
- }
- if (!supportsFloatingActionMode()) {
- getContentViewClient().onContextualActionBarHidden();
- }
- }
-
- @Override
- public void onGetContentRect(Rect outRectPix) {
- final float deviceScale = mRenderCoordinates.getDeviceScaleFactor();
- outRectPix.set((int) (mSelectionRect.left * deviceScale),
- (int) (mSelectionRect.top * deviceScale),
- (int) (mSelectionRect.right * deviceScale),
- (int) (mSelectionRect.bottom * deviceScale));
-
- // The selection coordinates are relative to the content viewport, but we need
- // coordinates relative to the containing View.
- outRectPix.offset(0, (int) mRenderCoordinates.getContentOffsetYPix());
- }
-
- @Override
- public boolean isIncognito() {
- return mWebContents.isIncognito();
- }
-
- @Override
- public boolean isSelectActionModeAllowed(int actionModeItem) {
- boolean isAllowedByClient =
- getContentViewClient().isSelectActionModeAllowed(actionModeItem);
- if (actionModeItem == WebActionModeCallback.MENU_ITEM_SHARE) {
- return isAllowedByClient && isShareAvailable();
- }
-
- if (actionModeItem == WebActionModeCallback.MENU_ITEM_WEB_SEARCH) {
- return isAllowedByClient && isWebSearchAvailable();
- }
-
- return isAllowedByClient;
- }
-
- private boolean isShareAvailable() {
- Intent intent = new Intent(Intent.ACTION_SEND);
- intent.setType("text/plain");
- return getContext().getPackageManager().queryIntentActivities(intent,
- PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
- }
-
- private boolean isWebSearchAvailable() {
- if (getContentViewClient().doesPerformWebSearch()) return true;
- Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
- intent.putExtra(SearchManager.EXTRA_NEW_SEARCH, true);
- return getContext().getPackageManager().queryIntentActivities(intent,
- PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
- }
-
- private String sanitizeQuery(String query, int maxLength) {
- if (TextUtils.isEmpty(query) || query.length() < maxLength) return query;
- Log.w(TAG, "Truncating oversized query (" + query.length() + ").");
- return query.substring(0, maxLength) + "…";
- }
- };
- }
- mActionMode = null;
- // On ICS, startActionMode throws an NPE when getParent() is null.
- if (mContainerView.getParent() != null) {
- assert mWebContents != null;
- ActionMode actionMode = startActionMode(allowFallbackIfFloatingActionModeCreationFails);
- if (actionMode != null) {
- // This is to work around an LGE email issue. See crbug.com/651706 for more details.
- LGEmailActionModeWorkaround.runIfNecessary(mContext, actionMode);
- mActionMode = new WebActionMode(actionMode, mContainerView);
- }
- }
- mUnselectAllOnActionModeDismiss = true;
- if (mActionMode == null) {
+ mActionMode.showActionMode(allowFallback);
+ if (!mActionMode.isValid()) {
// There is no ActionMode, so remove the selection.
clearSelection();
- } else {
- // TODO(jdduke): Refactor ContentViewClient.onContextualActionBarShown to be aware
- // of non-action-bar (i.e., floating) ActionMode instances, crbug.com/524666.
- if (!supportsFloatingActionMode()) {
- getContentViewClient().onContextualActionBarShown();
- }
}
}
- private boolean supportsFloatingActionMode() {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false;
- return !mFloatingActionModeCreationFailed;
- }
-
- private ActionMode startActionMode(boolean allowFallbackIfFloatingActionModeCreationFails) {
- WebActionModeCallback callback =
- new WebActionModeCallback(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;
+ if (!mActionMode.isValid()) return;
boliu 2016/10/26 00:20:57 move this check into WebActionMode
Jinsuk Kim 2016/10/26 06:11:39 Can be removed here safely as canHide() in WAM.hid
// 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.
@@ -2108,7 +1841,7 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
* end if applicable.
*/
public void clearSelection() {
- if (mFocusedNodeEditable) {
+ if (isFocusedNodeEditable()) {
mImeAdapter.moveCursorToSelectionEnd();
} else {
// This method can be called during shutdown, guard against null accordingly.
@@ -2128,7 +1861,7 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
*/
@VisibleForTesting
public boolean hasSelection() {
- return mHasSelection;
+ return mActionMode.hasSelection();
}
/**
@@ -2136,36 +1869,22 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
*/
@VisibleForTesting
public boolean hasInsertion() {
- return mHasInsertion;
+ return mActionMode.isInsertion();
}
// All coordinates are in DIP.
@CalledByNative
private void onSelectionEvent(
int eventType, int xAnchor, int yAnchor, int left, int top, int right, int bottom) {
- // Ensure the provided selection coordinates form a non-empty rect, as required by
- // the selection action mode.
- if (left == right) ++right;
- if (top == bottom) ++bottom;
+ mActionMode.onSelectionEvent(eventType, xAnchor, yAnchor, left, top, right, bottom,
+ isScrollInProgress());
switch (eventType) {
case SelectionEventType.SELECTION_HANDLES_SHOWN:
- mSelectionRect.set(left, top, right, bottom);
- mHasSelection = true;
- mUnselectAllOnActionModeDismiss = true;
showSelectActionMode(true);
break;
- case SelectionEventType.SELECTION_HANDLES_MOVED:
- mSelectionRect.set(left, top, right, bottom);
- invalidateActionModeContentRect();
- break;
-
case SelectionEventType.SELECTION_HANDLES_CLEARED:
- mHasSelection = false;
mDraggingSelection = false;
- mUnselectAllOnActionModeDismiss = false;
- hideSelectActionMode();
- mSelectionRect.setEmpty();
break;
case SelectionEventType.SELECTION_HANDLE_DRAG_STARTED:
@@ -2177,54 +1896,10 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
mDraggingSelection = false;
updateActionModeVisibility();
break;
-
- case SelectionEventType.INSERTION_HANDLE_SHOWN:
- mSelectionRect.set(left, top, right, bottom);
- mHasInsertion = true;
- break;
-
- case SelectionEventType.INSERTION_HANDLE_MOVED:
- mSelectionRect.set(left, top, right, bottom);
- if (!isScrollInProgress() && isPastePopupShowing()) {
- showPastePopup(xAnchor, yAnchor);
- } else {
- hidePastePopup();
- }
- break;
-
- case SelectionEventType.INSERTION_HANDLE_TAPPED:
- if (mWasPastePopupShowingOnInsertionDragStart) {
- hidePastePopup();
- } else {
- showPastePopup(xAnchor, yAnchor);
- }
- mWasPastePopupShowingOnInsertionDragStart = false;
- break;
-
- case SelectionEventType.INSERTION_HANDLE_CLEARED:
- hidePastePopup();
- mHasInsertion = false;
- mSelectionRect.setEmpty();
- break;
-
- case SelectionEventType.INSERTION_HANDLE_DRAG_STARTED:
- mWasPastePopupShowingOnInsertionDragStart = isPastePopupShowing();
- hidePastePopup();
- break;
-
- case SelectionEventType.INSERTION_HANDLE_DRAG_STOPPED:
- if (mWasPastePopupShowingOnInsertionDragStart) {
- showPastePopup(xAnchor, yAnchor);
- }
- mWasPastePopupShowingOnInsertionDragStart = false;
- break;
- case SelectionEventType.SELECTION_ESTABLISHED:
- case SelectionEventType.SELECTION_DISSOLVED:
- break;
-
default:
- assert false : "Invalid selection event type.";
+ break;
}
+
if (mContextualSearchClient != null) {
final float deviceScale = mRenderCoordinates.getDeviceScaleFactor();
int xAnchorPix = (int) (xAnchor * deviceScale);
@@ -2233,10 +1908,6 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
}
}
- private void dismissTextHandles() {
- if (mNativeContentViewCore != 0) nativeDismissTextHandles(mNativeContentViewCore);
- }
-
private void setTextHandlesTemporarilyHidden(boolean hide) {
if (mNativeContentViewCore == 0) return;
nativeSetTextHandlesTemporarilyHidden(mNativeContentViewCore, hide);
@@ -2353,18 +2024,11 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
mImeAdapter.updateState(text, selectionStart, selectionEnd, compositionStart,
compositionEnd, isNonImeChange, inBatchEditMode);
- if (mActionMode != null) {
- final boolean actionModeConfigurationChanged =
- focusedNodeEditable != mFocusedNodeEditable
- || focusedNodeIsPassword != mFocusedNodeIsPassword;
- if (actionModeConfigurationChanged) mActionMode.invalidate();
- }
-
- mFocusedNodeIsPassword = focusedNodeIsPassword;
- if (focusedNodeEditable != mFocusedNodeEditable) {
- mFocusedNodeEditable = focusedNodeEditable;
- mJoystickScrollProvider.setEnabled(!mFocusedNodeEditable);
- getContentViewClient().onFocusedNodeEditabilityChanged(mFocusedNodeEditable);
+ boolean editableToggled = (focusedNodeEditable != isFocusedNodeEditable());
+ mActionMode.updateSelectionState(focusedNodeEditable, focusedNodeIsPassword);
+ if (editableToggled) {
+ mJoystickScrollProvider.setEnabled(!focusedNodeEditable);
+ getContentViewClient().onFocusedNodeEditabilityChanged(focusedNodeEditable);
}
} finally {
TraceEvent.end("ContentViewCore.updateImeAdapter");
@@ -2438,7 +2102,7 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
* Called when the <select> popup needs to be hidden. This calls
* nativeSelectPopupMenuItems() with null indices.
*/
- private void hideSelectPopupWithCancelMesage() {
+ private void hideSelectPopupWithCancelMessage() {
if (mSelectPopup != null) mSelectPopup.hide(true);
}
@@ -2500,7 +2164,7 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
@SuppressWarnings("unused")
@CalledByNative
private void onSelectionChanged(String text) {
- mLastSelectedText = text;
+ mActionMode.setSelectedText(text);
if (mContextualSearchClient != null) {
mContextualSearchClient.onSelectionChanged(text);
}
@@ -2514,56 +2178,20 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
@VisibleForTesting
public boolean isPastePopupShowing() {
boliu 2016/10/26 00:20:57 can you double check all these VisibleForTesting m
Jinsuk Kim 2016/10/26 06:11:39 Yes it can. Done.
- if (mPastePopupMenu != null) return mPastePopupMenu.isShowing();
- return false;
+ return mActionMode.isPastePopupShowing();
}
- // Coordinates are in DIP.
@CalledByNative
private void showPastePopup(int x, int y) {
- if (mContainerView.getParent() == null || mContainerView.getVisibility() != View.VISIBLE) {
- return;
- }
-
- if (!mHasInsertion || !canPaste()) return;
boliu 2016/10/26 00:20:57 this line changed on trunk, probably should rebase
Jinsuk Kim 2016/10/26 06:11:39 Rebased.
-
- PastePopupMenu pastePopupMenu = getPastePopup();
- if (pastePopupMenu == null) return;
-
- final float deviceScale = mRenderCoordinates.getDeviceScaleFactor();
- final int xPix = (int) (x * deviceScale);
- final int yPix = (int) (y * deviceScale);
- final float topControlsShownPix = mRenderCoordinates.getContentOffsetYPix();
- try {
- pastePopupMenu.show(xPix, (int) (yPix + topControlsShownPix));
- } catch (WindowManager.BadTokenException e) {
- }
+ mActionMode.showPastePopup(x, y);
}
private void hidePastePopup() {
- if (mPastePopupMenu != null) mPastePopupMenu.hide();
+ mActionMode.hidePastePopup();
}
- private PastePopupMenu getPastePopup() {
- if (mPastePopupMenu == null) {
- PastePopupMenuDelegate delegate = new PastePopupMenuDelegate() {
- @Override
- public void paste() {
- mWebContents.paste();
- dismissTextHandles();
- }
- };
- Context windowContext = getWindowAndroid().getContext().get();
- if (windowContext == null) return null;
- if (supportsFloatingActionMode()) {
- mPastePopupMenu = new FloatingPastePopupMenu(
- windowContext, getContainerView(), delegate);
- } else {
- mPastePopupMenu = new LegacyPastePopupMenu(
- windowContext, getContainerView(), delegate);
- }
- }
- return mPastePopupMenu;
+ private void destroyPastePopup() {
+ mActionMode.destroyPastePopup();
}
private boolean canPaste() {
@@ -3021,17 +2649,7 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
* @param data the reply that contains the processed text.
*/
public void onReceivedProcessTextResult(int resultCode, Intent data) {
- if (mWebContents == null || !isSelectionEditable() || resultCode != Activity.RESULT_OK
- || data == null) {
- return;
- }
-
- CharSequence result = data.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT);
- if (result != null) {
- // TODO(hush): Use a variant of replace that re-selects the replaced text.
- // crbug.com/546710
- mWebContents.replace(result.toString());
- }
+ mActionMode.onReceivedProcessTextResult(resultCode, data);
}
/**
@@ -3239,7 +2857,7 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
// ActionMode#invalidate() won't be able to re-layout the floating
// action mode menu items according to the new rotation. So Chrome
// has to re-create the action mode.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mActionMode != null) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mActionMode.isValid()) {
hidePopupsAndPreserveSelection();
showSelectActionMode(true);
}
@@ -3385,7 +3003,6 @@ public class ContentViewCore implements AccessibilityStateChangeListener, Displa
private native void nativePinchBy(long nativeContentViewCoreImpl, long timeMs,
float anchorX, float anchorY, float deltaScale);
- private native void nativeDismissTextHandles(long nativeContentViewCoreImpl);
private native void nativeSetTextHandlesTemporarilyHidden(
long nativeContentViewCoreImpl, boolean hidden);

Powered by Google App Engine
This is Rietveld 408576698