blob: 90f67333cd605a5d24fdf4cfa63326ab111ebf7e [file] [log] [blame]
// Copyright 2013 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.
#include "chrome/browser/ui/search/ntp_user_data_logger.h"
#include <algorithm>
#include <string>
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "chrome/browser/after_startup_task_utils.h"
#include "chrome/browser/search/instant_service.h"
#include "chrome/browser/search/instant_service_factory.h"
#include "chrome/browser/search/ntp_features.h"
#include "chrome/browser/search/search.h"
#include "chrome/browser/ui/search/ntp_user_data_types.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "components/ntp_tiles/metrics.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/web_contents.h"
namespace {
// This enum must match the numbering for NewTabPageVoiceAction in enums.xml.
// Do not reorder or remove items, only add new items before VOICE_ACTION_MAX.
enum VoiceAction {
// Activated by clicking on the fakebox icon.
VOICE_ACTION_ACTIVATE_FAKEBOX = 0,
// Activated by keyboard shortcut.
VOICE_ACTION_ACTIVATE_KEYBOARD = 1,
// Close the voice overlay by a user's explicit action.
VOICE_ACTION_CLOSE_OVERLAY = 2,
// Submitted voice query.
VOICE_ACTION_QUERY_SUBMITTED = 3,
// Clicked on support link in error message.
VOICE_ACTION_SUPPORT_LINK_CLICKED = 4,
// Retried by clicking Try Again link.
VOICE_ACTION_TRY_AGAIN_LINK = 5,
// Retried by clicking microphone button.
VOICE_ACTION_TRY_AGAIN_MIC_BUTTON = 6,
VOICE_ACTION_MAX
};
// Converts |NTPLoggingEventType| to a |VoiceAction|, if the value
// is an action value. Otherwise, |VOICE_ACTION_MAX| is returned.
VoiceAction LoggingEventToVoiceAction(NTPLoggingEventType event) {
switch (event) {
case NTP_VOICE_ACTION_ACTIVATE_FAKEBOX:
return VOICE_ACTION_ACTIVATE_FAKEBOX;
case NTP_VOICE_ACTION_ACTIVATE_KEYBOARD:
return VOICE_ACTION_ACTIVATE_KEYBOARD;
case NTP_VOICE_ACTION_CLOSE_OVERLAY:
return VOICE_ACTION_CLOSE_OVERLAY;
case NTP_VOICE_ACTION_QUERY_SUBMITTED:
return VOICE_ACTION_QUERY_SUBMITTED;
case NTP_VOICE_ACTION_SUPPORT_LINK_CLICKED:
return VOICE_ACTION_SUPPORT_LINK_CLICKED;
case NTP_VOICE_ACTION_TRY_AGAIN_LINK:
return VOICE_ACTION_TRY_AGAIN_LINK;
case NTP_VOICE_ACTION_TRY_AGAIN_MIC_BUTTON:
return VOICE_ACTION_TRY_AGAIN_MIC_BUTTON;
default:
NOTREACHED();
return VOICE_ACTION_MAX;
}
}
// This enum must match the numbering for NewTabPageVoiceError in enums.xml.
// Do not reorder or remove items, only add new items before VOICE_ERROR_MAX.
enum VoiceError {
VOICE_ERROR_ABORTED = 0,
VOICE_ERROR_AUDIO_CAPTURE = 1,
VOICE_ERROR_BAD_GRAMMAR = 2,
VOICE_ERROR_LANGUAGE_NOT_SUPPORTED = 3,
VOICE_ERROR_NETWORK = 4,
VOICE_ERROR_NO_MATCH = 5,
VOICE_ERROR_NO_SPEECH = 6,
VOICE_ERROR_NOT_ALLOWED = 7,
VOICE_ERROR_OTHER = 8,
VOICE_ERROR_SERVICE_NOT_ALLOWED = 9,
VOICE_ERROR_MAX
};
// Logs BackgroundCustomization availability on the NTP,
void LogBackgroundCustomizationAvailability(
BackgroundCustomization availability) {
UMA_HISTOGRAM_ENUMERATION("NewTabPage.CustomizationAvailability.Backgrounds",
availability);
}
// Logs ShortcutCustomization availability on the NTP,
void LogShortcutCustomizationAvailability(ShortcutCustomization availability) {
UMA_HISTOGRAM_ENUMERATION("NewTabPage.CustomizationAvailability.Shortcuts",
availability);
}
// Converts |NTPLoggingEventType| to a |CustomizedFeature|.
CustomizedFeature LoggingEventToCustomizedFeature(NTPLoggingEventType event) {
switch (event) {
case NTP_BACKGROUND_CUSTOMIZED:
return CustomizedFeature::CUSTOMIZED_FEATURE_BACKGROUND;
case NTP_SHORTCUT_CUSTOMIZED:
return CustomizedFeature::CUSTOMIZED_FEATURE_SHORTCUT;
default:
break;
}
NOTREACHED();
return CustomizedFeature::CUSTOMIZED_FEATURE_BACKGROUND;
}
// Converts |NTPLoggingEventType| to a |CustomizeAction|.
CustomizeAction LoggingEventToCustomizeAction(NTPLoggingEventType event) {
switch (event) {
case NTP_CUSTOMIZE_CHROME_BACKGROUNDS_CLICKED:
return CustomizeAction::CUSTOMIZE_ACTION_CHROME_BACKGROUNDS;
case NTP_CUSTOMIZE_LOCAL_IMAGE_CLICKED:
return CustomizeAction::CUSTOMIZE_ACTION_LOCAL_IMAGE;
case NTP_CUSTOMIZE_RESTORE_BACKGROUND_CLICKED:
return CustomizeAction::CUSTOMIZE_ACTION_RESTORE_BACKGROUND;
case NTP_CUSTOMIZE_ATTRIBUTION_CLICKED:
return CustomizeAction::CUSTOMIZE_ACTION_ATTRIBUTION;
case NTP_CUSTOMIZE_ADD_SHORTCUT_CLICKED:
return CustomizeAction::CUSTOMIZE_ACTION_ADD_SHORTCUT;
case NTP_CUSTOMIZE_EDIT_SHORTCUT_CLICKED:
return CustomizeAction::CUSTOMIZE_ACTION_EDIT_SHORTCUT;
case NTP_CUSTOMIZE_RESTORE_SHORTCUTS_CLICKED:
return CustomizeAction::CUSTOMIZE_ACTION_RESTORE_SHORTCUT;
default:
break;
}
NOTREACHED();
return CustomizeAction::CUSTOMIZE_ACTION_CHROME_BACKGROUNDS;
}
// Converts |NTPLoggingEventType| to a |CustomizeChromeBackgroundAction|.
CustomizeChromeBackgroundAction LoggingEventToCustomizeChromeBackgroundAction(
NTPLoggingEventType event) {
switch (event) {
case NTP_CUSTOMIZE_CHROME_BACKGROUND_SELECT_COLLECTION:
return CustomizeChromeBackgroundAction::
CUSTOMIZE_CHROME_BACKGROUND_ACTION_SELECT_COLLECTION;
case NTP_CUSTOMIZE_CHROME_BACKGROUND_SELECT_IMAGE:
return CustomizeChromeBackgroundAction::
CUSTOMIZE_CHROME_BACKGROUND_ACTION_SELECT_IMAGE;
case NTP_CUSTOMIZE_CHROME_BACKGROUND_CANCEL:
return CustomizeChromeBackgroundAction::
CUSTOMIZE_CHROME_BACKGROUND_ACTION_CANCEL;
case NTP_CUSTOMIZE_CHROME_BACKGROUND_DONE:
return CustomizeChromeBackgroundAction::
CUSTOMIZE_CHROME_BACKGROUND_ACTION_DONE;
default:
break;
}
NOTREACHED();
return CustomizeChromeBackgroundAction::
CUSTOMIZE_CHROME_BACKGROUND_ACTION_SELECT_COLLECTION;
}
// Converts |NTPLoggingEventType| to a |CustomizeLocalImageBackgroundAction|.
CustomizeLocalImageBackgroundAction
LoggingEventToCustomizeLocalImageBackgroundAction(NTPLoggingEventType event) {
switch (event) {
case NTP_CUSTOMIZE_LOCAL_IMAGE_CANCEL:
return CustomizeLocalImageBackgroundAction::
CUSTOMIZE_LOCAL_IMAGE_BACKGROUND_ACTION_CANCEL;
case NTP_CUSTOMIZE_LOCAL_IMAGE_DONE:
return CustomizeLocalImageBackgroundAction::
CUSTOMIZE_LOCAL_IMAGE_BACKGROUND_ACTION_DONE;
default:
break;
}
NOTREACHED();
return CustomizeLocalImageBackgroundAction::
CUSTOMIZE_LOCAL_IMAGE_BACKGROUND_ACTION_CANCEL;
}
// Converts |NTPLoggingEventType| to a |CustomizeShortcutAction|.
CustomizeShortcutAction LoggingEventToCustomizeShortcutAction(
NTPLoggingEventType event) {
switch (event) {
case NTP_CUSTOMIZE_SHORTCUT_ADD:
return CustomizeShortcutAction::CUSTOMIZE_SHORTCUT_ACTION_ADD;
case NTP_CUSTOMIZE_SHORTCUT_UPDATE:
return CustomizeShortcutAction::CUSTOMIZE_SHORTCUT_ACTION_UPDATE;
case NTP_CUSTOMIZE_SHORTCUT_REMOVE:
return CustomizeShortcutAction::CUSTOMIZE_SHORTCUT_ACTION_REMOVE;
case NTP_CUSTOMIZE_SHORTCUT_CANCEL:
return CustomizeShortcutAction::CUSTOMIZE_SHORTCUT_ACTION_CANCEL;
case NTP_CUSTOMIZE_SHORTCUT_DONE:
return CustomizeShortcutAction::CUSTOMIZE_SHORTCUT_ACTION_DONE;
case NTP_CUSTOMIZE_SHORTCUT_UNDO:
return CustomizeShortcutAction::CUSTOMIZE_SHORTCUT_ACTION_UNDO;
case NTP_CUSTOMIZE_SHORTCUT_RESTORE_ALL:
return CustomizeShortcutAction::CUSTOMIZE_SHORTCUT_ACTION_RESTORE_ALL;
default:
break;
}
NOTREACHED();
return CustomizeShortcutAction::CUSTOMIZE_SHORTCUT_ACTION_REMOVE;
}
// Converts |NTPLoggingEventType| to a |VoiceError|, if the value
// is an error value. Otherwise, |VOICE_ERROR_MAX| is returned.
VoiceError LoggingEventToVoiceError(NTPLoggingEventType event) {
switch (event) {
case NTP_VOICE_ERROR_ABORTED:
return VOICE_ERROR_ABORTED;
case NTP_VOICE_ERROR_AUDIO_CAPTURE:
return VOICE_ERROR_AUDIO_CAPTURE;
case NTP_VOICE_ERROR_BAD_GRAMMAR:
return VOICE_ERROR_BAD_GRAMMAR;
case NTP_VOICE_ERROR_LANGUAGE_NOT_SUPPORTED:
return VOICE_ERROR_LANGUAGE_NOT_SUPPORTED;
case NTP_VOICE_ERROR_NETWORK:
return VOICE_ERROR_NETWORK;
case NTP_VOICE_ERROR_NO_MATCH:
return VOICE_ERROR_NO_MATCH;
case NTP_VOICE_ERROR_NO_SPEECH:
return VOICE_ERROR_NO_SPEECH;
case NTP_VOICE_ERROR_NOT_ALLOWED:
return VOICE_ERROR_NOT_ALLOWED;
case NTP_VOICE_ERROR_OTHER:
return VOICE_ERROR_OTHER;
case NTP_VOICE_ERROR_SERVICE_NOT_ALLOWED:
return VOICE_ERROR_SERVICE_NOT_ALLOWED;
default:
NOTREACHED();
return VOICE_ERROR_MAX;
}
}
// This enum must match the numbering for NewTabPageLogoShown in enums.xml.
// Do not reorder or remove items, and only add new items before
// LOGO_IMPRESSION_TYPE_MAX.
enum LogoImpressionType {
// Static Doodle image.
LOGO_IMPRESSION_TYPE_STATIC = 0,
// Call-to-action Doodle image.
LOGO_IMPRESSION_TYPE_CTA = 1,
LOGO_IMPRESSION_TYPE_MAX
};
// This enum must match the numbering for NewTabPageLogoClick in enums.xml.
// Do not reorder or remove items, and only add new items before
// LOGO_CLICK_TYPE_MAX.
enum LogoClickType {
// Static Doodle image.
LOGO_CLICK_TYPE_STATIC = 0,
// Call-to-action Doodle image.
LOGO_CLICK_TYPE_CTA = 1,
// Animated Doodle image.
LOGO_CLICK_TYPE_ANIMATED = 2,
LOGO_CLICK_TYPE_MAX
};
// Converts |NTPLoggingEventType| to a |LogoClickType|, if the value
// is an error value. Otherwise, |LOGO_CLICK_TYPE_MAX| is returned.
LogoClickType LoggingEventToLogoClick(NTPLoggingEventType event) {
switch (event) {
case NTP_STATIC_LOGO_CLICKED:
return LOGO_CLICK_TYPE_STATIC;
case NTP_CTA_LOGO_CLICKED:
return LOGO_CLICK_TYPE_CTA;
case NTP_ANIMATED_LOGO_CLICKED:
return LOGO_CLICK_TYPE_ANIMATED;
default:
NOTREACHED();
return LOGO_CLICK_TYPE_MAX;
}
}
} // namespace
// Helper macro to log a load time to UMA. There's no good reason why we don't
// use one of the standard UMA_HISTORAM_*_TIMES macros, but all their ranges are
// different, and it's not worth changing all the existing histograms.
#define UMA_HISTOGRAM_LOAD_TIME(name, sample) \
UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, \
base::TimeDelta::FromMilliseconds(1), \
base::TimeDelta::FromSeconds(60), 100)
NTPUserDataLogger::~NTPUserDataLogger() {}
// static
NTPUserDataLogger* NTPUserDataLogger::GetOrCreateFromWebContents(
content::WebContents* content) {
DCHECK(search::IsInstantNTP(content));
// Calling CreateForWebContents when an instance is already attached has no
// effect, so we can do this.
NTPUserDataLogger::CreateForWebContents(content);
NTPUserDataLogger* logger = NTPUserDataLogger::FromWebContents(content);
// We record the URL of this NTP in order to identify navigations that
// originate from it. We use the NavigationController's URL since it might
// differ from the WebContents URL which is usually chrome://newtab/.
//
// We update the NTP URL every time this function is called, because the NTP
// URL sometimes changes while it is open, and we care about the final one for
// detecting when the user leaves or returns to the NTP. In particular, if the
// Google URL changes (e.g. google.com -> google.de), then we fall back to the
// local NTP.
content::NavigationEntry* entry = content->GetController().GetVisibleEntry();
if (entry && (logger->ntp_url_ != entry->GetURL())) {
DVLOG(1) << "NTP URL changed from \"" << logger->ntp_url_ << "\" to \""
<< entry->GetURL() << "\"";
logger->ntp_url_ = entry->GetURL();
}
logger->profile_ = Profile::FromBrowserContext(content->GetBrowserContext());
return logger;
}
void NTPUserDataLogger::LogEvent(NTPLoggingEventType event,
base::TimeDelta time) {
if (event == NTP_ALL_TILES_LOADED) {
EmitNtpStatistics(time);
}
// All other events can only be logged by the Google NTP
if (!DefaultSearchProviderIsGoogle()) {
return;
}
switch (event) {
case NTP_ALL_TILES_RECEIVED:
tiles_received_time_ = time;
break;
case NTP_ALL_TILES_LOADED:
// permitted above for non-Google search providers
break;
case NTP_VOICE_ACTION_ACTIVATE_FAKEBOX:
case NTP_VOICE_ACTION_ACTIVATE_KEYBOARD:
case NTP_VOICE_ACTION_CLOSE_OVERLAY:
case NTP_VOICE_ACTION_QUERY_SUBMITTED:
case NTP_VOICE_ACTION_SUPPORT_LINK_CLICKED:
case NTP_VOICE_ACTION_TRY_AGAIN_LINK:
case NTP_VOICE_ACTION_TRY_AGAIN_MIC_BUTTON:
UMA_HISTOGRAM_ENUMERATION("NewTabPage.VoiceActions",
LoggingEventToVoiceAction(event),
VOICE_ACTION_MAX);
break;
case NTP_VOICE_ERROR_ABORTED:
case NTP_VOICE_ERROR_AUDIO_CAPTURE:
case NTP_VOICE_ERROR_BAD_GRAMMAR:
case NTP_VOICE_ERROR_LANGUAGE_NOT_SUPPORTED:
case NTP_VOICE_ERROR_NETWORK:
case NTP_VOICE_ERROR_NO_MATCH:
case NTP_VOICE_ERROR_NO_SPEECH:
case NTP_VOICE_ERROR_NOT_ALLOWED:
case NTP_VOICE_ERROR_OTHER:
case NTP_VOICE_ERROR_SERVICE_NOT_ALLOWED:
UMA_HISTOGRAM_ENUMERATION("NewTabPage.VoiceErrors",
LoggingEventToVoiceError(event),
VOICE_ERROR_MAX);
break;
case NTP_STATIC_LOGO_SHOWN_FROM_CACHE:
RecordDoodleImpression(time, /*is_cta=*/false, /*from_cache=*/true);
break;
case NTP_STATIC_LOGO_SHOWN_FRESH:
RecordDoodleImpression(time, /*is_cta=*/false, /*from_cache=*/false);
break;
case NTP_CTA_LOGO_SHOWN_FROM_CACHE:
RecordDoodleImpression(time, /*is_cta=*/true, /*from_cache=*/true);
break;
case NTP_CTA_LOGO_SHOWN_FRESH:
RecordDoodleImpression(time, /*is_cta=*/true, /*from_cache=*/false);
break;
case NTP_STATIC_LOGO_CLICKED:
case NTP_CTA_LOGO_CLICKED:
case NTP_ANIMATED_LOGO_CLICKED:
UMA_HISTOGRAM_ENUMERATION("NewTabPage.LogoClick",
LoggingEventToLogoClick(event),
LOGO_CLICK_TYPE_MAX);
break;
case NTP_ONE_GOOGLE_BAR_SHOWN:
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.OneGoogleBar.ShownTime", time);
break;
case NTP_BACKGROUND_CUSTOMIZED:
case NTP_SHORTCUT_CUSTOMIZED:
UMA_HISTOGRAM_ENUMERATION("NewTabPage.Customized",
LoggingEventToCustomizedFeature(event));
break;
case NTP_CUSTOMIZE_CHROME_BACKGROUNDS_CLICKED:
case NTP_CUSTOMIZE_LOCAL_IMAGE_CLICKED:
case NTP_CUSTOMIZE_RESTORE_BACKGROUND_CLICKED:
case NTP_CUSTOMIZE_ATTRIBUTION_CLICKED:
case NTP_CUSTOMIZE_ADD_SHORTCUT_CLICKED:
case NTP_CUSTOMIZE_EDIT_SHORTCUT_CLICKED:
case NTP_CUSTOMIZE_RESTORE_SHORTCUTS_CLICKED:
UMA_HISTOGRAM_ENUMERATION("NewTabPage.CustomizeAction",
LoggingEventToCustomizeAction(event));
break;
case NTP_CUSTOMIZE_CHROME_BACKGROUND_SELECT_COLLECTION:
case NTP_CUSTOMIZE_CHROME_BACKGROUND_SELECT_IMAGE:
case NTP_CUSTOMIZE_CHROME_BACKGROUND_CANCEL:
case NTP_CUSTOMIZE_CHROME_BACKGROUND_DONE:
UMA_HISTOGRAM_ENUMERATION(
"NewTabPage.CustomizeChromeBackgroundAction",
LoggingEventToCustomizeChromeBackgroundAction(event));
break;
case NTP_CUSTOMIZE_LOCAL_IMAGE_CANCEL:
case NTP_CUSTOMIZE_LOCAL_IMAGE_DONE:
UMA_HISTOGRAM_ENUMERATION(
"NewTabPage.CustomizeLocalImageBackgroundAction",
LoggingEventToCustomizeLocalImageBackgroundAction(event));
break;
case NTP_CUSTOMIZE_SHORTCUT_ADD:
case NTP_CUSTOMIZE_SHORTCUT_UPDATE:
case NTP_CUSTOMIZE_SHORTCUT_REMOVE:
case NTP_CUSTOMIZE_SHORTCUT_CANCEL:
case NTP_CUSTOMIZE_SHORTCUT_DONE:
case NTP_CUSTOMIZE_SHORTCUT_UNDO:
case NTP_CUSTOMIZE_SHORTCUT_RESTORE_ALL:
UMA_HISTOGRAM_ENUMERATION("NewTabPage.CustomizeShortcutAction",
LoggingEventToCustomizeShortcutAction(event));
break;
case NTP_MIDDLE_SLOT_PROMO_SHOWN:
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.Promos.ShownTime", time);
break;
case NTP_MIDDLE_SLOT_PROMO_LINK_CLICKED:
UMA_HISTOGRAM_EXACT_LINEAR("NewTabPage.Promos.LinkClicked", 1, 1);
break;
}
}
void NTPUserDataLogger::LogSuggestionEventWithValue(
NTPSuggestionsLoggingEventType event,
int data,
base::TimeDelta time) {
// Only logged on the Google NTP.
if (!DefaultSearchProviderIsGoogle()) {
return;
}
switch (event) {
case NTPSuggestionsLoggingEventType::kShownCount:
UMA_HISTOGRAM_COUNTS_100("NewTabPage.SearchSuggestions.ShownCount", data);
break;
case NTPSuggestionsLoggingEventType::kIndexClicked:
UMA_HISTOGRAM_COUNTS_100("NewTabPage.SearchSuggestions.IndexClicked",
data);
break;
}
}
void NTPUserDataLogger::LogMostVisitedImpression(
const ntp_tiles::NTPTileImpression& impression) {
if ((impression.index >= ntp_tiles::kMaxNumTiles) ||
logged_impressions_[impression.index].has_value()) {
return;
}
logged_impressions_[impression.index] = impression;
}
void NTPUserDataLogger::LogMostVisitedNavigation(
const ntp_tiles::NTPTileImpression& impression) {
ntp_tiles::metrics::RecordTileClick(impression);
// Records the action. This will be available as a time-stamped stream
// server-side and can be used to compute time-to-long-dwell.
base::RecordAction(base::UserMetricsAction("MostVisited_Clicked"));
}
NTPUserDataLogger::NTPUserDataLogger(content::WebContents* contents)
: content::WebContentsObserver(contents),
has_emitted_(false),
should_record_doodle_load_time_(true),
during_startup_(!AfterStartupTaskUtils::IsBrowserStartupComplete()) {
}
// content::WebContentsObserver override
void NTPUserDataLogger::NavigationEntryCommitted(
const content::LoadCommittedDetails& load_details) {
NavigatedFromURLToURL(load_details.previous_url,
load_details.entry->GetURL());
}
void NTPUserDataLogger::NavigatedFromURLToURL(const GURL& from,
const GURL& to) {
// User is returning to NTP, probably via the back button; reset stats.
if (from.is_valid() && to.is_valid() && (to == ntp_url_)) {
DVLOG(1) << "Returning to New Tab Page";
logged_impressions_.fill(base::nullopt);
tiles_received_time_ = base::TimeDelta();
has_emitted_ = false;
should_record_doodle_load_time_ = true;
}
}
bool NTPUserDataLogger::DefaultSearchProviderIsGoogle() const {
return search::DefaultSearchProviderIsGoogle(profile_);
}
bool NTPUserDataLogger::CustomBackgroundIsConfigured() const {
InstantService* instant_service =
InstantServiceFactory::GetForProfile(profile_);
return instant_service->IsCustomBackgroundSet();
}
void NTPUserDataLogger::EmitNtpStatistics(base::TimeDelta load_time) {
// We only send statistics once per page.
if (has_emitted_) {
return;
}
bool has_server_side_suggestions = false;
int tiles_count = 0;
for (const base::Optional<ntp_tiles::NTPTileImpression>& impression :
logged_impressions_) {
if (!impression.has_value()) {
break;
}
if (impression->source == ntp_tiles::TileSource::SUGGESTIONS_SERVICE) {
has_server_side_suggestions = true;
}
// No URL and rappor service passed - not interested in favicon-related
// Rappor metrics.
ntp_tiles::metrics::RecordTileImpression(*impression,
/*rappor_service=*/nullptr);
++tiles_count;
}
ntp_tiles::metrics::RecordPageImpression(tiles_count);
DVLOG(1) << "Emitting NTP load time: " << load_time << ", "
<< "number of tiles: " << tiles_count;
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.TilesReceivedTime", tiles_received_time_);
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.LoadTime", load_time);
// Split between ML (aka SuggestionsService) and MV (aka TopSites).
if (has_server_side_suggestions) {
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.TilesReceivedTime.MostLikely",
tiles_received_time_);
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.LoadTime.MostLikely", load_time);
} else {
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.TilesReceivedTime.MostVisited",
tiles_received_time_);
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.LoadTime.MostVisited", load_time);
}
// Note: This could be inaccurate if the default search engine was changed
// since the page load started. That's unlikely enough to not warrant special
// handling.
bool is_google = DefaultSearchProviderIsGoogle();
// Split between Web and Local.
if (ntp_url_.SchemeIsHTTPOrHTTPS()) {
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.TilesReceivedTime.Web",
tiles_received_time_);
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.LoadTime.Web", load_time);
// Only third-party NTPs can be loaded from the web.
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.LoadTime.Web.Other", load_time);
} else {
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.TilesReceivedTime.LocalNTP",
tiles_received_time_);
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.LoadTime.LocalNTP", load_time);
// Further split between Google and non-Google.
if (is_google) {
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.LoadTime.LocalNTP.Google", load_time);
} else {
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.LoadTime.LocalNTP.Other", load_time);
}
}
// Split between Startup and non-startup.
if (during_startup_) {
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.TilesReceivedTime.Startup",
tiles_received_time_);
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.LoadTime.Startup", load_time);
} else {
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.TilesReceivedTime.NewTab",
tiles_received_time_);
UMA_HISTOGRAM_LOAD_TIME("NewTabPage.LoadTime.NewTab", load_time);
}
if (!is_google) {
// TODO(crbug.com/869931): This is only emitted upon search engine change.
LogBackgroundCustomizationAvailability(
BackgroundCustomization::
BACKGROUND_CUSTOMIZATION_UNAVAILABLE_SEARCH_PROVIDER);
} else {
LogBackgroundCustomizationAvailability(
BackgroundCustomization::BACKGROUND_CUSTOMIZATION_AVAILABLE);
}
if (!is_google) {
// TODO(crbug.com/869931): This is only emitted upon search engine change.
LogShortcutCustomizationAvailability(
ShortcutCustomization::
SHORTCUT_CUSTOMIZATION_UNAVAILABLE_SEARCH_PROVIDER);
} else {
LogShortcutCustomizationAvailability(
ShortcutCustomization::SHORTCUT_CUSTOMIZATION_AVAILABLE);
}
if (CustomBackgroundIsConfigured()) {
UMA_HISTOGRAM_ENUMERATION(
"NewTabPage.Customized",
LoggingEventToCustomizedFeature(NTP_BACKGROUND_CUSTOMIZED));
}
has_emitted_ = true;
during_startup_ = false;
}
void NTPUserDataLogger::RecordDoodleImpression(base::TimeDelta time,
bool is_cta,
bool from_cache) {
LogoImpressionType logo_type =
is_cta ? LOGO_IMPRESSION_TYPE_CTA : LOGO_IMPRESSION_TYPE_STATIC;
UMA_HISTOGRAM_ENUMERATION("NewTabPage.LogoShown", logo_type,
LOGO_IMPRESSION_TYPE_MAX);
if (from_cache) {
UMA_HISTOGRAM_ENUMERATION("NewTabPage.LogoShown.FromCache", logo_type,
LOGO_IMPRESSION_TYPE_MAX);
} else {
UMA_HISTOGRAM_ENUMERATION("NewTabPage.LogoShown.Fresh", logo_type,
LOGO_IMPRESSION_TYPE_MAX);
}
if (should_record_doodle_load_time_) {
UMA_HISTOGRAM_MEDIUM_TIMES("NewTabPage.LogoShownTime2", time);
should_record_doodle_load_time_ = false;
}
}
WEB_CONTENTS_USER_DATA_KEY_IMPL(NTPUserDataLogger)