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

Unified Diff: content/public/android/java/src/org/chromium/content/browser/WebActionMode.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. 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/WebActionMode.java
diff --git a/content/public/android/java/src/org/chromium/content/browser/WebActionMode.java b/content/public/android/java/src/org/chromium/content/browser/WebActionMode.java
index befbb81b1f5279794a6f65c0b750c90474912206..24168b1cc31866cf8818a98ebbfe1e7fe6f972c9 100644
--- a/content/public/android/java/src/org/chromium/content/browser/WebActionMode.java
+++ b/content/public/android/java/src/org/chromium/content/browser/WebActionMode.java
@@ -4,7 +4,11 @@
package org.chromium.content.browser;
+import android.annotation.TargetApi;
+import android.os.Build;
import android.view.ActionMode;
+import android.view.View;
+import android.view.ViewConfiguration;
import org.chromium.base.Log;
@@ -12,18 +16,57 @@ import org.chromium.base.Log;
* An ActionMode for in-page web content selection. This class wraps an ActionMode created
* by the associated View, providing modified interaction with that ActionMode.
*/
+@TargetApi(Build.VERSION_CODES.M)
public class WebActionMode {
- private static final String TAG = "cr.SelectActionMode";
+ private static final String TAG = "cr.WebActionMode";
+
+ // Default delay for reshowing the {@link ActionMode} after it has been
+ // hidden. This avoids flickering issues if there are trailing rect
+ // invalidations after the ActionMode is shown. For example, after the user
+ // stops dragging a selection handle, in turn showing the ActionMode, the
+ // selection change response will be asynchronous. 300ms should accomodate
+ // most such trailing, async delays.
+ private static final int SHOW_DELAY_MS = 300;
protected final ActionMode mActionMode;
+ private final View mView;
+ private boolean mHidden;
+ private boolean mPendingInvalidateContentRect;
+
+ // Self-repeating task that repeatedly hides the ActionMode. This is
+ // required because ActionMode only exposes a temporary hide routine.
+ private final Runnable mRepeatingHideRunnable;
/**
* Constructs a SelectActionMode instance wrapping a concrete ActionMode.
* @param actionMode the wrapped ActionMode.
+ * @param view the associated View.
*/
- public WebActionMode(ActionMode actionMode) {
+ public WebActionMode(ActionMode actionMode, View view) {
assert actionMode != null;
+ assert view != null;
mActionMode = actionMode;
+ mView = view;
+ mRepeatingHideRunnable = new Runnable() {
+ @Override
+ public void run() {
+ assert mHidden;
+ final long hideDuration = getDefaultHideDuration();
+ // Ensure the next hide call occurs before the ActionMode reappears.
+ mView.postDelayed(mRepeatingHideRunnable, hideDuration - 1);
+ hideTemporarily(hideDuration);
+ }
+ };
+ }
+
+ /**
+ * Constructs a SelectActionMode instance wrapping a concrete ActionMode.
+ * TODO(jdduke): Remove when downstream references removed.
+ * @param actionMode the wrapped ActionMode.
+ */
+ @Deprecated
+ public WebActionMode(ActionMode actionMode) {
+ this(actionMode, null);
}
/**
@@ -35,8 +78,17 @@ public class WebActionMode {
/**
* @see ActionMode#invalidate()
+ * Note that invalidation will also reset visibility state. The caller
+ * should account for this when making subsequent visibility updates.
*/
public void invalidate() {
+ if (mHidden) {
+ assert canHide();
+ mHidden = false;
+ mView.removeCallbacks(mRepeatingHideRunnable);
+ mPendingInvalidateContentRect = false;
+ }
+
// Try/catch necessary for framework bug, crbug.com/446717.
try {
mActionMode.invalidate();
@@ -48,5 +100,69 @@ public class WebActionMode {
/**
* @see ActionMode#invalidateContentRect()
*/
- public void invalidateContentRect() {}
+ public void invalidateContentRect() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (mHidden) {
+ mPendingInvalidateContentRect = true;
+ } else {
+ mPendingInvalidateContentRect = false;
+ mActionMode.invalidateContentRect();
+ }
+ }
+ }
+
+ /**
+ * @see ActionMode#onWindowFocusChanged()
+ */
+ public void onWindowFocusChanged(boolean hasWindowFocus) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ mActionMode.onWindowFocusChanged(hasWindowFocus);
+ }
+ }
+
+ /**
+ * Hide or reveal the ActionMode. Note that this only has visible
+ * side-effects if the underlying ActionMode supports hiding.
+ * @param hide whether to hide or show the ActionMode.
+ */
+ public void hide(boolean hide) {
+ if (!canHide()) return;
+ if (mHidden == hide) return;
+ mHidden = hide;
+ if (mHidden) {
+ mRepeatingHideRunnable.run();
+ } else {
+ mHidden = false;
+ mView.removeCallbacks(mRepeatingHideRunnable);
+ hideTemporarily(SHOW_DELAY_MS);
+ if (mPendingInvalidateContentRect) {
+ mPendingInvalidateContentRect = false;
+ invalidateContentRect();
+ }
+ }
+ }
+
+ /**
+ * @see ActionMode#hide(long)
+ */
+ private void hideTemporarily(long duration) {
+ assert canHide();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ mActionMode.hide(duration);
+ }
+ }
+
+ private boolean canHide() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ return mActionMode.getType() == ActionMode.TYPE_FLOATING;
+ }
+ return false;
+ }
+
+ private long getDefaultHideDuration() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ return ViewConfiguration.getDefaultActionModeHideDuration();
+ }
+ return 2000;
+ }
}

Powered by Google App Engine
This is Rietveld 408576698