Commit 4a22f717 authored by donnd's avatar donnd Committed by Commit Bot

[TTS] Add some initial signals for Tap in content.

Adds a few simple signals for a Tap gesture relative to the content
that was tapped.  These signals include word length and tap offset.
Logs UMA for CTR when these signals are present.

Updates the CS Context with analysis of the content where the Tap
gesture occurred.

One signal determines if the user tapped near the edge of a word
or not. The rest look at very short words, or relatively long words.

All signals use the existing CSHeuristics framework to do the checking and logging.

Updates the CSHeuristics framework to make the CSContext available
to heuristics so they can inspect the text tapped before deciding
whether to suppress or not.

Adds Field Trial params to enable actual suppression based on
these new signals (likely to be used only for interactive-testing
and demonstration purposes).

BUG=723194

Review-Url: https://codereview.chromium.org/2906763002
Cr-Commit-Position: refs/heads/master@{#476485}
parent 9aecc2e1
......@@ -4,6 +4,7 @@
package org.chromium.chrome.browser.contextualsearch;
import android.annotation.SuppressLint;
import android.text.TextUtils;
import org.chromium.base.annotations.CalledByNative;
......@@ -17,7 +18,10 @@ import javax.annotation.Nullable;
* or changed.
*/
public abstract class ContextualSearchContext {
static final int INVALID_SELECTION_OFFSET = -1;
static final int INVALID_OFFSET = -1;
// Non-visible word-break marker.
private static final int SOFT_HYPHEN_CHAR = '\u00AD';
// Pointer to the native instance of this class.
private long mNativePointer;
......@@ -30,8 +34,11 @@ public abstract class ContextualSearchContext {
private String mSurroundingText;
// The start and end offsets of the selection within the text content.
private int mSelectionStartOffset = INVALID_SELECTION_OFFSET;
private int mSelectionEndOffset = INVALID_SELECTION_OFFSET;
private int mSelectionStartOffset = INVALID_OFFSET;
private int mSelectionEndOffset = INVALID_OFFSET;
// The offset of an initial Tap gesture within the text content.
private int mTapOffset = INVALID_OFFSET;
// The initial word selected by a Tap, or null.
private String mInitialSelectedWord;
......@@ -39,6 +46,13 @@ public abstract class ContextualSearchContext {
// The original encoding of the base page.
private String mEncoding;
// The tapped word, as analyzed internally before selection takes place, or {@code null} if no
// analysis has been done yet.
private String mTappedWord;
// The offset of the tap within the tapped word or {@code INVALID_OFFSET} if not yet analyzed.
private int mTappedWordOffset = INVALID_OFFSET;
/**
* Constructs a context that tracks the selection and some amount of page content.
*/
......@@ -85,6 +99,9 @@ public abstract class ContextualSearchContext {
mSurroundingText = surroundingText;
mSelectionStartOffset = startOffset;
mSelectionEndOffset = endOffset;
if (startOffset == endOffset && !hasAnalyzedTap()) {
analyzeTap(startOffset);
}
// Notify of an initial selection if it's not empty.
if (endOffset > startOffset) onSelectionChanged();
}
......@@ -99,7 +116,7 @@ public abstract class ContextualSearchContext {
/**
* @return The offset into the surrounding text of the start of the selection, or
* {@link #INVALID_SELECTION_OFFSET} if not yet established.
* {@link #INVALID_OFFSET} if not yet established.
*/
int getSelectionStartOffset() {
return mSelectionStartOffset;
......@@ -107,7 +124,7 @@ public abstract class ContextualSearchContext {
/**
* @return The offset into the surrounding text of the end of the selection, or
* {@link #INVALID_SELECTION_OFFSET} if not yet established.
* {@link #INVALID_OFFSET} if not yet established.
*/
int getSelectionEndOffset() {
return mSelectionEndOffset;
......@@ -143,9 +160,7 @@ public abstract class ContextualSearchContext {
* @return Whether this context can Resolve the Search Term.
*/
boolean canResolve() {
return mHasSetResolveProperties && mSelectionStartOffset != INVALID_SELECTION_OFFSET
&& mSelectionEndOffset != INVALID_SELECTION_OFFSET
&& mSelectionEndOffset > mSelectionStartOffset;
return mHasSetResolveProperties && hasValidSelection();
}
/**
......@@ -180,7 +195,138 @@ public abstract class ContextualSearchContext {
*/
abstract void onSelectionChanged();
// TODO(donnd): Add a test for this class!
// ============================================================================================
// Content Analysis.
// ============================================================================================
/**
* @return Whether this context has valid Surrounding text and initial Tap offset.
*/
private boolean hasValidTappedText() {
return !TextUtils.isEmpty(mSurroundingText) && mTapOffset >= 0
&& mTapOffset <= mSurroundingText.length();
}
/**
* @return Whether this context has a valid selection.
*/
private boolean hasValidSelection() {
if (!hasValidTappedText()) return false;
return mSelectionStartOffset != INVALID_OFFSET && mSelectionEndOffset != INVALID_OFFSET
&& mSelectionStartOffset < mSelectionEndOffset
&& mSelectionEndOffset < mSurroundingText.length();
}
/**
* @return Whether a Tap gesture has occurred and been analyzed.
*/
private boolean hasAnalyzedTap() {
return mTapOffset >= 0;
}
/**
* @return The tapped word, or {@code null} if the tapped word cannot be identified by the
* current limited parsing capability.
* @see #analyzeTap
*/
String getTappedWord() {
return mTappedWord;
}
/**
* @return The offset of the tap within the tapped word, or {@code -1} if the tapped word cannot
* be identified by the current parsing capability.
* @see #analyzeTap
*/
int getTappedWordOffset() {
return mTappedWordOffset;
}
/**
* Finds the tapped word by expanding from the initial Tap offset looking for word-breaks.
* This mimics the Blink word-segmentation invoked by SelectWordAroundCaret and similar
* selection logic, but is only appropriate for limited use. Does not work on ideographic
* languages and possibly many other cases. Should only be used only for ML signal evaluation.
* @param tapOffset The offset of the Tap within the surrounding text.
*/
private void analyzeTap(int tapOffset) {
mTapOffset = tapOffset;
mTappedWord = null;
mTappedWordOffset = INVALID_OFFSET;
assert hasValidTappedText();
int wordStartOffset = findWordStartOffset(mSurroundingText, mTapOffset);
int wordEndOffset = findWordEndOffset(mSurroundingText, mTapOffset);
if (wordStartOffset == INVALID_OFFSET || wordEndOffset == INVALID_OFFSET) return;
mTappedWord = mSurroundingText.substring(wordStartOffset, wordEndOffset);
mTappedWordOffset = mTapOffset - wordStartOffset;
}
/**
* Finds the offset of the start of the word that includes the given initial offset.
* The character at the initial offset is not examined, but the one before it is, and scanning
* continues on to earlier characters until a non-word character is found. The offset just
* before the non-word character is returned. If the initial offset is a space immediately
* following a word then the start offset of that word is returned.
* @param text The text to scan.
* @param initial The initial offset to scan before.
* @return The start of the word that contains the given initial offset, within {@code text}.
*/
private int findWordStartOffset(String text, int initial) {
// Scan before, aborting if we hit any ideographic letter.
for (int offset = initial - 1; offset >= 0; offset--) {
if (isIdeographicAtIndex(text, offset)) return INVALID_OFFSET;
if (isWordBreakAtIndex(text, offset)) {
// The start of the word is after this word break.
return offset + 1;
}
}
return INVALID_OFFSET;
}
/**
* Finds the offset of the end of the word that includes the given initial offset.
* NOTE: this is the index of the character just past the last character of the word,
* so a 3 character word "who" has start index 0 and end index 3.
* The character at the initial offset is examined and each one after that too until a non-word
* character is encountered, and that offset will be returned.
* @param text The text to scan.
* @param initial The initial offset to scan from.
* @return The end of the word that contains the given initial offset, within {@code text}.
*/
private int findWordEndOffset(String text, int initial) {
// Scan after, aborting if we hit any CJKN letter.
for (int offset = initial; offset < text.length(); offset++) {
if (isIdeographicAtIndex(text, offset)) return INVALID_OFFSET;
if (isWordBreakAtIndex(text, offset)) {
// The end of the word is the offset of this word break.
return offset;
}
}
return INVALID_OFFSET;
}
/**
* @return Whether the character at the given index in the text is "Ideographic" (as in CJKV
* languages), which means there may not be reliable word breaks.
*/
@SuppressLint("NewApi")
private boolean isIdeographicAtIndex(String text, int index) {
return Character.isIdeographic(text.charAt(index));
}
/**
* @return Whether the character at the given index is a word-break.
*/
private boolean isWordBreakAtIndex(String text, int index) {
return !Character.isLetterOrDigit(text.charAt(index))
&& text.codePointAt(index) != SOFT_HYPHEN_CHAR;
}
// ============================================================================================
// Native callback support.
......
......@@ -48,6 +48,10 @@ public class ContextualSearchFieldTrial {
private static final String SCREEN_TOP_SUPPRESSION_DPS = "screen_top_suppression_dps";
private static final String ENABLE_BAR_OVERLAP_COLLECTION = "enable_bar_overlap_collection";
private static final String BAR_OVERLAP_SUPPRESSION_ENABLED = "enable_bar_overlap_suppression";
private static final String WORD_EDGE_SUPPRESSION_ENABLED = "enable_word_edge_suppression";
private static final String SHORT_WORD_SUPPRESSION_ENABLED = "enable_short_word_suppression";
private static final String NOT_LONG_WORD_SUPPRESSION_ENABLED =
"enable_not_long_word_suppression";
private static final String MINIMUM_SELECTION_LENGTH = "minimum_selection_length";
......@@ -67,6 +71,7 @@ public class ContextualSearchFieldTrial {
"disable_page_content_notification";
// Cached values to avoid repeated and redundant JNI operations.
// TODO(donnd): consider creating a single Map to cache these static values.
private static Boolean sEnabled;
private static Boolean sDisableSearchTermResolution;
private static Boolean sIsMandatoryPromoEnabled;
......@@ -78,6 +83,9 @@ public class ContextualSearchFieldTrial {
private static Integer sScreenTopSuppressionDps;
private static Boolean sIsBarOverlapCollectionEnabled;
private static Boolean sIsBarOverlapSuppressionEnabled;
private static Boolean sIsWordEdgeSuppressionEnabled;
private static Boolean sIsShortWordSuppressionEnabled;
private static Boolean sIsNotLongWordSuppressionEnabled;
private static Integer sMinimumSelectionLength;
private static Boolean sIsOnlineDetectionDisabled;
private static Boolean sIsAmpAsSeparateTabDisabled;
......@@ -247,6 +255,36 @@ public class ContextualSearchFieldTrial {
return sIsBarOverlapSuppressionEnabled.booleanValue();
}
/**
* @return Whether triggering is suppressed by a tap that's near the edge of a word.
*/
static boolean isWordEdgeSuppressionEnabled() {
if (sIsWordEdgeSuppressionEnabled == null) {
sIsWordEdgeSuppressionEnabled = getBooleanParam(WORD_EDGE_SUPPRESSION_ENABLED);
}
return sIsWordEdgeSuppressionEnabled.booleanValue();
}
/**
* @return Whether triggering is suppressed by a tap that's in a short word.
*/
static boolean isShortWordSuppressionEnabled() {
if (sIsShortWordSuppressionEnabled == null) {
sIsShortWordSuppressionEnabled = getBooleanParam(SHORT_WORD_SUPPRESSION_ENABLED);
}
return sIsShortWordSuppressionEnabled.booleanValue();
}
/**
* @return Whether triggering is suppressed by a tap that's not in a long word.
*/
static boolean isNotLongWordSuppressionEnabled() {
if (sIsNotLongWordSuppressionEnabled == null) {
sIsNotLongWordSuppressionEnabled = getBooleanParam(NOT_LONG_WORD_SUPPRESSION_ENABLED);
}
return sIsNotLongWordSuppressionEnabled.booleanValue();
}
/**
* @return The minimum valid selection length.
*/
......
......@@ -1475,13 +1475,14 @@ public class ContextualSearchManager implements ContextualSearchManagementDelega
@Override
public void decideSuppression() {
mInternalStateController.notifyStartingWorkOn(InternalState.DECIDING_SUPPRESSION);
// Ranker will handle the suppression, but our legacy implementation uses
// TapSuppressionHeuristics (run from the ContextualSearchSelectionConroller).
// Usage includes tap-far-from-previous suppression.
mTapSuppressionRankerLogger.setupLoggingForPage(getBasePageUrl());
// TODO(donnd): Move handleShouldSuppressTap out of the Selection Controller.
mSelectionController.handleShouldSuppressTap(mTapSuppressionRankerLogger);
mSelectionController.handleShouldSuppressTap(mContext, mTapSuppressionRankerLogger);
}
/** Starts showing the Tap UI by selecting a word around the current caret. */
......
......@@ -205,7 +205,7 @@ public class ContextualSearchSelectionController {
if (baseContentView != null) {
baseContentView.clearSelection();
}
resetAllStates();
resetSelectionStates();
}
/**
......@@ -351,10 +351,12 @@ public class ContextualSearchSelectionController {
* 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.
* @param contextualSearchContext The {@link ContextualSearchContext} for the Tap gesture.
* @param rankerLogger The {@link ContextualSearchRankerLogger} currently being used to measure
* or suppress the UI by Ranker.
*/
void handleShouldSuppressTap(ContextualSearchRankerLogger rankerLogger) {
void handleShouldSuppressTap(ContextualSearchContext contextualSearchContext,
ContextualSearchRankerLogger rankerLogger) {
int x = (int) mX;
int y = (int) mY;
......@@ -362,9 +364,8 @@ public class ContextualSearchSelectionController {
ChromePreferenceManager prefs = ChromePreferenceManager.getInstance();
int adjustedTapsSinceOpen = prefs.getContextualSearchTapCount()
- prefs.getContextualSearchTapQuickAnswerCount();
TapSuppressionHeuristics tapHeuristics =
new TapSuppressionHeuristics(this, mLastTapState, x, y, adjustedTapsSinceOpen);
TapSuppressionHeuristics tapHeuristics = new TapSuppressionHeuristics(
this, mLastTapState, x, y, adjustedTapsSinceOpen, contextualSearchContext);
// TODO(donnd): Move to be called when the panel closes to work with states that change.
tapHeuristics.logConditionState();
......
......@@ -802,6 +802,47 @@ public class ContextualSearchUma {
}
}
/**
* Log whether results were seen due to a Tap on a short word.
* @param wasSearchContentViewSeen If the panel was opened.
* @param isTapOnShortWord Whether this tap was on a "short" word.
*/
public static void logTapShortWordSeen(
boolean wasSearchContentViewSeen, boolean isTapOnShortWord) {
if (!isTapOnShortWord) return;
// We just record CTR of short words.
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchTapShortWordSeen",
wasSearchContentViewSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN, RESULTS_SEEN_BOUNDARY);
}
/**
* Log whether results were seen due to a Tap on a long word.
* @param wasSearchContentViewSeen If the panel was opened.
* @param isTapOnLongWord Whether this tap was on a long word.
*/
public static void logTapLongWordSeen(
boolean wasSearchContentViewSeen, boolean isTapOnLongWord) {
if (!isTapOnLongWord) return;
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchTapLongWordSeen",
wasSearchContentViewSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN, RESULTS_SEEN_BOUNDARY);
}
/**
* Log whether results were seen due to a Tap that was on the middle of a word.
* @param wasSearchContentViewSeen If the panel was opened.
* @param isTapOnWordMiddle Whether this tap was on the middle of a word.
*/
public static void logTapOnWordMiddleSeen(
boolean wasSearchContentViewSeen, boolean isTapOnWordMiddle) {
if (!isTapOnWordMiddle) return;
// We just record CTR of words tapped in the "middle".
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchTapOnWordMiddleSeen",
wasSearchContentViewSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN, RESULTS_SEEN_BOUNDARY);
}
/**
* Logs whether results were seen and whether any tap suppression heuristics were satisfied.
* @param wasSearchContentViewSeen If the panel was opened.
......
......@@ -19,22 +19,19 @@ public class TapSuppressionHeuristics extends ContextualSearchHeuristics {
* @param tapsSinceOpen the number of Tap gestures since the last open of the panel.
*/
TapSuppressionHeuristics(ContextualSearchSelectionController selectionController,
ContextualSearchTapState previousTapState, int x, int y, int tapsSinceOpen) {
ContextualSearchTapState previousTapState, int x, int y, int tapsSinceOpen,
ContextualSearchContext contextualSearchContext) {
super();
mCtrSuppression = new CtrSuppression();
mHeuristics.add(mCtrSuppression);
RecentScrollTapSuppression scrollTapExperiment =
new RecentScrollTapSuppression(selectionController);
mHeuristics.add(scrollTapExperiment);
mHeuristics.add(new RecentScrollTapSuppression(selectionController));
TapFarFromPreviousSuppression farFromPreviousHeuristic =
new TapFarFromPreviousSuppression(selectionController, previousTapState, x, y);
mHeuristics.add(farFromPreviousHeuristic);
NearTopTapSuppression tapNearTopSuppression =
new NearTopTapSuppression(selectionController, y);
mHeuristics.add(tapNearTopSuppression);
BarOverlapTapSuppression barOverlapTapSuppression =
new BarOverlapTapSuppression(selectionController, y);
mHeuristics.add(barOverlapTapSuppression);
mHeuristics.add(new TapWordLengthSuppression(contextualSearchContext));
mHeuristics.add(new TapWordEdgeSuppression(contextualSearchContext));
mHeuristics.add(new NearTopTapSuppression(selectionController, y));
mHeuristics.add(new BarOverlapTapSuppression(selectionController, y));
// General Tap Suppression and Tap Twice.
TapSuppression tapSuppression =
new TapSuppression(selectionController, previousTapState, x, y, tapsSinceOpen);
......
// Copyright 2017 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.text.TextUtils;
/**
* Implements the policy that a Tap relatively far away from the middle of a word should be
* ignored. When a Tap is close to the middle of the word tapped it's treated normally.
*/
class TapWordEdgeSuppression extends ContextualSearchHeuristic {
private static final int INVALID_OFFSET = ContextualSearchContext.INVALID_OFFSET;
private static final int MIN_WORD_LENGTH = 4;
private static final double MIN_WORD_START_RATIO = 0.25;
private static final double MIN_WORD_END_RATIO = 0.25;
private final boolean mIsSuppressionEnabled;
private final boolean mIsConditionSatisfied;
/**
* Constructs a heuristic to determine if the current Tap is close to the edge of the word.
* @param contextualSearchContext The current {@link ContextualSearchContext} so we can figure
* out what part of the word has been tapped.
*/
TapWordEdgeSuppression(ContextualSearchContext contextualSearchContext) {
mIsSuppressionEnabled = ContextualSearchFieldTrial.isWordEdgeSuppressionEnabled();
mIsConditionSatisfied = isTapNearWordEdge(contextualSearchContext);
}
@Override
protected boolean isConditionSatisfiedAndEnabled() {
return mIsSuppressionEnabled && mIsConditionSatisfied;
}
@Override
protected void logResultsSeen(boolean wasSearchContentViewSeen, boolean wasActivatedByTap) {
if (wasActivatedByTap) {
ContextualSearchUma.logTapOnWordMiddleSeen(
wasSearchContentViewSeen, !mIsConditionSatisfied);
}
}
@Override
protected boolean shouldAggregateLogForTapSuppression() {
return true;
}
@Override
protected boolean isConditionSatisfiedForAggregateLogging() {
return mIsConditionSatisfied;
}
/**
* Whether the tap is near the word edge and not a second-tap (tap following a suppressed tap).
* @param contextualSearchContext The {@link ContextualSearchContext}, used to determine how
* close the tap offset is to the word edges.
* @return Whether the tap is near an edge and not a second tap.
*/
private boolean isTapNearWordEdge(ContextualSearchContext contextualSearchContext) {
// If setup failed, don't suppress.
String tappedWord = contextualSearchContext.getTappedWord();
int tapOffset = contextualSearchContext.getTappedWordOffset();
if (TextUtils.isEmpty(tappedWord) || tapOffset == INVALID_OFFSET) return false;
// If the word is long enough, suppress if the tap was near one end or the other.
boolean isInStartEdge = (double) tapOffset / tappedWord.length() < MIN_WORD_START_RATIO;
boolean isInEndEdge = (double) (tappedWord.length() - tapOffset) / tappedWord.length()
< MIN_WORD_END_RATIO;
if (tappedWord.length() >= MIN_WORD_LENGTH && (isInStartEdge || isInEndEdge)) return true;
return false;
}
}
// Copyright 2017 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.text.TextUtils;
/**
* Implements signals for Taps on short and long words.
* This signal could be used for suppression when the word is short, so we aggregate-log too.
* We log CTR to UMA for Taps on both short and long words.
*/
class TapWordLengthSuppression extends ContextualSearchHeuristic {
private static final int MAXIMUM_SHORT_WORD_LENGTH = 3;
private static final int MAXIMUM_NOT_LONG_WORD_LENGTH = 9;
private final boolean mIsShortWordSuppressionEnabled;
private final boolean mIsNotLongWordSuppressionEnabled;
private final boolean mIsShortWordConditionSatisfied;
private final boolean mIsNotLongWordConditionSatisfied;
/**
* Constructs a heuristic to categorize the Tap based on word length of the tapped word.
* @param contextualSearchContext The current {@link ContextualSearchContext} so we can inspect
* the word tapped.
*/
TapWordLengthSuppression(ContextualSearchContext contextualSearchContext) {
mIsShortWordSuppressionEnabled = ContextualSearchFieldTrial.isShortWordSuppressionEnabled();
mIsNotLongWordSuppressionEnabled =
ContextualSearchFieldTrial.isNotLongWordSuppressionEnabled();
mIsShortWordConditionSatisfied =
!isTapOnWordLongerThan(MAXIMUM_SHORT_WORD_LENGTH, contextualSearchContext);
mIsNotLongWordConditionSatisfied =
!isTapOnWordLongerThan(MAXIMUM_NOT_LONG_WORD_LENGTH, contextualSearchContext);
}
@Override
protected boolean isConditionSatisfiedAndEnabled() {
return mIsShortWordSuppressionEnabled && mIsShortWordConditionSatisfied
|| mIsNotLongWordSuppressionEnabled && mIsNotLongWordConditionSatisfied;
}
@Override
protected void logResultsSeen(boolean wasSearchContentViewSeen, boolean wasActivatedByTap) {
if (wasActivatedByTap) {
ContextualSearchUma.logTapShortWordSeen(
wasSearchContentViewSeen, mIsShortWordConditionSatisfied);
// Log CTR of long words, since not-long word CTR is probably not useful.
ContextualSearchUma.logTapLongWordSeen(
wasSearchContentViewSeen, !mIsNotLongWordConditionSatisfied);
}
}
@Override
protected boolean shouldAggregateLogForTapSuppression() {
return true;
}
@Override
protected boolean isConditionSatisfiedForAggregateLogging() {
// Short-word suppression is a good candidate for aggregate logging of overall suppression.
return mIsShortWordConditionSatisfied;
}
/**
* @return Whether the tap is on a word longer than the given word length maximum.
*/
private boolean isTapOnWordLongerThan(
int maxWordLength, ContextualSearchContext contextualSearchContext) {
// If setup failed, don't suppress.
String tappedWord = contextualSearchContext.getTappedWord();
return !TextUtils.isEmpty(tappedWord) && tappedWord.length() > maxWordLength;
}
}
......@@ -262,6 +262,8 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/contextualsearch/TapFarFromPreviousSuppression.java",
"java/src/org/chromium/chrome/browser/contextualsearch/TapSuppression.java",
"java/src/org/chromium/chrome/browser/contextualsearch/TapSuppressionHeuristics.java",
"java/src/org/chromium/chrome/browser/contextualsearch/TapWordEdgeSuppression.java",
"java/src/org/chromium/chrome/browser/contextualsearch/TapWordLengthSuppression.java",
"java/src/org/chromium/chrome/browser/cookies/CanonicalCookie.java",
"java/src/org/chromium/chrome/browser/cookies/CookiesFetcher.java",
"java/src/org/chromium/chrome/browser/crash/ChromeMinidumpUploadJobService.java",
......
......@@ -66297,6 +66297,26 @@ http://cs/file:chrome/histograms.xml - but prefer this file for new entries.
</summary>
</histogram>
<histogram name="Search.ContextualSearchTapLongWordSeen"
enum="ContextualSearchResultsSeen">
<owner>donnd@chromium.org</owner>
<owner>twellington@chromium.org</owner>
<summary>
Whether results were seen for a Tap that was on a word considered long.
Recorded when the UX is hidden. Implemented for Android.
</summary>
</histogram>
<histogram name="Search.ContextualSearchTapShortWordSeen"
enum="ContextualSearchResultsSeen">
<owner>donnd@chromium.org</owner>
<owner>twellington@chromium.org</owner>
<summary>
Whether results were seen for a Tap that was on a word considered short.
Recorded when the UX is hidden. Implemented for Android.
</summary>
</histogram>
<histogram name="Search.ContextualSearchTapsSinceOpenDecided" units="taps">
<owner>donnd@chromium.org</owner>
<owner>twellington@chromium.org</owner>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment