chromium/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/RelatedSearchesUma.java

// Copyright 2021 The Chromium Authors
// 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 androidx.annotation.IntDef;

import org.chromium.base.metrics.RecordHistogram;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Centralizes UMA data collection for Related Searches. All calls must be made from the UI thread.
 */
public class RelatedSearchesUma {
    // Constants for user permissions histogram.
    @IntDef({
        Permissions.SEND_NOTHING,
        Permissions.SEND_URL,
        Permissions.SEND_CONTENT,
        Permissions.SEND_URL_AND_CONTENT,
    })
    @Retention(RetentionPolicy.SOURCE)
    private @interface Permissions {
        int SEND_NOTHING = 0;
        int SEND_URL = 1;
        int SEND_CONTENT = 2;
        int SEND_URL_AND_CONTENT = 3;
        int NUM_ENTRIES = 4;
    }

    // Constants with ScrollAndClickStatus in enums.xml.
    // These values are persisted to logs. Entries should not be renumbered and
    // numeric values should never be reused.
    @IntDef({
        ScrollAndClickStatus.NO_SCROLL_NO_CLICK,
        ScrollAndClickStatus.NO_SCROLL_CLICKED,
        ScrollAndClickStatus.SCROLLED_NO_CLICK,
        ScrollAndClickStatus.SCROLLED_CLICKED,
    })
    @Retention(RetentionPolicy.SOURCE)
    private @interface ScrollAndClickStatus {
        int NO_SCROLL_NO_CLICK = 0;
        int NO_SCROLL_CLICKED = 1;
        int SCROLLED_NO_CLICK = 2;
        int SCROLLED_CLICKED = 3;
        int NUM_ENTRIES = 4;
    }

    /**
     * Logs a histogram indicating which privacy permissions are available that Related Searches
     * cares about. This ignores any language constraint.
     * <p>This can be called multiple times for each user from any part of the code that's freqently
     * executed.
     * @param canSendUrl Whether this user has allowed sending page URL info to Google.
     * @param canSendContent Whether the user can send page content to Google (has accepted the
     *        Contextual Search opt-in).
     */
    static void logRelatedSearchesPermissionsForAllUsers(
            boolean canSendUrl, boolean canSendContent) {
        @Permissions int permissionsEnum;
        if (canSendUrl) {
            permissionsEnum =
                    canSendContent ? Permissions.SEND_URL_AND_CONTENT : Permissions.SEND_URL;
        } else {
            permissionsEnum = canSendContent ? Permissions.SEND_CONTENT : Permissions.SEND_NOTHING;
        }
        RecordHistogram.recordEnumeratedHistogram(
                "Search.RelatedSearches.AllUserPermissions",
                permissionsEnum,
                Permissions.NUM_ENTRIES);
    }

    /**
     * Logs a histogram indicating that a user is qualified for the Related Searches experiment
     * regardless of whether that feature is enabled. This uses a boolean histogram but always
     * logs true in order to get a raw bucket count (without using a user action, as suggested
     * in the User Action Guidelines doc).
     * <p>We use this to gauge whether each group has a balanced number of qualified users.
     * Can be logged multiple times since we'll just look at the user-count of this histogram.
     * This should be called any time a gesture is detected that could trigger a Related Search
     * if the feature were enabled.
     */
    static void logRelatedSearchesQualifiedUsers() {
        RecordHistogram.recordBooleanHistogram("Search.RelatedSearches.QualifiedUsers", true);
    }

    /**
     * Logs that a Related Searches suggestion was selected by the user and records its position.
     * A position of 0 indicates that the query is the default selection search. This may not be a
     * possible position in some implementations. All indices from 1 on are true Related Searches
     * suggestions.
     * @param position The zero-based position of the suggestion in the UI, or the one-based
     *    position of the suggestion in the list of those returned by the server in cases where the
     *    UI does not show the default selection search in position 0.
     */
    public static void logSelectedSuggestionIndex(int position) {
        RecordHistogram.recordCount1MHistogram(
                "Search.RelatedSearches.SelectedSuggestionIndex", position);
    }

    /**
     * Logs that a Chip was selected by the user in a carousel and records its position.
     * The indexes indicate the physical position of the chip in the carousel, not the
     * logical association with any suggestion (since the first position is variable).
     * @param position The 0-based position in the carousel.
     */
    public static void logSelectedCarouselIndex(int position) {
        RecordHistogram.recordCount1MHistogram(
                "Search.RelatedSearches.SelectedCarouselIndex", position);
    }

    /**
     * Logs the CTR for a Related Searches user interaction. Call this function with either
     * {@code false} or {@code true} when the UI is closed depending on whether the user chose any
     * suggestion.
     * @param clicked Whether the user clicked any suggestion or not after they were presented.
     */
    public static void logCtr(boolean clicked) {
        RecordHistogram.recordBooleanHistogram("Search.RelatedSearches.CTR", clicked);
    }

    /**
     * Logs the number of suggestions that were selected in a bottom-bar search session.
     * @param numberOfSuggestionsClicked A count of all the clicks on any suggestion in the
     * UI, including the default selection search (when shown in within the suggestions UI).
     */
    public static void logNumberOfSuggestionsClicked(int numberOfSuggestionsClicked) {
        if (numberOfSuggestionsClicked > 0) {
            RecordHistogram.recordCount1MHistogram(
                    "Search.RelatedSearches.NumberOfSuggestionsClicked2",
                    numberOfSuggestionsClicked);
        }
    }

    /**
     * Logs that the last visible item position in a carousel when a carousel shows.
     * @param position The last visible item position in the carousel.
     */
    public static void logCarouselLastVisibleItemPosition(int position) {
        RecordHistogram.recordCount1MHistogram(
                "Search.RelatedSearches.CarouselLastVisibleItemPosition", position);
    }

    /**
     * Logs weather the users scrolled the carousel or not.
     * @param scrolled Whether the user scrolled the carousel after chips were presented.
     */
    public static void logCarouselScrolled(boolean scrolled) {
        RecordHistogram.recordBooleanHistogram("Search.RelatedSearches.CarouselScrolled", scrolled);
    }

    /**
     * Logs weather the users scrolled and clicked the carousel.
     * @param scrolled Whether the user scrolled the carousel after chips were presented.
     * @param clicked Whether the user clicked any suggestion or not after they were presented.
     */
    public static void logCarouselScrollAndClickStatus(boolean scrolled, boolean clicked) {
        @ScrollAndClickStatus int scrollAndClickStatus;
        if (scrolled) {
            scrollAndClickStatus =
                    clicked
                            ? ScrollAndClickStatus.SCROLLED_CLICKED
                            : ScrollAndClickStatus.SCROLLED_NO_CLICK;
        } else {
            scrollAndClickStatus =
                    clicked
                            ? ScrollAndClickStatus.NO_SCROLL_CLICKED
                            : ScrollAndClickStatus.NO_SCROLL_NO_CLICK;
        }
        RecordHistogram.recordEnumeratedHistogram(
                "Search.RelatedSearches.CarouselScrollAndClick",
                scrollAndClickStatus,
                Permissions.NUM_ENTRIES);
    }
}