root/chrome/browser/ui/webui/ntp/ntp_user_data_logger.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GetOrCreateFromWebContents
  2. GetMostVisitedImpressionHistogramNameForProvider
  3. GetMostVisitedNavigationHistogramNameForProvider
  4. EmitNtpStatistics
  5. LogEvent
  6. LogMostVisitedImpression
  7. LogMostVisitedNavigation
  8. NavigationEntryCommitted
  9. number_of_mouseovers_

// 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/webui/ntp/ntp_user_data_logger.h"

#include "base/metrics/histogram.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/search/most_visited_iframe_source.h"
#include "chrome/browser/search/search.h"
#include "chrome/common/search_urls.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/user_metrics.h"
#include "content/public/browser/web_contents.h"

// Macro to log UMA statistics related to the 8 tiles shown on the NTP.
#define UMA_HISTOGRAM_NTP_TILES(name, sample) \
    UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, 0, 8, 9)

namespace {

// Used to track if suggestions were issued by the client or the server.
enum SuggestionsType {
  CLIENT_SIDE = 0,
  SERVER_SIDE = 1,
  SUGGESTIONS_TYPE_COUNT = 2
};

// Number of Most Visited elements on the NTP for logging purposes.
const int kNumMostVisited = 8;

// Name of the histogram keeping track of Most Visited impressions.
const char kMostVisitedImpressionHistogramName[] =
    "NewTabPage.SuggestionsImpression";

// Format string to generate the name for the histogram keeping track of
// suggestion impressions.
const char kMostVisitedImpressionHistogramWithProvider[] =
    "NewTabPage.SuggestionsImpression.%s";

// Name of the histogram keeping track of Most Visited navigations.
const char kMostVisitedNavigationHistogramName[] =
    "NewTabPage.MostVisited";

// Format string to generate the name for the histogram keeping track of
// suggestion navigations.
const char kMostVisitedNavigationHistogramWithProvider[] =
    "NewTabPage.MostVisited.%s";

}  // namespace

DEFINE_WEB_CONTENTS_USER_DATA_KEY(NTPUserDataLogger);

NTPUserDataLogger::~NTPUserDataLogger() {}

// static
NTPUserDataLogger* NTPUserDataLogger::GetOrCreateFromWebContents(
      content::WebContents* 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/.
  const content::NavigationEntry* entry =
      content->GetController().GetVisibleEntry();
  if (entry)
    logger->ntp_url_ = entry->GetURL();

  return logger;
}

// static
std::string NTPUserDataLogger::GetMostVisitedImpressionHistogramNameForProvider(
    const std::string& provider) {
  return base::StringPrintf(kMostVisitedImpressionHistogramWithProvider,
                            provider.c_str());
}

// static
std::string NTPUserDataLogger::GetMostVisitedNavigationHistogramNameForProvider(
    const std::string& provider) {
  return base::StringPrintf(kMostVisitedNavigationHistogramWithProvider,
                            provider.c_str());
}

void NTPUserDataLogger::EmitNtpStatistics() {
  UMA_HISTOGRAM_COUNTS("NewTabPage.NumberOfMouseOvers", number_of_mouseovers_);
  number_of_mouseovers_ = 0;

  // Only log the following statistics if at least one tile is recorded. This
  // check is required because the statistics are emitted whenever the user
  // changes tab away from the NTP. However, if the user comes back to that NTP
  // later the statistics are not regenerated (i.e. they are all 0). If we log
  // them again we get a strong bias.
  if (number_of_tiles_ > 0) {
    UMA_HISTOGRAM_ENUMERATION(
        "NewTabPage.SuggestionsType",
        has_server_side_suggestions_ ? SERVER_SIDE : CLIENT_SIDE,
        SUGGESTIONS_TYPE_COUNT);
    has_server_side_suggestions_ = false;
    UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfTiles", number_of_tiles_);
    number_of_tiles_ = 0;
    UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfThumbnailTiles",
                            number_of_thumbnail_tiles_);
    number_of_thumbnail_tiles_ = 0;
    UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfGrayTiles",
                            number_of_gray_tiles_);
    number_of_gray_tiles_ = 0;
    UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfExternalTiles",
                            number_of_external_tiles_);
    number_of_external_tiles_ = 0;
    UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfThumbnailErrors",
                            number_of_thumbnail_errors_);
    number_of_thumbnail_errors_ = 0;
    UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfGrayTileFallbacks",
                            number_of_gray_tile_fallbacks_);
    number_of_gray_tile_fallbacks_ = 0;
    UMA_HISTOGRAM_NTP_TILES("NewTabPage.NumberOfExternalTileFallbacks",
                            number_of_external_tile_fallbacks_);
    number_of_external_tile_fallbacks_ = 0;
  }
}

void NTPUserDataLogger::LogEvent(NTPLoggingEventType event) {
  switch (event) {
    case NTP_SERVER_SIDE_SUGGESTION:
      has_server_side_suggestions_ = true;
      break;
    case NTP_CLIENT_SIDE_SUGGESTION:
      // We should never get a mix of server and client side suggestions,
      // otherwise there could be a race condition depending on the order in
      // which the iframes call this method.
      DCHECK(!has_server_side_suggestions_);
      break;
    case NTP_TILE:
      number_of_tiles_++;
      break;
    case NTP_THUMBNAIL_TILE:
      number_of_thumbnail_tiles_++;
      break;
    case NTP_GRAY_TILE:
      number_of_gray_tiles_++;
      break;
    case NTP_EXTERNAL_TILE:
      number_of_external_tiles_++;
      break;
    case NTP_THUMBNAIL_ERROR:
      number_of_thumbnail_errors_++;
      break;
    case NTP_GRAY_TILE_FALLBACK:
      number_of_gray_tile_fallbacks_++;
      break;
    case NTP_EXTERNAL_TILE_FALLBACK:
      number_of_external_tile_fallbacks_++;
      break;
    case NTP_MOUSEOVER:
      number_of_mouseovers_++;
      break;
    default:
      NOTREACHED();
  }
}

void NTPUserDataLogger::LogMostVisitedImpression(
    int position, const base::string16& provider) {
  // Log the Most Visited navigation for navigations that have providers and
  // those that dont.
  UMA_HISTOGRAM_ENUMERATION(kMostVisitedImpressionHistogramName, position,
                            kNumMostVisited);

  // If a provider is specified, log the metric specific to it.
  if (!provider.empty()) {
    // Cannot rely on UMA histograms macro because the name of the histogram is
    // generated dynamically.
    base::HistogramBase* counter = base::LinearHistogram::FactoryGet(
        GetMostVisitedImpressionHistogramNameForProvider(
            base::UTF16ToUTF8(provider)),
        1,
        kNumMostVisited,
        kNumMostVisited + 1,
        base::Histogram::kUmaTargetedHistogramFlag);
    counter->Add(position);
  }
}

void NTPUserDataLogger::LogMostVisitedNavigation(
    int position, const base::string16& provider) {
  // Log the Most Visited navigation for navigations that have providers and
  // those that dont.
  UMA_HISTOGRAM_ENUMERATION(kMostVisitedNavigationHistogramName, position,
                            kNumMostVisited);

  // If a provider is specified, log the metric specific to it.
  if (!provider.empty()) {
    // Cannot rely on UMA histograms macro because the name of the histogram is
    // generated dynamically.
    base::HistogramBase* counter = base::LinearHistogram::FactoryGet(
        GetMostVisitedNavigationHistogramNameForProvider(
            base::UTF16ToUTF8(provider)),
        1,
        kNumMostVisited,
        kNumMostVisited + 1,
        base::Histogram::kUmaTargetedHistogramFlag);
    counter->Add(position);
  }

  // Records the action. This will be available as a time-stamped stream
  // server-side and can be used to compute time-to-long-dwell.
  content::RecordAction(base::UserMetricsAction("MostVisited_Clicked"));
}

// content::WebContentsObserver override
void NTPUserDataLogger::NavigationEntryCommitted(
    const content::LoadCommittedDetails& load_details) {
  if (!load_details.previous_url.is_valid())
    return;

  if (search::MatchesOriginAndPath(ntp_url_, load_details.previous_url)) {
    EmitNtpStatistics();
  }
}

NTPUserDataLogger::NTPUserDataLogger(content::WebContents* contents)
    : content::WebContentsObserver(contents),
      has_server_side_suggestions_(false),
      number_of_tiles_(0),
      number_of_thumbnail_tiles_(0),
      number_of_gray_tiles_(0),
      number_of_external_tiles_(0),
      number_of_thumbnail_errors_(0),
      number_of_gray_tile_fallbacks_(0),
      number_of_external_tile_fallbacks_(0),
      number_of_mouseovers_(0) {
}

/* [<][>][^][v][top][bottom][index][help] */