Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapSuppression.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapSuppression.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapSuppression.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..8a741316ae7171e79458a707d0af964d6da2c45f |
| --- /dev/null |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/TapSuppression.java |
| @@ -0,0 +1,113 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +package org.chromium.chrome.browser.contextualsearch; |
| + |
| +import android.content.Context; |
| + |
| +import org.chromium.chrome.browser.preferences.ChromePreferenceManager; |
| + |
| +/** |
| + * Heuristic for general Tap suppression that factors in a variety of signals. |
| + */ |
| +class TapSuppression extends ContextualSearchHeuristic { |
| + private static final int TIME_THRESHOLD_MILLISECONDS = 3000; |
|
pedro (no code reviews)
2016/06/27 22:14:29
The "second tap" is essentially a double tap and I
Donn Denman
2016/06/28 23:39:09
I think we briefly talked with Zach about this and
|
| + private static final double TAP_TWICE_DISTANCE_SQUARED_DP = Math.pow(30, 2); |
|
pedro (no code reviews)
2016/06/27 22:14:29
The "twice" in the name here is confusing, and see
Donn Denman
2016/06/28 23:39:09
Renamed to TAP_RADIUS_SQUARED_DP.
|
| + |
| + private final boolean mIsTapSuppressionEnabled; |
| + private final int mExperimentThresholdTaps; |
| + private final int mTapsSinceOpen; |
| + private final float mPxToDp; |
| + private final boolean mIsSecondTap; |
| + private final boolean mIsConditionSatisfied; // whether to suppress or not. |
| + |
| + /** |
| + * Constructs a heuristic to decide if a Tap should be suppressed or not. |
| + * Combines various signals to determine suppression, including whether the previous |
| + * Tap was suppressed for any reason. |
| + * @param context The Android Context. |
| + * @param controller The Selection Controller. |
| + * @param previousTapState The specifics regarding the previous Tap. |
| + * @param x The x coordinate of the current tap. |
| + * @param y The y coordinate of the current tap. |
| + */ |
| + TapSuppression(Context context, ContextualSearchSelectionController controller, |
| + ContextualSearchTapState previousTapState, int x, int y) { |
| + mIsSecondTap = previousTapState != null && previousTapState.wasSuppressed(); |
|
Donn Denman
2016/06/28 23:39:09
I think there were some cases where we think we're
|
| + mIsTapSuppressionEnabled = ContextualSearchFieldTrial.isTapSupressionEnabled(); |
| + mExperimentThresholdTaps = ContextualSearchFieldTrial.getSuppressionTaps(); |
| + mPxToDp = controller.getPxToDp(); |
| + mTapsSinceOpen = ChromePreferenceManager.getInstance(context).getContextualSearchTapCount(); |
| + |
| + boolean doSuppressTap = false; |
| + if (mIsTapSuppressionEnabled) { |
| + if (mIsSecondTap) { |
| + boolean shouldHandle = |
| + shouldHandleFirstTap() || shouldHandleSecondTap(previousTapState, x, y); |
| + doSuppressTap = !shouldHandle; |
| + } else { |
| + doSuppressTap = !shouldHandleFirstTap(); |
| + } |
| + } |
| + mIsConditionSatisfied = doSuppressTap; |
| + } |
| + |
| + @Override |
| + protected boolean isConditionSatisfied() { |
| + return mIsConditionSatisfied; |
| + } |
| + |
| + @Override |
| + protected void logConditionState() { |
| + if (mIsTapSuppressionEnabled) { |
| + ContextualSearchUma.logTapSuppression(mIsConditionSatisfied, mIsSecondTap); |
| + } |
| + } |
| + |
| + @Override |
| + protected void logResultsSeen(boolean wasSearchContentViewSeen, boolean wasActivatedByTap) { |
| + if (mIsTapSuppressionEnabled) { |
|
pedro (no code reviews)
2016/06/27 22:14:29
This will be called even when was triggered by lon
Donn Denman
2016/06/28 23:39:09
Done.
|
| + ContextualSearchUma.logTapSuppressionResultsSeen( |
| + wasSearchContentViewSeen, mIsSecondTap); |
| + } |
| + } |
| + |
| + /** |
| + * @return whether a first tap should be handled or not. |
| + */ |
| + private boolean shouldHandleFirstTap() { |
| + return mTapsSinceOpen < mExperimentThresholdTaps; |
| + } |
| + |
| + /** |
| + * Determines whether a second tap at the given coordinates should be handled. |
| + * @param tapState The specifics regarding the previous Tap. |
| + * @param x The x coordinate of the current tap. |
| + * @param y The y coordinate of the current tap. |
| + * @return whether a second tap at the given coordinates should be handled or not. |
| + */ |
| + private boolean shouldHandleSecondTap(ContextualSearchTapState tapState, int x, int y) { |
| + return wasTapCloseToPreviousTap(tapState, x, y); |
| + } |
| + |
| + /** |
| + * Determines whether a tap at the given coordinates is considered "close" to the previous |
| + * tap. |
| + * @param tapState The specifics regarding the previous Tap. |
| + * @param x The x coordinate of the current tap. |
| + * @param y The y coordinate of the current tap. |
| + */ |
| + private boolean wasTapCloseToPreviousTap(ContextualSearchTapState tapState, int x, int y) { |
|
twellington
2016/06/27 18:44:01
nit: can we combine this with the method in TapFar
Donn Denman
2016/06/28 23:39:09
I don't think it's worth combining since we're jus
|
| + boolean result = false; |
| + if (System.nanoTime() - tapState.tapTimeNanoseconds() |
|
pedro (no code reviews)
2016/06/27 22:14:29
The duration threshold does not belong in a method
Donn Denman
2016/06/28 23:39:09
Done.
|
| + <= (long) TIME_THRESHOLD_MILLISECONDS * NANOSECONDS_IN_A_MILLISECOND) { |
| + // Close enough in time, also in space? |
|
twellington
2016/06/27 18:44:01
The space is a 30dp square? Are we trying to detec
Donn Denman
2016/06/28 23:39:09
We're trying to determine if the user is tapping i
Donn Denman
2016/06/28 23:39:09
Yes, that was my plan.
|
| + float deltaXDp = (tapState.x() - x) * mPxToDp; |
| + float deltaYDp = (tapState.y() - y) * mPxToDp; |
| + float distanceSquaredDp = deltaXDp * deltaXDp + deltaYDp * deltaYDp; |
| + result = distanceSquaredDp <= TAP_TWICE_DISTANCE_SQUARED_DP; |
| + } |
| + return result; |
| + } |
| +} |