blob: f929e0f8b41a2c4df19b57a83bb84f2f712795d3 [file] [log] [blame]
// Copyright 2015 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.format.DateUtils;
import android.util.Pair;
import androidx.annotation.IntDef;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.PanelState;
import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason;
import org.chromium.chrome.browser.contextualsearch.ResolvedSearchTerm.CardTag;
import org.chromium.components.sync.AndroidSyncSettings;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Centralizes UMA data collection for Contextual Search. All calls must be made from the UI thread.
*/
public class ContextualSearchUma {
// Constants to use for the original selection gesture
private static final boolean LONG_PRESS = false;
private static final boolean TAP = true;
// Constants used to log UMA "enum" histograms about the Contextual Search's preference state.
@IntDef({Preference.UNINITIALIZED, Preference.ENABLED, Preference.DISABLED})
@Retention(RetentionPolicy.SOURCE)
private @interface Preference {
int UNINITIALIZED = 0;
int ENABLED = 1;
int DISABLED = 2;
int NUM_ENTRIES = 3;
}
// Constants used to log UMA "enum" histograms about whether search results were seen.
@IntDef({Results.SEEN, Results.NOT_SEEN})
@Retention(RetentionPolicy.SOURCE)
private @interface Results {
int SEEN = 0;
int NOT_SEEN = 1;
int NUM_ENTRIES = 2;
}
// Constants used to log UMA "enum" histograms about whether the selection is valid.
@IntDef({Selection.VALID, Selection.INVALID})
@Retention(RetentionPolicy.SOURCE)
private @interface Selection {
int VALID = 0;
int INVALID = 1;
int NUM_ENTRIES = 2;
}
// Constants used to log UMA "enum" histograms about a request's outcome.
@IntDef({Request.NOT_FAILED, Request.FAILED})
@Retention(RetentionPolicy.SOURCE)
private @interface Request {
int NOT_FAILED = 0;
int FAILED = 1;
int NUM_ENTRIES = 2;
}
// Constants used to log UMA "enum" histograms about the panel's state transitions.
// Entry code: first entry into CLOSED.
@IntDef({EnterClosedFrom.OTHER, EnterClosedFrom.PEEKED_BACK_PRESS,
EnterClosedFrom.PEEKED_BASE_PAGE_SCROLL, EnterClosedFrom.PEEKED_TEXT_SELECT_TAP,
EnterClosedFrom.EXPANDED_BACK_PRESS, EnterClosedFrom.EXPANDED_BASE_PAGE_TAP,
EnterClosedFrom.EXPANDED_FLING, EnterClosedFrom.MAXIMIZED_BACK_PRESS,
EnterClosedFrom.MAXIMIZED_FLING, EnterClosedFrom.MAXIMIZED_TAB_PROMOTION,
EnterClosedFrom.MAXIMIZED_SERP_NAVIGATION})
@Retention(RetentionPolicy.SOURCE)
private @interface EnterClosedFrom {
int OTHER = 0;
int PEEKED_BACK_PRESS = 1;
int PEEKED_BASE_PAGE_SCROLL = 2;
int PEEKED_TEXT_SELECT_TAP = 3;
int EXPANDED_BACK_PRESS = 4;
int EXPANDED_BASE_PAGE_TAP = 5;
int EXPANDED_FLING = 6;
int MAXIMIZED_BACK_PRESS = 7;
int MAXIMIZED_FLING = 8;
int MAXIMIZED_TAB_PROMOTION = 9;
int MAXIMIZED_SERP_NAVIGATION = 10;
int NUM_ENTRIES = 11;
}
// Entry code: first entry into PEEKED.
@IntDef({EnterPeekedFrom.OTHER, EnterPeekedFrom.CLOSED_TEXT_SELECT_TAP,
EnterPeekedFrom.CLOSED_EXT_SELECT_LONG_PRESS, EnterPeekedFrom.PEEKED_TEXT_SELECT_TAP,
EnterPeekedFrom.PEEKED_TEXT_SELECT_LONG_PRESS, EnterPeekedFrom.EXPANDED_SEARCH_BAR_TAP,
EnterPeekedFrom.EXPANDED_SWIPE, EnterPeekedFrom.EXPANDED_FLING,
EnterPeekedFrom.MAXIMIZED_SWIPE, EnterPeekedFrom.MAXIMIZED_FLING})
@Retention(RetentionPolicy.SOURCE)
private @interface EnterPeekedFrom {
int OTHER = 0;
int CLOSED_TEXT_SELECT_TAP = 1;
int CLOSED_EXT_SELECT_LONG_PRESS = 2;
int PEEKED_TEXT_SELECT_TAP = 3;
int PEEKED_TEXT_SELECT_LONG_PRESS = 4;
int EXPANDED_SEARCH_BAR_TAP = 5;
int EXPANDED_SWIPE = 6;
int EXPANDED_FLING = 7;
int MAXIMIZED_SWIPE = 8;
int MAXIMIZED_FLING = 9;
int NUM_ENTRIES = 10;
}
// Entry code: first entry into EXPANDED.
@IntDef({EnterExpandedFrom.OTHER, EnterExpandedFrom.PEEKED_SEARCH_BAR_TAP,
EnterExpandedFrom.PEEKED_SWIPE, EnterExpandedFrom.PEEKED_FLING,
EnterExpandedFrom.MAXIMIZED_SWIPE, EnterExpandedFrom.MAXIMIZED_FLING})
@Retention(RetentionPolicy.SOURCE)
private @interface EnterExpandedFrom {
int OTHER = 0;
int PEEKED_SEARCH_BAR_TAP = 1;
int PEEKED_SWIPE = 2;
int PEEKED_FLING = 3;
int MAXIMIZED_SWIPE = 4;
int MAXIMIZED_FLING = 5;
int NUM_ENTRIES = 6;
}
// Entry code: first entry into MAXIMIZED.
@IntDef({EnterMaximizedFrom.OTHER, EnterMaximizedFrom.PEEKED_SWIPE,
EnterMaximizedFrom.PEEKED_FLING, EnterMaximizedFrom.EXPANDED_SWIPE,
EnterMaximizedFrom.EXPANDED_FLING, EnterMaximizedFrom.EXPANDED_SERP_NAVIGATION})
@Retention(RetentionPolicy.SOURCE)
private @interface EnterMaximizedFrom {
int OTHER = 0;
int PEEKED_SWIPE = 1;
int PEEKED_FLING = 2;
int EXPANDED_SWIPE = 3;
int EXPANDED_FLING = 4;
int EXPANDED_SERP_NAVIGATION = 5;
int NUM_ENTRIES = 6;
}
// Exit code: first exit from CLOSED (or UNDEFINED).
@IntDef({ExitClosedTo.OTHER, ExitClosedTo.PEEKED_TEXT_SELECT_TAP,
ExitClosedTo.PEEKED_TEXT_SELECT_LONG_PRESS})
@Retention(RetentionPolicy.SOURCE)
private @interface ExitClosedTo {
int OTHER = 0;
int PEEKED_TEXT_SELECT_TAP = 1;
int PEEKED_TEXT_SELECT_LONG_PRESS = 2;
int NUM_ENTRIES = 3;
}
// Exit code: first exit from PEEKED.
@IntDef({ExitPeekedTo.OTHER, ExitPeekedTo.CLOSED_BACK_PRESS,
ExitPeekedTo.CLOSED_BASE_PAGE_SCROLL, ExitPeekedTo.CLOSED_TEXT_SELECT_TAP,
ExitPeekedTo.PEEKED_TEXT_SELECT_TAP, ExitPeekedTo.PEEKED_TEXT_SELECT_LONG_PRESS,
ExitPeekedTo.EXPANDED_SEARCH_BAR_TAP, ExitPeekedTo.EXPANDED_SWIPE,
ExitPeekedTo.EXPANDED_FLING, ExitPeekedTo.MAXIMIZED_SWIPE,
ExitPeekedTo.MAXIMIZED_FLING})
@Retention(RetentionPolicy.SOURCE)
private @interface ExitPeekedTo {
int OTHER = 0;
int CLOSED_BACK_PRESS = 1;
int CLOSED_BASE_PAGE_SCROLL = 2;
int CLOSED_TEXT_SELECT_TAP = 3;
int PEEKED_TEXT_SELECT_TAP = 4;
int PEEKED_TEXT_SELECT_LONG_PRESS = 5;
int EXPANDED_SEARCH_BAR_TAP = 6;
int EXPANDED_SWIPE = 7;
int EXPANDED_FLING = 8;
int MAXIMIZED_SWIPE = 9;
int MAXIMIZED_FLING = 10;
int NUM_ENTRIES = 11;
}
// Exit code: first exit from EXPANDED.
@IntDef({ExitExpandedTo.OTHER, ExitExpandedTo.CLOSED_BACK_PRESS,
ExitExpandedTo.CLOSED_BASE_PAGE_TAP, ExitExpandedTo.CLOSED_FLING,
ExitExpandedTo.PEEKED_SEARCH_BAR_TAP, ExitExpandedTo.PEEKED_SWIPE,
ExitExpandedTo.PEEKED_FLING, ExitExpandedTo.MAXIMIZED_SWIPE,
ExitExpandedTo.MAXIMIZED_FLING, ExitExpandedTo.MAXIMIZED_SERP_NAVIGATION})
@Retention(RetentionPolicy.SOURCE)
private @interface ExitExpandedTo {
int OTHER = 0;
int CLOSED_BACK_PRESS = 1;
int CLOSED_BASE_PAGE_TAP = 2;
int CLOSED_FLING = 3;
int PEEKED_SEARCH_BAR_TAP = 4;
int PEEKED_SWIPE = 5;
int PEEKED_FLING = 6;
int MAXIMIZED_SWIPE = 7;
int MAXIMIZED_FLING = 8;
int MAXIMIZED_SERP_NAVIGATION = 9;
int NUM_ENTRIES = 10;
}
// Exit code: first exit from MAXIMIZED.
@IntDef({ExitMaximizedTo.OTHER, ExitMaximizedTo.CLOSED_BACK_PRESS, ExitMaximizedTo.CLOSED_FLING,
ExitMaximizedTo.CLOSED_TAB_PROMOTION, ExitMaximizedTo.CLOSED_SERP_NAVIGATION,
ExitMaximizedTo.PEEKED_SWIPE, ExitMaximizedTo.PEEKED_FLING,
ExitMaximizedTo.EXPANDED_SWIPE, ExitMaximizedTo.EXPANDED_FLING})
@Retention(RetentionPolicy.SOURCE)
private @interface ExitMaximizedTo {
int OTHER = 0;
int CLOSED_BACK_PRESS = 1;
int CLOSED_FLING = 2;
int CLOSED_TAB_PROMOTION = 3;
int CLOSED_SERP_NAVIGATION = 4;
int PEEKED_SWIPE = 5;
int PEEKED_FLING = 6;
int EXPANDED_SWIPE = 7;
int EXPANDED_FLING = 8;
int NUM_ENTRIES = 9;
}
// Constants used to log UMA "enum" histograms with details about whether search results
// were seen, and what the original triggering gesture was.
@IntDef({ResultsByGesture.SEEN_FROM_TAP, ResultsByGesture.NOT_SEEN_FROM_TAP,
ResultsByGesture.SEEN_FROM_LONG_PRESS, ResultsByGesture.NOT_SEEN_FROM_LONG_PRESS})
@Retention(RetentionPolicy.SOURCE)
private @interface ResultsByGesture {
int SEEN_FROM_TAP = 0;
int NOT_SEEN_FROM_TAP = 1;
int SEEN_FROM_LONG_PRESS = 2;
int NOT_SEEN_FROM_LONG_PRESS = 3;
int NUM_ENTRIES = 4;
}
// Constants used to log UMA "enum" histograms with details about whether search results
// were seen, and whether any existing tap suppression heuristics were satisfied.
@IntDef({ResultsBySuppression.SEEN_SUPPRESSION_HEURSTIC_SATISFIED,
ResultsBySuppression.NOT_SEEN_SUPPRESSION_HEURSTIC_SATISFIED,
ResultsBySuppression.SEEN_SUPPRESSION_HEURSTIC_NOT_SATISFIED,
ResultsBySuppression.NOT_SEEN_SUPPRESSION_HEURSTIC_NOT_SATISFIED})
@Retention(RetentionPolicy.SOURCE)
private @interface ResultsBySuppression {
int SEEN_SUPPRESSION_HEURSTIC_SATISFIED = 0;
int NOT_SEEN_SUPPRESSION_HEURSTIC_SATISFIED = 1;
int SEEN_SUPPRESSION_HEURSTIC_NOT_SATISFIED = 2;
int NOT_SEEN_SUPPRESSION_HEURSTIC_NOT_SATISFIED = 3;
int NUM_ENTRIES = 4;
}
// Constants used to log UMA "enum" histograms with details about whether search results
// were seen, and what the original triggering gesture was.
@IntDef({Promo.ENABLED_FROM_TAP, Promo.DISABLED_FROM_TAP, Promo.UNDECIDED_FROM_TAP,
Promo.ENABLED_FROM_LONG_PRESS, Promo.DISABLED_FROM_LONG_PRESS,
Promo.UNDECIDED_FROM_LONG_PRESS})
@Retention(RetentionPolicy.SOURCE)
private @interface Promo {
int ENABLED_FROM_TAP = 0;
int DISABLED_FROM_TAP = 1;
int UNDECIDED_FROM_TAP = 2;
int ENABLED_FROM_LONG_PRESS = 3;
int DISABLED_FROM_LONG_PRESS = 4;
int UNDECIDED_FROM_LONG_PRESS = 5;
int NUM_ENTRIES = 6;
}
// Constants used to log UMA "enum" histograms for HTTP / HTTPS.
@IntDef({Protocol.IS_HTTP, Protocol.NOT_HTTP})
@Retention(RetentionPolicy.SOURCE)
private @interface Protocol {
int IS_HTTP = 0;
int NOT_HTTP = 1;
int NUM_ENTRIES = 2;
}
// Constants used to log UMA "enum" histograms for single / multi-word.
@IntDef({ResolvedGranularity.SINGLE_WORD, ResolvedGranularity.MULTI_WORD})
@Retention(RetentionPolicy.SOURCE)
private @interface ResolvedGranularity {
int SINGLE_WORD = 0;
int MULTI_WORD = 1;
int NUM_ENTRIES = 2;
}
// Constants used to log UMA "enum" histograms for triggering the Translate Onebox.
@IntDef({ForceTranslate.DID_FORCE, ForceTranslate.WOULD_FORCE})
@Retention(RetentionPolicy.SOURCE)
private @interface ForceTranslate {
int DID_FORCE = 0;
int WOULD_FORCE = 1;
int NUM_ENTRIES = 2;
}
// Constants used to log UMA "enum" histograms for Quick Answers.
@IntDef({QuickAnswerSeen.ACTIVATED_WAS_AN_ANSWER_SEEN,
QuickAnswerSeen.ACTIVATED_WAS_AN_ANSWER_NOT_SEEN,
QuickAnswerSeen.ACTIVATED_NOT_AN_ANSWER_SEEN,
QuickAnswerSeen.ACTIVATED_NOT_AN_ANSWER_NOT_SEEN, QuickAnswerSeen.NOT_ACTIVATED_SEEN,
QuickAnswerSeen.NOT_ACTIVATED_NOT_SEEN})
@Retention(RetentionPolicy.SOURCE)
private @interface QuickAnswerSeen {
int ACTIVATED_WAS_AN_ANSWER_SEEN = 0;
int ACTIVATED_WAS_AN_ANSWER_NOT_SEEN = 1;
int ACTIVATED_NOT_AN_ANSWER_SEEN = 2;
int ACTIVATED_NOT_AN_ANSWER_NOT_SEEN = 3;
int NOT_ACTIVATED_SEEN = 4;
int NOT_ACTIVATED_NOT_SEEN = 5;
int NUM_ENTRIES = 6;
}
// Constants for "Bar Overlap" with triggering gesture, and whether the results were seen.
@IntDef({BarOverlapResults.BAR_OVERLAP_RESULTS_SEEN_FROM_TAP,
BarOverlapResults.BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_TAP,
BarOverlapResults.NO_BAR_OVERLAP_RESULTS_SEEN_FROM_TAP,
BarOverlapResults.NO_BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_TAP,
BarOverlapResults.BAR_OVERLAP_RESULTS_SEEN_FROM_LONG_PRESS,
BarOverlapResults.BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_LONG_PRESS,
BarOverlapResults.NO_BAR_OVERLAP_RESULTS_SEEN_FROM_LONG_PRESS,
BarOverlapResults.NO_BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_LONG_PRESS})
@Retention(RetentionPolicy.SOURCE)
private @interface BarOverlapResults {
int BAR_OVERLAP_RESULTS_SEEN_FROM_TAP = 0;
int BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_TAP = 1;
int NO_BAR_OVERLAP_RESULTS_SEEN_FROM_TAP = 2;
int NO_BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_TAP = 3;
int BAR_OVERLAP_RESULTS_SEEN_FROM_LONG_PRESS = 4;
int BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_LONG_PRESS = 5;
int NO_BAR_OVERLAP_RESULTS_SEEN_FROM_LONG_PRESS = 6;
int NO_BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_LONG_PRESS = 7;
int NUM_ENTRIES = 8;
}
// Constants for quick action intent resolution histogram.
@IntDef({QuickActionResolve.FAILED, QuickActionResolve.SINGLE, QuickActionResolve.MULTIPLE})
@Retention(RetentionPolicy.SOURCE)
private @interface QuickActionResolve {
int FAILED = 0;
int SINGLE = 1;
int MULTIPLE = 2;
int NUM_ENTRIES = 3;
}
/**
* Key used in maps from {state, reason} to state entry (exit) logging code.
*/
static class StateChangeKey {
final @PanelState int mState;
final @StateChangeReason int mReason;
final int mHashCode;
StateChangeKey(@PanelState int state, @StateChangeReason int reason) {
mState = state;
mReason = reason;
mHashCode = 31 * state + reason;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof StateChangeKey)) return false;
if (obj == this) return true;
StateChangeKey other = (StateChangeKey) obj;
return mState == other.mState && mReason == other.mReason;
}
@Override
public int hashCode() {
return mHashCode;
}
}
// TODO(donnd): switch from using Maps to some method that does not require creation of a key.
// Entry code map: first entry into CLOSED.
private static final Map<StateChangeKey, Integer> ENTER_CLOSED_STATE_CHANGE_CODES;
static {
Map<StateChangeKey, Integer> codes = new HashMap<StateChangeKey, Integer>();
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.BACK_PRESS),
EnterClosedFrom.PEEKED_BACK_PRESS);
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.BASE_PAGE_SCROLL),
EnterClosedFrom.PEEKED_BASE_PAGE_SCROLL);
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.TEXT_SELECT_TAP),
EnterClosedFrom.PEEKED_TEXT_SELECT_TAP);
codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.BACK_PRESS),
EnterClosedFrom.EXPANDED_BACK_PRESS);
codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.BASE_PAGE_TAP),
EnterClosedFrom.EXPANDED_BASE_PAGE_TAP);
codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.FLING),
EnterClosedFrom.EXPANDED_FLING);
codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.BACK_PRESS),
EnterClosedFrom.MAXIMIZED_BACK_PRESS);
codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.FLING),
EnterClosedFrom.MAXIMIZED_FLING);
codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.TAB_PROMOTION),
EnterClosedFrom.MAXIMIZED_TAB_PROMOTION);
codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.SERP_NAVIGATION),
EnterClosedFrom.MAXIMIZED_SERP_NAVIGATION);
ENTER_CLOSED_STATE_CHANGE_CODES = Collections.unmodifiableMap(codes);
}
// Entry code map: first entry into PEEKED.
private static final Map<StateChangeKey, Integer> ENTER_PEEKED_STATE_CHANGE_CODES;
static {
Map<StateChangeKey, Integer> codes = new HashMap<StateChangeKey, Integer>();
// Note: we don't distinguish entering PEEKED from UNDEFINED / CLOSED.
codes.put(new StateChangeKey(PanelState.UNDEFINED, StateChangeReason.TEXT_SELECT_TAP),
EnterPeekedFrom.CLOSED_TEXT_SELECT_TAP);
codes.put(
new StateChangeKey(PanelState.UNDEFINED, StateChangeReason.TEXT_SELECT_LONG_PRESS),
EnterPeekedFrom.CLOSED_EXT_SELECT_LONG_PRESS);
codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.TEXT_SELECT_TAP),
EnterPeekedFrom.CLOSED_TEXT_SELECT_TAP);
codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.TEXT_SELECT_LONG_PRESS),
EnterPeekedFrom.CLOSED_EXT_SELECT_LONG_PRESS);
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.TEXT_SELECT_TAP),
EnterPeekedFrom.PEEKED_TEXT_SELECT_TAP);
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.TEXT_SELECT_LONG_PRESS),
EnterPeekedFrom.PEEKED_TEXT_SELECT_LONG_PRESS);
codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.SEARCH_BAR_TAP),
EnterPeekedFrom.EXPANDED_SEARCH_BAR_TAP);
codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.SWIPE),
EnterPeekedFrom.EXPANDED_SWIPE);
codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.FLING),
EnterPeekedFrom.EXPANDED_FLING);
codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.SWIPE),
EnterPeekedFrom.MAXIMIZED_SWIPE);
codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.FLING),
EnterPeekedFrom.MAXIMIZED_FLING);
ENTER_PEEKED_STATE_CHANGE_CODES = Collections.unmodifiableMap(codes);
}
// Entry code map: first entry into EXPANDED.
private static final Map<StateChangeKey, Integer> ENTER_EXPANDED_STATE_CHANGE_CODES;
static {
Map<StateChangeKey, Integer> codes = new HashMap<StateChangeKey, Integer>();
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.SEARCH_BAR_TAP),
EnterExpandedFrom.PEEKED_SEARCH_BAR_TAP);
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.SWIPE),
EnterExpandedFrom.PEEKED_SWIPE);
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.FLING),
EnterExpandedFrom.PEEKED_FLING);
codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.SWIPE),
EnterExpandedFrom.MAXIMIZED_SWIPE);
codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.FLING),
EnterExpandedFrom.MAXIMIZED_FLING);
ENTER_EXPANDED_STATE_CHANGE_CODES = Collections.unmodifiableMap(codes);
}
// Entry code map: first entry into MAXIMIZED.
private static final Map<StateChangeKey, Integer> ENTER_MAXIMIZED_STATE_CHANGE_CODES;
static {
Map<StateChangeKey, Integer> codes = new HashMap<StateChangeKey, Integer>();
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.SWIPE),
EnterMaximizedFrom.PEEKED_SWIPE);
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.FLING),
EnterMaximizedFrom.PEEKED_FLING);
codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.SWIPE),
EnterMaximizedFrom.EXPANDED_SWIPE);
codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.FLING),
EnterMaximizedFrom.EXPANDED_FLING);
codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.SERP_NAVIGATION),
EnterMaximizedFrom.EXPANDED_SERP_NAVIGATION);
ENTER_MAXIMIZED_STATE_CHANGE_CODES = Collections.unmodifiableMap(codes);
}
// Exit code map: first exit from CLOSED.
private static final Map<StateChangeKey, Integer> EXIT_CLOSED_TO_STATE_CHANGE_CODES;
static {
Map<StateChangeKey, Integer> codes = new HashMap<StateChangeKey, Integer>();
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.TEXT_SELECT_TAP),
ExitClosedTo.PEEKED_TEXT_SELECT_TAP);
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.TEXT_SELECT_LONG_PRESS),
ExitClosedTo.PEEKED_TEXT_SELECT_LONG_PRESS);
EXIT_CLOSED_TO_STATE_CHANGE_CODES = Collections.unmodifiableMap(codes);
}
// Exit code map: first exit from PEEKED.
private static final Map<StateChangeKey, Integer> EXIT_PEEKED_TO_STATE_CHANGE_CODES;
static {
Map<StateChangeKey, Integer> codes = new HashMap<StateChangeKey, Integer>();
codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.BACK_PRESS),
ExitPeekedTo.CLOSED_BACK_PRESS);
codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.BASE_PAGE_SCROLL),
ExitPeekedTo.CLOSED_BASE_PAGE_SCROLL);
codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.BASE_PAGE_TAP),
ExitPeekedTo.CLOSED_TEXT_SELECT_TAP);
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.TEXT_SELECT_TAP),
ExitPeekedTo.PEEKED_TEXT_SELECT_TAP);
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.TEXT_SELECT_LONG_PRESS),
ExitPeekedTo.PEEKED_TEXT_SELECT_LONG_PRESS);
codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.SEARCH_BAR_TAP),
ExitPeekedTo.EXPANDED_SEARCH_BAR_TAP);
codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.SWIPE),
ExitPeekedTo.EXPANDED_SWIPE);
codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.FLING),
ExitPeekedTo.EXPANDED_FLING);
codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.SWIPE),
ExitPeekedTo.MAXIMIZED_SWIPE);
codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.FLING),
ExitPeekedTo.MAXIMIZED_FLING);
EXIT_PEEKED_TO_STATE_CHANGE_CODES = Collections.unmodifiableMap(codes);
}
// Exit code map: first exit from EXPANDED.
private static final Map<StateChangeKey, Integer> EXIT_EXPANDED_TO_STATE_CHANGE_CODES;
static {
Map<StateChangeKey, Integer> codes = new HashMap<StateChangeKey, Integer>();
codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.BACK_PRESS),
ExitExpandedTo.CLOSED_BACK_PRESS);
codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.BASE_PAGE_TAP),
ExitExpandedTo.CLOSED_BASE_PAGE_TAP);
codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.FLING),
ExitExpandedTo.CLOSED_FLING);
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.SEARCH_BAR_TAP),
ExitExpandedTo.PEEKED_SEARCH_BAR_TAP);
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.SWIPE),
ExitExpandedTo.PEEKED_SWIPE);
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.FLING),
ExitExpandedTo.PEEKED_FLING);
codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.SWIPE),
ExitExpandedTo.MAXIMIZED_SWIPE);
codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.FLING),
ExitExpandedTo.MAXIMIZED_FLING);
codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.SERP_NAVIGATION),
ExitExpandedTo.MAXIMIZED_SERP_NAVIGATION);
EXIT_EXPANDED_TO_STATE_CHANGE_CODES = Collections.unmodifiableMap(codes);
}
// Exit code map: first exit from MAXIMIZED.
private static final Map<StateChangeKey, Integer> EXIT_MAXIMIZED_TO_STATE_CHANGE_CODES;
static {
Map<StateChangeKey, Integer> codes = new HashMap<StateChangeKey, Integer>();
codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.BACK_PRESS),
ExitMaximizedTo.CLOSED_BACK_PRESS);
codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.FLING),
ExitMaximizedTo.CLOSED_FLING);
codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.TAB_PROMOTION),
ExitMaximizedTo.CLOSED_TAB_PROMOTION);
codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.SERP_NAVIGATION),
ExitMaximizedTo.CLOSED_SERP_NAVIGATION);
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.SWIPE),
ExitMaximizedTo.PEEKED_SWIPE);
codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.FLING),
ExitMaximizedTo.PEEKED_FLING);
codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.SWIPE),
ExitMaximizedTo.EXPANDED_SWIPE);
codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.FLING),
ExitMaximizedTo.EXPANDED_FLING);
EXIT_MAXIMIZED_TO_STATE_CHANGE_CODES = Collections.unmodifiableMap(codes);
}
// "Seen by gesture" code map: logged on first exit from expanded panel, or promo,
// broken down by gesture.
private static final Map<Pair<Boolean, Boolean>, Integer> SEEN_BY_GESTURE_CODES;
static {
final boolean unseen = false;
final boolean seen = true;
Map<Pair<Boolean, Boolean>, Integer> codes = new HashMap<Pair<Boolean, Boolean>, Integer>();
codes.put(new Pair<Boolean, Boolean>(seen, TAP), ResultsByGesture.SEEN_FROM_TAP);
codes.put(new Pair<Boolean, Boolean>(unseen, TAP), ResultsByGesture.NOT_SEEN_FROM_TAP);
codes.put(new Pair<Boolean, Boolean>(seen, LONG_PRESS),
ResultsByGesture.SEEN_FROM_LONG_PRESS);
codes.put(new Pair<Boolean, Boolean>(unseen, LONG_PRESS),
ResultsByGesture.NOT_SEEN_FROM_LONG_PRESS);
SEEN_BY_GESTURE_CODES = Collections.unmodifiableMap(codes);
}
// "Promo outcome by gesture" code map: logged on exit from promo, broken down by gesture.
private static final Map<Pair<Integer, Boolean>, Integer> PROMO_BY_GESTURE_CODES;
static {
Map<Pair<Integer, Boolean>, Integer> codes =
new HashMap<Pair<Integer, Boolean>, Integer>();
codes.put(new Pair<Integer, Boolean>(Preference.ENABLED, TAP), Promo.ENABLED_FROM_TAP);
codes.put(new Pair<Integer, Boolean>(Preference.DISABLED, TAP), Promo.DISABLED_FROM_TAP);
codes.put(new Pair<Integer, Boolean>(Preference.UNINITIALIZED, TAP),
Promo.UNDECIDED_FROM_TAP);
codes.put(new Pair<Integer, Boolean>(Preference.ENABLED, LONG_PRESS),
Promo.ENABLED_FROM_LONG_PRESS);
codes.put(new Pair<Integer, Boolean>(Preference.DISABLED, LONG_PRESS),
Promo.DISABLED_FROM_LONG_PRESS);
codes.put(new Pair<Integer, Boolean>(Preference.UNINITIALIZED, LONG_PRESS),
Promo.UNDECIDED_FROM_LONG_PRESS);
PROMO_BY_GESTURE_CODES = Collections.unmodifiableMap(codes);
}
/**
* Logs the state of the Contextual Search preference. This function should be called if the
* Contextual Search feature is active, and will track the different preference settings
* (disabled, enabled or uninitialized). Calling more than once is fine.
*/
public static void logPreferenceState() {
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchPreferenceState",
getPreferenceValue(), Preference.NUM_ENTRIES);
}
/**
* Logs the given number of promo taps remaining. Should be called only for users that
* are still undecided.
* @param promoTapsRemaining The number of taps remaining (should not be negative).
*/
public static void logPromoTapsRemaining(int promoTapsRemaining) {
if (promoTapsRemaining >= 0) {
RecordHistogram.recordCountHistogram("Search.ContextualSearchPromoTapsRemaining",
promoTapsRemaining);
}
}
/**
* Logs the historic number of times that a Tap gesture triggered the peeking promo
* for users that have never opened the panel. This should be called periodically for
* undecided users only.
* @param promoTaps The historic number of taps that have caused the peeking bar for the promo,
* for users that have never opened the panel.
*/
public static void logPromoTapsForNeverOpened(int promoTaps) {
RecordHistogram.recordCountHistogram("Search.ContextualSearchPromoTapsForNeverOpened",
promoTaps);
}
/**
* Logs the historic number of times that a Tap gesture triggered the peeking promo before
* the user ever opened the panel. This should be called periodically for all users.
* @param promoTaps The historic number of taps that have caused the peeking bar for the promo
* before the first open of the panel, for all users that have ever opened the panel.
*/
public static void logPromoTapsBeforeFirstOpen(int promoTaps) {
RecordHistogram.recordCountHistogram("Search.ContextualSearchPromoTapsBeforeFirstOpen",
promoTaps);
}
/**
* Records the total count of times the promo panel has *ever* been opened. This should only
* be called when the user is still undecided.
* @param count The total historic count of times the panel has ever been opened for the
* current user.
*/
public static void logPromoOpenCount(int count) {
RecordHistogram.recordCountHistogram("Search.ContextualSearchPromoOpenCount", count);
}
/**
* Logs the number of taps that have been counted since the user last opened the panel, for
* undecided users.
* @param tapsSinceOpen The number of taps to log.
*/
public static void logTapsSinceOpenForUndecided(int tapsSinceOpen) {
RecordHistogram.recordCountHistogram("Search.ContextualSearchTapsSinceOpenUndecided",
tapsSinceOpen);
}
/**
* Logs the number of taps that have been counted since the user last opened the panel, for
* decided users.
* @param tapsSinceOpen The number of taps to log.
*/
public static void logTapsSinceOpenForDecided(int tapsSinceOpen) {
RecordHistogram.recordCountHistogram("Search.ContextualSearchTapsSinceOpenDecided",
tapsSinceOpen);
}
/**
* Logs whether the Search Term was single or multiword.
* @param isSingleWord Whether the resolved search term is a single word or not.
*/
public static void logSearchTermResolvedWords(boolean isSingleWord) {
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchResolvedTermWords",
isSingleWord ? ResolvedGranularity.SINGLE_WORD : ResolvedGranularity.MULTI_WORD,
ResolvedGranularity.NUM_ENTRIES);
}
/**
* Logs whether the base page was using the HTTP protocol or not.
* @param isHttpBasePage Whether the base page was using the HTTP protocol or not (should
* be false for HTTPS or other URIs).
*/
public static void logBasePageProtocol(boolean isHttpBasePage) {
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchBasePageProtocol",
isHttpBasePage ? Protocol.IS_HTTP : Protocol.NOT_HTTP, Protocol.NUM_ENTRIES);
}
/**
* Logs changes to the Contextual Search preference, aside from those resulting from the first
* run flow.
* @param enabled Whether the preference is being enabled or disabled.
*/
public static void logPreferenceChange(boolean enabled) {
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchPreferenceStateChange",
enabled ? Preference.ENABLED : Preference.DISABLED, Preference.NUM_ENTRIES);
}
/**
* Logs the outcome of the Promo.
* Logs multiple histograms; with and without the originating gesture.
* @param wasTap Whether the gesture that originally caused the panel to show was a Tap.
* @param wasMandatory Whether the Promo was mandatory.
*/
public static void logPromoOutcome(boolean wasTap, boolean wasMandatory) {
int preferenceCode = getPreferenceValue();
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchFirstRunFlowOutcome",
preferenceCode, Preference.NUM_ENTRIES);
int preferenceByGestureCode = getPromoByGestureStateCode(preferenceCode, wasTap);
if (wasMandatory) {
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchMandatoryPromoOutcomeByGesture",
preferenceByGestureCode, Promo.NUM_ENTRIES);
} else {
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchPromoOutcomeByGesture", preferenceByGestureCode,
Promo.NUM_ENTRIES);
}
}
/**
* Logs the duration of a Contextual Search panel being viewed by the user.
* @param wereResultsSeen Whether search results were seen.
* @param isChained Whether the Contextual Search ended with the start of another.
* @param durationMs The duration of the contextual search in milliseconds.
*/
public static void logDuration(boolean wereResultsSeen, boolean isChained, long durationMs) {
if (wereResultsSeen) {
RecordHistogram.recordTimesHistogram("Search.ContextualSearchDurationSeen", durationMs);
} else if (isChained) {
RecordHistogram.recordTimesHistogram(
"Search.ContextualSearchDurationUnseenChained", durationMs);
} else {
RecordHistogram.recordTimesHistogram(
"Search.ContextualSearchDurationUnseen", durationMs);
}
}
/**
* Logs the duration from starting a search until the Search Term is resolved.
* @param durationMs The duration to record.
*/
public static void logSearchTermResolutionDuration(long durationMs) {
RecordHistogram.recordMediumTimesHistogram(
"Search.ContextualSearchResolutionDuration", durationMs);
}
/**
* Logs the duration from starting a prefetched search until the panel navigates to the results
* and they start becoming viewable. Should be called only for searches that are prefetched.
* @param durationMs The duration to record.
* @param didResolve Whether a Search Term resolution was required as part of the loading.
*/
public static void logPrefetchedSearchNavigatedDuration(long durationMs, boolean didResolve) {
String histogramName = didResolve ? "Search.ContextualSearchResolvedSearchDuration"
: "Search.ContextualSearchLiteralSearchDuration";
RecordHistogram.recordMediumTimesHistogram(histogramName, durationMs);
}
/**
* Logs the duration from opening the panel beyond peek until the panel is closed.
* @param durationMs The duration to record.
*/
public static void logPanelOpenDuration(long durationMs) {
RecordHistogram.recordMediumTimesHistogram(
"Search.ContextualSearchPanelOpenDuration", durationMs);
}
/**
* When Contextual Search panel is opened, logs whether In-Product Help for opening the panel
* was ever shown.
* @param wasIPHShown Whether In-Product help was shown.
*/
public static void logPanelOpenedIPH(boolean wasIPHShown) {
RecordHistogram.recordBooleanHistogram(
"Search.ContextualSearchPanelOpenedIPHShown", wasIPHShown);
}
/**
* When Contextual Search panel is opened, logs whether In-Product Help for Contextual Search
* was ever shown.
* @param wasIPHShown Whether In-Product help was shown.
*/
public static void logContextualSearchIPH(boolean wasIPHShown) {
RecordHistogram.recordBooleanHistogram("Search.ContextualSearchIPHShown", wasIPHShown);
}
/**
* When Contextual Search is triggered by tapping, logs whether In-Product Help for tapping was
* ever shown.
* @param wasIPHShown Whether In-Product help was shown.
*/
public static void logTapIPH(boolean wasIPHShown) {
RecordHistogram.recordBooleanHistogram("Search.ContextualSearchTapIPHShown", wasIPHShown);
}
/**
* Logs a user action for the duration of viewing the panel that describes the amount of time
* the user viewed the bar and panel overall.
* @param durationMs The duration to record.
*/
public static void logPanelViewDurationAction(long durationMs) {
if (durationMs < DateUtils.SECOND_IN_MILLIS) {
RecordUserAction.record("ContextualSearch.ViewLessThanOneSecond");
} else if (durationMs < DateUtils.SECOND_IN_MILLIS * 3) {
RecordUserAction.record("ContextualSearch.ViewOneToThreeSeconds");
} else if (durationMs < DateUtils.SECOND_IN_MILLIS * 10) {
RecordUserAction.record("ContextualSearch.ViewThreeToTenSeconds");
} else {
RecordUserAction.record("ContextualSearch.ViewMoreThanTenSeconds");
}
}
/**
* Logs whether the promo was seen.
* Logs multiple histograms, with and without the original triggering gesture.
* @param wasPanelSeen Whether the panel was seen.
* @param wasTap Whether the gesture that originally caused the panel to show was a Tap.
*/
public static void logPromoSeen(boolean wasPanelSeen, boolean wasTap) {
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchFirstRunPanelSeen",
wasPanelSeen ? Results.SEEN : Results.NOT_SEEN, Results.NUM_ENTRIES);
logHistogramByGesture(wasPanelSeen, wasTap, "Search.ContextualSearchPromoSeenByGesture");
}
/**
* Logs whether search results were seen.
* Logs multiple histograms; with and without the original triggering gesture.
* @param wasPanelSeen Whether the panel was seen.
* @param wasTap Whether the gesture that originally caused the panel to show was a Tap.
*/
public static void logResultsSeen(boolean wasPanelSeen, boolean wasTap) {
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchResultsSeen",
wasPanelSeen ? Results.SEEN : Results.NOT_SEEN, Results.NUM_ENTRIES);
logHistogramByGesture(wasPanelSeen, wasTap, "Search.ContextualSearchResultsSeenByGesture");
}
/**
* Logs whether search results were seen for a Tap gesture, for all users and sync-enabled
* users. For sync-enabled users we log to a separate histogram for that sub-population in order
* to help validate the Ranker Tap Suppression model results (since they are trained on UKM data
* which approximately reflects this sync-enabled population).
* @param wasPanelSeen Whether the panel was seen.
*/
public static void logTapResultsSeen(boolean wasPanelSeen) {
RecordHistogram.recordBooleanHistogram(
"Search.ContextualSearch.Tap.ResultsSeen", wasPanelSeen);
if (AndroidSyncSettings.get().isSyncEnabled()) {
RecordHistogram.recordBooleanHistogram(
"Search.ContextualSearch.Tap.SyncEnabled.ResultsSeen", wasPanelSeen);
}
}
/**
* Logs whether search results were seen for all gestures. Recorded for all users.
* @param wasPanelSeen Whether the panel was seen.
*/
public static void logAllResultsSeen(boolean wasPanelSeen) {
RecordHistogram.recordBooleanHistogram(
"Search.ContextualSearch.All.ResultsSeen", wasPanelSeen);
}
/**
* Logs the whether the panel was seen and the type of the trigger and if Bar nearly overlapped.
* If the panel was seen, logs the duration of the panel view into a BarOverlap or BarNoOverlap
* duration histogram.
* @param wasPanelSeen Whether the panel was seen.
* @param wasTap Whether the gesture was a Tap or not.
* @param wasBarOverlap Whether the trigger location overlapped the Bar area.
*/
public static void logBarOverlapResultsSeen(
boolean wasPanelSeen, boolean wasTap, boolean wasBarOverlap) {
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchBarOverlapSeen",
getBarOverlapEnum(wasBarOverlap, wasPanelSeen, wasTap),
BarOverlapResults.NUM_ENTRIES);
}
/**
* Logs the duration of the panel viewed in its Peeked state before being opened.
* @param wasBarOverlap Whether the trigger location overlapped the Bar area.
* @param panelPeekDurationMs The duration that the panel was peeking before being opened
* by the user.
*/
public static void logBarOverlapPeekDuration(boolean wasBarOverlap, long panelPeekDurationMs) {
String histogram = wasBarOverlap ? "Search.ContextualSearchBarOverlap.PeekDuration"
: "Search.ContextualSearchBarNoOverlap.PeekDuration";
RecordHistogram.recordMediumTimesHistogram(histogram, panelPeekDurationMs);
}
/**
* Log whether the UX was suppressed due to Bar overlap.
* @param wasSuppressed Whether showing the UX was suppressed.
*/
public static void logBarOverlapSuppression(boolean wasSuppressed) {
RecordHistogram.recordBooleanHistogram("Search.ContextualSearchBarOverlap", wasSuppressed);
}
/**
* Logs the length of the selection in two histograms, one when results were seen and one when
* results were not seen.
* @param wasPanelSeen Whether the panel was seen.
* @param selectionLength The length of the triggering selection.
*/
public static void logSelectionLengthResultsSeen(boolean wasPanelSeen, int selectionLength) {
if (wasPanelSeen) {
RecordHistogram.recordSparseHistogram(
"Search.ContextualSearchSelectionLengthSeen", selectionLength);
} else {
RecordHistogram.recordSparseHistogram(
"Search.ContextualSearchSelectionLengthNotSeen", selectionLength);
}
}
/**
* Log whether the UX was suppressed due to the selection length.
* @param wasSuppressed Whether showing the UX was suppressed due to selection length.
*/
public static void logSelectionLengthSuppression(boolean wasSuppressed) {
RecordHistogram.recordBooleanHistogram(
"Search.ContextualSearchSelectionLengthSuppression", wasSuppressed);
}
/**
* Logs the location of a Tap and whether the panel was seen and the type of the
* trigger.
* @param wasPanelSeen Whether the panel was seen.
* @param wasTap Whether the gesture was a Tap or not.
* @param triggerLocationDps The trigger location from the top of the screen.
*/
public static void logScreenTopTapLocation(
boolean wasPanelSeen, boolean wasTap, int triggerLocationDps) {
// We only log Tap locations for the screen top.
if (!wasTap) return;
String histogram = wasPanelSeen ? "Search.ContextualSearchTopLocationSeen"
: "Search.ContextualSearchTopLocationNotSeen";
int min = 1;
int max = 250;
int numBuckets = 50;
RecordHistogram.recordCustomCountHistogram(
histogram, triggerLocationDps, min, max, numBuckets);
}
/**
* Log whether the UX was suppressed due to a Tap too close to the screen top.
* @param wasSuppressed Whether showing the UX was suppressed.
*/
public static void logScreenTopTapSuppression(boolean wasSuppressed) {
RecordHistogram.recordBooleanHistogram(
"Search.ContextualSearchScreenTopSuppressed", wasSuppressed);
}
/**
* Log whether results were seen due to a Tap that was allowed to override an ML suppression.
* @param wasSearchContentViewSeen If the panel was opened.
*/
static void logSecondTapMlOverrideResultsSeen(boolean wasSearchContentViewSeen) {
RecordHistogram.recordBooleanHistogram(
"Search.ContextualSearchSecondTapMlOverrideSeen", wasSearchContentViewSeen);
}
/**
* Logs whether results were seen based on the duration of the Tap, for both short and long
* durations.
* @param wasSearchContentViewSeen If the panel was opened.
* @param isTapShort Whether this tap was "short" in duration.
*/
public static void logTapDurationSeen(boolean wasSearchContentViewSeen, boolean isTapShort) {
if (isTapShort) {
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchTapShortDurationSeen",
wasSearchContentViewSeen ? Results.SEEN : Results.NOT_SEEN,
Results.NUM_ENTRIES);
} else {
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchTapLongDurationSeen",
wasSearchContentViewSeen ? Results.SEEN : Results.NOT_SEEN,
Results.NUM_ENTRIES);
}
}
/**
* Logs the duration of a Tap in ms into custom histograms to profile the duration of seen
* and not seen taps.
* @param wasPanelSeen Whether the panel was seen.
* @param durationMs The duration of the tap gesture.
*/
public static void logTapDuration(boolean wasPanelSeen, int durationMs) {
int min = 1;
int max = 1000;
int numBuckets = 100;
if (wasPanelSeen) {
RecordHistogram.recordCustomCountHistogram(
"Search.ContextualSearchTapDurationSeen", durationMs, min, max, numBuckets);
} else {
RecordHistogram.recordCustomCountHistogram(
"Search.ContextualSearchTapDurationNotSeen", durationMs, min, max, numBuckets);
}
}
/**
* 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.NUM_ENTRIES);
}
/**
* 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.NUM_ENTRIES);
}
/**
* 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.NUM_ENTRIES);
}
/**
* Log whether results were seen due to a Tap on what we've recognized as a probable entity.
* @param wasSearchContentViewSeen If the panel was opened.
* @param isWordAnEntity Whether this tap was on a word that's an entity.
*/
public static void logTapOnEntitySeen(
boolean wasSearchContentViewSeen, boolean isWordAnEntity) {
if (isWordAnEntity) {
// We just record CTR of probable entity words.
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchEntitySeen",
wasSearchContentViewSeen ? Results.SEEN : Results.NOT_SEEN,
Results.NUM_ENTRIES);
}
}
/**
* Logs whether results were seen and whether any tap suppression heuristics were satisfied.
* @param wasSearchContentViewSeen If the panel was opened.
* @param wasAnySuppressionHeuristicSatisfied Whether any of the implemented suppression
* heuristics were satisfied.
*/
public static void logAnyTapSuppressionHeuristicSatisfied(boolean wasSearchContentViewSeen,
boolean wasAnySuppressionHeuristicSatisfied) {
int code;
if (wasAnySuppressionHeuristicSatisfied) {
code = wasSearchContentViewSeen
? ResultsBySuppression.SEEN_SUPPRESSION_HEURSTIC_SATISFIED
: ResultsBySuppression.NOT_SEEN_SUPPRESSION_HEURSTIC_SATISFIED;
} else {
code = wasSearchContentViewSeen
? ResultsBySuppression.SEEN_SUPPRESSION_HEURSTIC_NOT_SATISFIED
: ResultsBySuppression.NOT_SEEN_SUPPRESSION_HEURSTIC_NOT_SATISFIED;
}
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchTapSuppressionSeen.AnyHeuristicSatisfied", code,
ResultsBySuppression.NUM_ENTRIES);
}
/**
* Logs whether a selection is valid.
* @param isSelectionValid Whether the selection is valid.
*/
public static void logSelectionIsValid(boolean isSelectionValid) {
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchSelectionValid",
isSelectionValid ? Selection.VALID : Selection.INVALID, Selection.NUM_ENTRIES);
}
/**
* Logs whether a normal priority search request failed.
* @param isFailure Whether the request failed.
*/
public static void logNormalPrioritySearchRequestOutcome(boolean isFailure) {
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchNormalPrioritySearchRequestStatus",
isFailure ? Request.FAILED : Request.NOT_FAILED, Request.NUM_ENTRIES);
}
/**
* Logs whether a low priority search request failed.
* @param isFailure Whether the request failed.
*/
public static void logLowPrioritySearchRequestOutcome(boolean isFailure) {
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchLowPrioritySearchRequestStatus",
isFailure ? Request.FAILED : Request.NOT_FAILED, Request.NUM_ENTRIES);
}
/**
* Logs whether a fallback search request failed.
* @param isFailure Whether the request failed.
*/
public static void logFallbackSearchRequestOutcome(boolean isFailure) {
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchFallbackSearchRequestStatus",
isFailure ? Request.FAILED : Request.NOT_FAILED, Request.NUM_ENTRIES);
}
/**
* Log whether the UX was suppressed by a recent scroll.
* @param wasSuppressed Whether showing the UX was suppressed by a recent scroll.
*/
public static void logRecentScrollSuppression(boolean wasSuppressed) {
RecordHistogram.recordBooleanHistogram(
"Search.ContextualSearchRecentScrollSuppression", wasSuppressed);
}
/**
* Logs the duration between the panel being triggered due to a tap and the panel being
* dismissed due to a scroll.
* @param durationSincePanelTriggerMs The amount of time between the panel getting triggered and
* the panel being dismissed due to a scroll.
* @param wasSearchContentViewSeen If the panel was opened.
*/
public static void logDurationBetweenTriggerAndScroll(
long durationSincePanelTriggerMs, boolean wasSearchContentViewSeen) {
String histogram = wasSearchContentViewSeen
? "Search.ContextualSearchDurationBetweenTriggerAndScrollSeen"
: "Search.ContextualSearchDurationBetweenTriggerAndScrollNotSeen";
if (durationSincePanelTriggerMs < 2000) {
RecordHistogram.recordCustomCountHistogram(
histogram, (int) durationSincePanelTriggerMs, 1, 2000, 200);
}
}
/**
* Logs whether a Quick Answer caption was activated, and whether it was an answer (as opposed
* to just being informative), and whether the panel was opened anyway.
* Logged only for Tap events.
* @param didActivate If the Quick Answer caption was shown.
* @param didAnswer If the caption was considered an answer (reducing the need to open the
* panel).
* @param wasSearchContentViewSeen If the panel was opened.
*/
static void logQuickAnswerSeen(
boolean wasSearchContentViewSeen, boolean didActivate, boolean didAnswer) {
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchQuickAnswerSeen",
getQuickAnswerSeenValue(didActivate, didAnswer, wasSearchContentViewSeen),
QuickAnswerSeen.NUM_ENTRIES);
}
/**
* Logs how a state was entered for the first time within a Contextual Search.
* @param fromState The state to transition from.
* @param toState The state to transition to.
* @param reason The reason for the state transition.
*/
public static void logFirstStateEntry(
@PanelState int fromState, @PanelState int toState, @StateChangeReason int reason) {
int code;
switch (toState) {
case PanelState.CLOSED:
code = getStateChangeCode(
fromState, reason, ENTER_CLOSED_STATE_CHANGE_CODES, EnterClosedFrom.OTHER);
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchEnterClosed", code, EnterClosedFrom.NUM_ENTRIES);
break;
case PanelState.PEEKED:
code = getStateChangeCode(
fromState, reason, ENTER_PEEKED_STATE_CHANGE_CODES, EnterPeekedFrom.OTHER);
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchEnterPeeked", code, EnterPeekedFrom.NUM_ENTRIES);
break;
case PanelState.EXPANDED:
code = getStateChangeCode(fromState, reason, ENTER_EXPANDED_STATE_CHANGE_CODES,
EnterExpandedFrom.OTHER);
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchEnterExpanded",
code, EnterExpandedFrom.NUM_ENTRIES);
break;
case PanelState.MAXIMIZED:
code = getStateChangeCode(fromState, reason, ENTER_MAXIMIZED_STATE_CHANGE_CODES,
EnterMaximizedFrom.OTHER);
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchEnterMaximized",
code, EnterMaximizedFrom.NUM_ENTRIES);
break;
default:
break;
}
}
/**
* Logs a user action for a change to the Panel state, which allows sequencing of actions.
* @param toState The state to transition to.
* @param reason The reason for the state transition.
*/
public static void logPanelStateUserAction(
@PanelState int toState, @StateChangeReason int reason) {
switch (toState) {
case PanelState.CLOSED:
if (reason == StateChangeReason.BACK_PRESS) {
RecordUserAction.record("ContextualSearch.BackPressClose");
} else if (reason == StateChangeReason.CLOSE_BUTTON) {
RecordUserAction.record("ContextualSearch.CloseButtonClose");
} else if (reason == StateChangeReason.SWIPE || reason == StateChangeReason.FLING) {
RecordUserAction.record("ContextualSearch.SwipeOrFlingClose");
} else if (reason == StateChangeReason.TAB_PROMOTION) {
RecordUserAction.record("ContextualSearch.TabPromotionClose");
} else if (reason == StateChangeReason.BASE_PAGE_TAP) {
RecordUserAction.record("ContextualSearch.BasePageTapClose");
} else if (reason == StateChangeReason.BASE_PAGE_SCROLL) {
RecordUserAction.record("ContextualSearch.BasePageScrollClose");
} else if (reason == StateChangeReason.SEARCH_BAR_TAP) {
RecordUserAction.record("ContextualSearch.SearchBarTapClose");
} else if (reason == StateChangeReason.SERP_NAVIGATION) {
RecordUserAction.record("ContextualSearch.NavigationClose");
} else {
RecordUserAction.record("ContextualSearch.UncommonClose");
}
break;
case PanelState.PEEKED:
if (reason == StateChangeReason.TEXT_SELECT_TAP) {
RecordUserAction.record("ContextualSearch.TapPeek");
} else if (reason == StateChangeReason.SWIPE || reason == StateChangeReason.FLING) {
RecordUserAction.record("ContextualSearch.SwipeOrFlingPeek");
} else if (reason == StateChangeReason.TEXT_SELECT_LONG_PRESS) {
RecordUserAction.record("ContextualSearch.LongpressPeek");
}
break;
case PanelState.EXPANDED:
if (reason == StateChangeReason.SWIPE || reason == StateChangeReason.FLING) {
RecordUserAction.record("ContextualSearch.SwipeOrFlingExpand");
} else if (reason == StateChangeReason.SEARCH_BAR_TAP) {
RecordUserAction.record("ContextualSearch.SearchBarTapExpand");
}
break;
case PanelState.MAXIMIZED:
if (reason == StateChangeReason.SWIPE || reason == StateChangeReason.FLING) {
RecordUserAction.record("ContextualSearch.SwipeOrFlingMaximize");
} else if (reason == StateChangeReason.SERP_NAVIGATION) {
RecordUserAction.record("ContextualSearch.NavigationMaximize");
}
break;
default:
break;
}
}
/**
* Logs how a state was exited for the first time within a Contextual Search.
* @param fromState The state to transition from.
* @param toState The state to transition to.
* @param reason The reason for the state transition.
*/
public static void logFirstStateExit(
@PanelState int fromState, @PanelState int toState, @StateChangeReason int reason) {
int code;
switch (fromState) {
case PanelState.UNDEFINED:
case PanelState.CLOSED:
code = getStateChangeCode(
toState, reason, EXIT_CLOSED_TO_STATE_CHANGE_CODES, ExitClosedTo.OTHER);
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchExitClosed", code, ExitClosedTo.NUM_ENTRIES);
break;
case PanelState.PEEKED:
code = getStateChangeCode(
toState, reason, EXIT_PEEKED_TO_STATE_CHANGE_CODES, ExitPeekedTo.OTHER);
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchExitPeeked", code, ExitPeekedTo.NUM_ENTRIES);
break;
case PanelState.EXPANDED:
code = getStateChangeCode(
toState, reason, EXIT_EXPANDED_TO_STATE_CHANGE_CODES, ExitExpandedTo.OTHER);
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchExitExpanded", code, ExitExpandedTo.NUM_ENTRIES);
break;
case PanelState.MAXIMIZED:
code = getStateChangeCode(toState, reason, EXIT_MAXIMIZED_TO_STATE_CHANGE_CODES,
ExitMaximizedTo.OTHER);
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchExitMaximized", code, ExitMaximizedTo.NUM_ENTRIES);
break;
default:
break;
}
}
/**
* Logs the number of impressions and CTR for the previous week for the current user.
* @param previousWeekImpressions The number of times the user saw the Contextual Search Bar.
* @param previousWeekCtr The CTR expressed as a percentage.
*/
public static void logPreviousWeekCtr(int previousWeekImpressions, int previousWeekCtr) {
RecordHistogram.recordCountHistogram(
"Search.ContextualSearchPreviousWeekImpressions", previousWeekImpressions);
RecordHistogram.recordPercentageHistogram(
"Search.ContextualSearchPreviousWeekCtr", previousWeekCtr);
}
/**
* Logs the number of impressions and CTR for previous 28-day period for the current user.
* @param previous28DayImpressions The number of times the user saw the Contextual Search Bar.
* @param previous28DayCtr The CTR expressed as a percentage.
*/
public static void logPrevious28DayCtr(int previous28DayImpressions, int previous28DayCtr) {
RecordHistogram.recordCountHistogram(
"Search.ContextualSearchPrevious28DayImpressions", previous28DayImpressions);
RecordHistogram.recordPercentageHistogram(
"Search.ContextualSearchPrevious28DayCtr", previous28DayCtr);
}
/**
* Logs a duration since the outcomes (and associated timestamp) were saved in persistent
* storage.
* @param durationMs The duration to log, in milliseconds.
*/
public static void logOutcomesTimestamp(long durationMs) {
int durationInDays = (int) (durationMs / DateUtils.DAY_IN_MILLIS);
RecordHistogram.recordCount100Histogram(
"Search.ContextualSearch.OutcomesDuration", durationInDays);
}
/**
* Get the encoded value to use for the Bar Overlap histogram by encoding all the input
* parameters.
* @param didBarOverlap Whether the selection overlapped the Bar position.
* @param wasPanelSeen Whether the panel content was seen.
* @param wasTap Whether the gesture was a Tap.
* @return The value for the enum histogram.
*/
private static @BarOverlapResults int getBarOverlapEnum(
boolean didBarOverlap, boolean wasPanelSeen, boolean wasTap) {
if (wasTap) {
if (didBarOverlap) {
return wasPanelSeen ? BarOverlapResults.BAR_OVERLAP_RESULTS_SEEN_FROM_TAP
: BarOverlapResults.BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_TAP;
} else {
return wasPanelSeen ? BarOverlapResults.NO_BAR_OVERLAP_RESULTS_SEEN_FROM_TAP
: BarOverlapResults.NO_BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_TAP;
}
} else {
if (didBarOverlap) {
return wasPanelSeen
? BarOverlapResults.BAR_OVERLAP_RESULTS_SEEN_FROM_LONG_PRESS
: BarOverlapResults.BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_LONG_PRESS;
} else {
return wasPanelSeen
? BarOverlapResults.NO_BAR_OVERLAP_RESULTS_SEEN_FROM_LONG_PRESS
: BarOverlapResults.NO_BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_LONG_PRESS;
}
}
}
/**
* Logs that whether or not the conditions are met to perform a translation.
* @param isConditionMet Whether the translation conditions were met.
*/
public static void logTranslateCondition(boolean isConditionMet) {
RecordHistogram.recordBooleanHistogram(
"Search.ContextualSearchTranslateCondition", isConditionMet);
}
/**
* Logs whether Contextual Cards data was shown. Should be logged on tap if Contextual
* Cards integration is enabled.
* @param shown Whether Contextual Cards data was shown in the Bar.
*/
public static void logContextualCardsDataShown(boolean shown) {
RecordHistogram.recordBooleanHistogram(
"Search.ContextualSearchContextualCardsIntegration.DataShown", shown);
}
/**
* Logs whether results were seen when Contextual Cards data was shown.
* @param wasSeen Whether the search results were seen.
*/
public static void logContextualCardsResultsSeen(boolean wasSeen) {
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchContextualCardsIntegration.ResultsSeen",
wasSeen ? Results.SEEN : Results.NOT_SEEN, Results.NUM_ENTRIES);
}
/**
* Logs whether a quick action intent resolved to zero, one, or many apps.
* @param quickActionCategory The {@link QuickActionCategory} for the quick action.
* @param numMatchingAppsApps The number of apps that the resolved intent matched.
*/
public static void logQuickActionIntentResolution(int quickActionCategory,
int numMatchingAppsApps) {
int code = numMatchingAppsApps == 0
? QuickActionResolve.FAILED
: numMatchingAppsApps == 1 ? QuickActionResolve.SINGLE
: QuickActionResolve.MULTIPLE;
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchQuickActions.IntentResolution."
+ getLabelForQuickActionCategory(quickActionCategory),
code, QuickActionResolve.NUM_ENTRIES);
}
/**
* Logs whether a quick action was shown, and the quick aciton category if a quick action was
* shown. Should be logged on tap if Contextual Search single actions are enabled.
* @param quickActionShown Whether a quick action was shown.
* @param quickActionCategory The {@link QuickActionCategory} for the quick action.
*/
public static void logQuickActionShown(boolean quickActionShown, int quickActionCategory) {
RecordHistogram.recordBooleanHistogram(
"Search.ContextualSearchQuickActions.Shown", quickActionShown);
if (quickActionShown) {
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearchQuickActions.Category", quickActionCategory,
QuickActionResolve.NUM_ENTRIES);
}
}
/**
* Logs whether results were seen when a quick action was present.
* @param wasSeen Whether the search results were seen.
* @param quickActionCategory The {@link QuickActionCategory} for the quick action.
*/
public static void logQuickActionResultsSeen(boolean wasSeen, int quickActionCategory) {
RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchQuickActions.ResultsSeen."
+ getLabelForQuickActionCategory(quickActionCategory),
wasSeen ? Results.SEEN : Results.NOT_SEEN, Results.NUM_ENTRIES);
}
/**
* Logs whether a quick action was clicked.
* @param wasClicked Whether the quick action was clicked
* @param quickActionCategory The {@link QuickActionCategory} for the quick action.
*/
public static void logQuickActionClicked(boolean wasClicked, int quickActionCategory) {
RecordHistogram.recordBooleanHistogram(
"Search.ContextualSearchQuickActions.Clicked."
+ getLabelForQuickActionCategory(quickActionCategory),
wasClicked);
}
/**
* Logs the primary CoCa {@link CardTag} for searches where the panel contents was seen,
* including {@codeCardTag.CT_NONE} when no card or tag, and {@codeCardTag.CT_OTHER} when it's
* one we do not recognize.
* @param wasSearchContentViewSeen Whether the panel was seen.
* @param cardTagEnum The primary CoCa card Tag for the result seen.
*/
public static void logCardTagSeen(boolean wasSearchContentViewSeen, @CardTag int cardTagEnum) {
if (wasSearchContentViewSeen) {
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearch.CardTagSeen", cardTagEnum, CardTag.NUM_ENTRIES);
}
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearch.CardTag", cardTagEnum, CardTag.NUM_ENTRIES);
}
/**
* Logs results-seen when we have a useful Ranker prediction inference.
* @param wasPanelSeen Whether the panel was seen.
* @param predictionKind An integer reflecting the Ranker prediction, e.g. that this is a good
* time to suppress triggering because the likelihood of opening the panel is relatively
* low.
*/
public static void logRankerInference(
boolean wasPanelSeen, @AssistRankerPrediction int predictionKind) {
if (predictionKind == AssistRankerPrediction.SHOW) {
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearch.Ranker.NotSuppressed.ResultsSeen",
wasPanelSeen ? Results.SEEN : Results.NOT_SEEN, Results.NUM_ENTRIES);
} else if (predictionKind == AssistRankerPrediction.SUPPRESS) {
RecordHistogram.recordEnumeratedHistogram(
"Search.ContextualSearch.Ranker.WouldSuppress.ResultsSeen",
wasPanelSeen ? Results.SEEN : Results.NOT_SEEN, Results.NUM_ENTRIES);
}
}
/**
* Logs Ranker's prediction of whether or not to suppress.
* @param predictionKind An integer reflecting the Ranker prediction, e.g. that this is a good
* time to suppress triggering because the likelihood of opening the panel is relatively
* low.
*/
public static void logRankerPrediction(@AssistRankerPrediction int predictionKind) {
// For now we just log whether or not suppression is predicted.
RecordHistogram.recordBooleanHistogram("Search.ContextualSearch.Ranker.Suppressed",
predictionKind == AssistRankerPrediction.SUPPRESS);
}
/** Logs that Ranker recorded a set of features for training or inference. */
public static void logRecordedFeaturesToRanker() {
logRecordedToRanker(false);
}
/** Logs that Ranker recorded a set of outcomes for training or inference. */
public static void logRecordedOutcomesToRanker() {
logRecordedToRanker(true);
}
/**
* Logs that Ranker recorded some data for training or inference.
* @param areOutcomes Whether the data are outcomes.
*/
private static void logRecordedToRanker(boolean areOutcomes) {
RecordHistogram.recordBooleanHistogram(
"Search.ContextualSearch.Ranker.Recorded", areOutcomes);
}
/**
* Logs that features or outcomes are available to record to Ranker.
* This data can be used to correlate with #logRecordedToRanker to validate that everything that
* should be recorded is actually being recorded.
* @param areOutcomes Whether the features available are outcomes.
*/
static void logRankerFeaturesAvailable(boolean areOutcomes) {
RecordHistogram.recordBooleanHistogram(
"Search.ContextualSearch.Ranker.FeaturesAvailable", areOutcomes);
}
/**
* Logs the previous enabled-state of this user before the feature was turned full-on for
* Unified Consent (when integration is enabled).
* @param wasPreviouslyUndecided Whether the user was previously undecided.
*/
static void logUnifiedConsentPreviousEnabledState(boolean wasPreviouslyUndecided) {
RecordHistogram.recordBooleanHistogram(
"Search.ContextualSearch.UnifiedConsent.PreviouslyUndecided",
wasPreviouslyUndecided);
}
/**
* Logs whether a request will be throttled for Unified Consent integration, for all requests
* regardless of whether the integration feature is enabled. Logged multiple times per request.
* @param isRequestThrottled Whether the current request is being throttled.
*/
static void logUnifiedConsentThrottledRequests(boolean isRequestThrottled) {
RecordHistogram.recordBooleanHistogram(
"Search.ContextualSearch.UnifiedConsent.ThrottledRequests", isRequestThrottled);
}
/**
* Logs whether this user was eligible for throttling of requests when Unified Consent
* integration is enabled and throttling is in effect.
* @param isThrottleEligible Whether this user is eligible to be throttled.
*/
static void logUnifiedConsentThrottleEligible(boolean isThrottleEligible) {
RecordHistogram.recordBooleanHistogram(
"Search.ContextualSearch.UnifiedConsent.ThrottleEligible", isThrottleEligible);
}
/**
* Gets the state-change code for the given parameters by doing a lookup in the given map.
* @param state The panel state.
* @param reason The reason the state changed.
* @param stateChangeCodes The map of state and reason to code.
* @param defaultCode The code to return if the given values are not found in the map.
* @return The code to write into an enum histogram, based on the given map.
*/
private static int getStateChangeCode(@PanelState int state, @StateChangeReason int reason,
Map<StateChangeKey, Integer> stateChangeCodes, int defaultCode) {
Integer code = stateChangeCodes.get(new StateChangeKey(state, reason));
return code != null ? code : defaultCode;
}
/**
* Gets the panel-seen code for the given parameters by doing a lookup in the seen-by-gesture
* map.
* @param wasPanelSeen Whether the panel was seen.
* @param wasTap Whether the gesture that originally caused the panel to show was a Tap.
* @return The code to write into a panel-seen histogram.
*/
private static int getPanelSeenByGestureStateCode(boolean wasPanelSeen, boolean wasTap) {
return SEEN_BY_GESTURE_CODES.get(new Pair<Boolean, Boolean>(wasPanelSeen, wasTap));
}
/**
* Gets the promo-outcome code for the given parameter by doing a lookup in the
* promo-by-gesture map.
* @param preferenceValue The code for the current preference value.
* @param wasTap Whether the gesture that originally caused the panel to show was a Tap.
* @return The code to write into a promo-outcome histogram.
*/
private static int getPromoByGestureStateCode(int preferenceValue, boolean wasTap) {
return PROMO_BY_GESTURE_CODES.get(new Pair<Integer, Boolean>(preferenceValue, wasTap));
}
/**
* @return The code for the Contextual Search preference.
*/
private static int getPreferenceValue() {
if (ContextualSearchManager.isContextualSearchUninitialized()) {
return Preference.UNINITIALIZED;
} else if (ContextualSearchManager.isContextualSearchDisabled()) {
return Preference.DISABLED;
}
return Preference.ENABLED;
}
/**
* Gets the encode value for quick answers seen.
* @param didActivate Whether the quick answer was shown.
* @param didAnswer Whether the caption was a full answer, not just a hint.
* @param wasSeen Whether the search panel was opened.
* @return The encoded value.
*/
private static @QuickAnswerSeen int getQuickAnswerSeenValue(
boolean didActivate, boolean didAnswer, boolean wasSeen) {
if (wasSeen) {
if (didActivate) {
return didAnswer ? QuickAnswerSeen.ACTIVATED_WAS_AN_ANSWER_SEEN
: QuickAnswerSeen.ACTIVATED_NOT_AN_ANSWER_SEEN;
} else {
return QuickAnswerSeen.NOT_ACTIVATED_SEEN;
}
} else {
if (didActivate) {
return didAnswer ? QuickAnswerSeen.ACTIVATED_WAS_AN_ANSWER_NOT_SEEN
: QuickAnswerSeen.ACTIVATED_NOT_AN_ANSWER_NOT_SEEN;
} else {
return QuickAnswerSeen.NOT_ACTIVATED_NOT_SEEN;
}
}
}
/**
* Logs to a seen-by-gesture histogram of the given name.
* @param wasPanelSeen Whether the panel was seen.
* @param wasTap Whether the gesture that originally caused the panel to show was a Tap.
* @param histogramName The full name of the histogram to log to.
*/
private static void logHistogramByGesture(boolean wasPanelSeen, boolean wasTap,
String histogramName) {
RecordHistogram.recordEnumeratedHistogram(histogramName,
getPanelSeenByGestureStateCode(wasPanelSeen, wasTap), ResultsByGesture.NUM_ENTRIES);
}
private static String getLabelForQuickActionCategory(int quickActionCategory) {
switch(quickActionCategory) {
case QuickActionCategory.ADDRESS:
return "Address";
case QuickActionCategory.EMAIL:
return "Email";
case QuickActionCategory.EVENT:
return "Event";
case QuickActionCategory.PHONE:
return "Phone";
case QuickActionCategory.WEBSITE:
return "Website";
default:
return "None";
}
}
}