| Index: chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
|
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
|
| index aa90dddbbe452f8368c4c158442a024a061e8018..5a40ac5d0cd66f6ab2f2e04d2c336d5dac74cedc 100644
|
| --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
|
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
|
| @@ -4,7 +4,6 @@
|
|
|
| package org.chromium.chrome.browser.contextualsearch;
|
|
|
| -import android.os.Handler;
|
| import android.text.TextUtils;
|
|
|
| import org.chromium.base.VisibleForTesting;
|
| @@ -35,15 +34,6 @@ public class ContextualSearchSelectionController {
|
| LONG_PRESS
|
| }
|
|
|
| - // The number of milliseconds to wait for a selection change after a tap before considering
|
| - // the tap invalid. This can't be too small or the subsequent taps may not have established
|
| - // a new selection in time. This is because selectWordAroundCaret doesn't always select.
|
| - // TODO(donnd): Fix in Blink, crbug.com/435778.
|
| - private static final int INVALID_IF_NO_SELECTION_CHANGE_AFTER_TAP_MS = 50;
|
| -
|
| - // The default navigation-detection-delay in milliseconds.
|
| - private static final int TAP_NAVIGATION_DETECTION_DELAY = 16;
|
| -
|
| private static final String CONTAINS_WORD_PATTERN = "(\\w|\\p{L}|\\p{N})+";
|
| // A URL is:
|
| // 1: scheme://
|
| @@ -59,8 +49,6 @@ public class ContextualSearchSelectionController {
|
|
|
| private final ChromeActivity mActivity;
|
| private final ContextualSearchSelectionHandler mHandler;
|
| - private final Runnable mHandleInvalidTapRunnable;
|
| - private final Handler mRunnableHandler;
|
| private final float mPxToDp;
|
| private final Pattern mContainsWordPattern;
|
|
|
| @@ -69,7 +57,6 @@ public class ContextualSearchSelectionController {
|
| private boolean mWasTapGestureDetected;
|
| // Reflects whether the last tap was valid and whether we still have a tap-based selection.
|
| private ContextualSearchTapState mLastTapState;
|
| - private TapSuppressionHeuristics mTapHeuristics;
|
| private boolean mIsWaitingForInvalidTapDetection;
|
| private boolean mShouldHandleSelectionModification;
|
| private boolean mDidExpandSelection;
|
| @@ -81,6 +68,9 @@ public class ContextualSearchSelectionController {
|
| // The time of the most last scroll activity, or 0 if none.
|
| private long mLastScrollTimeNs;
|
|
|
| + // When the last tap gesture happened.
|
| + private long mTapTimeNanoseconds;
|
| +
|
| // Tracks whether a Context Menu has just been shown and the UX has been dismissed.
|
| // The selection may be unreliable until the next reset. See crbug.com/628436.
|
| private boolean mIsContextMenuShown;
|
| @@ -109,13 +99,7 @@ public class ContextualSearchSelectionController {
|
| // See crbug.com/444114.
|
| @Override
|
| public void onSingleTap(boolean consumed) {
|
| - // We may be notified that a tap has happened even when the system consumed the event.
|
| - // This is being used to support tapping on an existing selection to show the selection
|
| - // handles. We should process this tap unless we have already shown the selection
|
| - // handles (have a long-press selection) and the tap was consumed.
|
| - if (!(consumed && mSelectionType == SelectionType.LONG_PRESS)) {
|
| - scheduleInvalidTapNotification();
|
| - }
|
| + // TODO(donnd): remove completely!
|
| }
|
| }
|
|
|
| @@ -130,15 +114,6 @@ public class ContextualSearchSelectionController {
|
| mActivity = activity;
|
| mHandler = handler;
|
| mPxToDp = 1.f / mActivity.getResources().getDisplayMetrics().density;
|
| -
|
| - mRunnableHandler = new Handler();
|
| - mHandleInvalidTapRunnable = new Runnable() {
|
| - @Override
|
| - public void run() {
|
| - onInvalidTapDetectionTimeout();
|
| - }
|
| - };
|
| -
|
| mContainsWordPattern = Pattern.compile(CONTAINS_WORD_PATTERN);
|
| }
|
|
|
| @@ -246,7 +221,7 @@ public class ContextualSearchSelectionController {
|
| }
|
|
|
| if (selection == null || selection.isEmpty()) {
|
| - scheduleInvalidTapNotification();
|
| + mHandler.handleSelectionCleared();
|
| // When the user taps on the page it will place the caret in that position, which
|
| // will trigger a onSelectionChanged event with an empty string.
|
| if (mSelectionType == SelectionType.TAP) {
|
| @@ -255,14 +230,11 @@ public class ContextualSearchSelectionController {
|
| return;
|
| }
|
| }
|
| - if (!selection.isEmpty()) {
|
| - unscheduleInvalidTapNotification();
|
| - }
|
|
|
| mSelectedText = selection;
|
|
|
| if (mWasTapGestureDetected) {
|
| - mSelectionType = SelectionType.TAP;
|
| + assert mSelectionType == SelectionType.TAP;
|
| handleSelection(selection, mSelectionType);
|
| mWasTapGestureDetected = false;
|
| } else {
|
| @@ -285,9 +257,6 @@ public class ContextualSearchSelectionController {
|
| mWasTapGestureDetected = false;
|
| mSelectionType = SelectionType.LONG_PRESS;
|
| shouldHandleSelection = true;
|
| - // Since we're showing pins, we don't care if the previous tap was invalid
|
| - // anymore.
|
| - unscheduleInvalidTapNotification();
|
| }
|
| break;
|
| case SelectionEventType.SELECTION_HANDLES_CLEARED:
|
| @@ -334,6 +303,8 @@ public class ContextualSearchSelectionController {
|
| mLastTapState = null;
|
| mLastScrollTimeNs = 0;
|
| mIsContextMenuShown = false;
|
| + mTapTimeNanoseconds = 0;
|
| + mDidExpandSelection = false;
|
| }
|
|
|
| /**
|
| @@ -364,39 +335,11 @@ public class ContextualSearchSelectionController {
|
| // TODO(donnd): refactor to avoid needing a new handler API method as suggested by Pedro.
|
| if (mSelectionType != SelectionType.LONG_PRESS) {
|
| mWasTapGestureDetected = true;
|
| - long tapTimeNanoseconds = System.nanoTime();
|
| - // TODO(donnd): add a policy method to get adjusted tap count.
|
| - ChromePreferenceManager prefs = ChromePreferenceManager.getInstance();
|
| - int adjustedTapsSinceOpen = prefs.getContextualSearchTapCount()
|
| - - prefs.getContextualSearchTapQuickAnswerCount();
|
| - // Explicitly destroy the old heuristics so native code can dispose data.
|
| - if (mTapHeuristics != null) mTapHeuristics.destroy();
|
| - mTapHeuristics =
|
| - new TapSuppressionHeuristics(this, mLastTapState, x, y, adjustedTapsSinceOpen);
|
| - // TODO(donnd): Move to be called when the panel closes to work with states that change.
|
| - mTapHeuristics.logConditionState();
|
| - // Tell the manager what it needs in order to log metrics on whether the tap would have
|
| - // been suppressed if each of the heuristics were satisfied.
|
| - mHandler.handleMetricsForWouldSuppressTap(mTapHeuristics);
|
| + mSelectionType = SelectionType.TAP;
|
| + mTapTimeNanoseconds = System.nanoTime();
|
| mX = x;
|
| mY = y;
|
| - boolean shouldSuppressTap = mTapHeuristics.shouldSuppressTap();
|
| - if (shouldSuppressTap) {
|
| - mHandler.handleSuppressedTap();
|
| - } else {
|
| - // TODO(donnd): Find a better way to determine that a navigation will be triggered
|
| - // by the tap, or merge with other time-consuming actions like gathering surrounding
|
| - // text or detecting page mutations.
|
| - new Handler().postDelayed(new Runnable() {
|
| - @Override
|
| - public void run() {
|
| - mHandler.handleValidTap();
|
| - }
|
| - }, TAP_NAVIGATION_DETECTION_DELAY);
|
| - }
|
| - // Remember the tap state for subsequent tap evaluation.
|
| - mLastTapState =
|
| - new ContextualSearchTapState(x, y, tapTimeNanoseconds, shouldSuppressTap);
|
| + mHandler.handleValidTap();
|
| } else {
|
| // Long press; reset last tap state.
|
| mLastTapState = null;
|
| @@ -405,6 +348,44 @@ public class ContextualSearchSelectionController {
|
| }
|
|
|
| /**
|
| + * Handles Tap suppression by making a callback to either the handler's #handleSuppressedTap()
|
| + * or #handleNonSuppressedTap() after a possible delay.
|
| + * This should be called when the context is fully built (by gathering surrounding text
|
| + * if needed, etc) but before showing any UX.
|
| + */
|
| + void handleShouldSuppressTap() {
|
| + int x = (int) mX;
|
| + int y = (int) mY;
|
| +
|
| + // TODO(donnd): add a policy method to get adjusted tap count.
|
| + ChromePreferenceManager prefs = ChromePreferenceManager.getInstance();
|
| + int adjustedTapsSinceOpen = prefs.getContextualSearchTapCount()
|
| + - prefs.getContextualSearchTapQuickAnswerCount();
|
| + TapSuppressionHeuristics tapHeuristics =
|
| + new TapSuppressionHeuristics(this, mLastTapState, x, y, adjustedTapsSinceOpen);
|
| + // TODO(donnd): Move to be called when the panel closes to work with states that change.
|
| + tapHeuristics.logConditionState();
|
| + // Tell the manager what it needs in order to log metrics on whether the tap would have
|
| + // been suppressed if each of the heuristics were satisfied.
|
| + mHandler.handleMetricsForWouldSuppressTap(tapHeuristics);
|
| +
|
| + boolean shouldSuppressTap = tapHeuristics.shouldSuppressTap();
|
| + if (mTapTimeNanoseconds != 0) {
|
| + // Remember the tap state for subsequent tap evaluation.
|
| + mLastTapState =
|
| + new ContextualSearchTapState(x, y, mTapTimeNanoseconds, shouldSuppressTap);
|
| + } else {
|
| + mLastTapState = null;
|
| + }
|
| +
|
| + if (shouldSuppressTap) {
|
| + mHandler.handleSuppressedTap();
|
| + } else {
|
| + mHandler.handleNonSuppressedTap();
|
| + }
|
| + }
|
| +
|
| + /**
|
| * Gets the base page ContentViewCore.
|
| * Deprecated, use getBaseWebContents instead.
|
| * @return The Base Page's {@link ContentViewCore}, or {@code null} if there is no current tab.
|
| @@ -437,9 +418,6 @@ public class ContextualSearchSelectionController {
|
| * the search term.
|
| */
|
| void adjustSelection(int selectionStartAdjust, int selectionEndAdjust) {
|
| - // TODO(donnd): add code to verify that the selection is still valid before changing it.
|
| - // crbug.com/508354
|
| -
|
| if (selectionStartAdjust == 0 && selectionEndAdjust == 0) return;
|
| WebContents basePageWebContents = getBaseWebContents();
|
| if (basePageWebContents != null) {
|
| @@ -450,39 +428,6 @@ public class ContextualSearchSelectionController {
|
| }
|
|
|
| // ============================================================================================
|
| - // Invalid Tap Notification
|
| - // ============================================================================================
|
| -
|
| - /**
|
| - * Schedules a notification to check if the tap was invalid.
|
| - * When we call selectWordAroundCaret it selects nothing in cases where the tap was invalid.
|
| - * We have no way to know other than scheduling a notification to check later.
|
| - * This allows us to hide the bar when there's no selection.
|
| - */
|
| - private void scheduleInvalidTapNotification() {
|
| - // TODO(donnd): Fix selectWordAroundCaret to we can tell if it selects, instead
|
| - // of using a timer here! See crbug.com/435778.
|
| - mRunnableHandler.postDelayed(mHandleInvalidTapRunnable,
|
| - INVALID_IF_NO_SELECTION_CHANGE_AFTER_TAP_MS);
|
| - }
|
| -
|
| - /**
|
| - * Un-schedules all pending notifications to check if a tap was invalid.
|
| - */
|
| - private void unscheduleInvalidTapNotification() {
|
| - mRunnableHandler.removeCallbacks(mHandleInvalidTapRunnable);
|
| - mIsWaitingForInvalidTapDetection = true;
|
| - }
|
| -
|
| - /**
|
| - * Notify's the system that tap gesture has been completed.
|
| - */
|
| - private void onInvalidTapDetectionTimeout() {
|
| - mHandler.handleInvalidTap();
|
| - mIsWaitingForInvalidTapDetection = false;
|
| - }
|
| -
|
| - // ============================================================================================
|
| // Selection Modification
|
| // ============================================================================================
|
|
|
|
|