Home | History | Annotate | Download | only in metrics
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/metrics/omnibox_metrics_provider.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/logging.h"
     10 #include "base/strings/string16.h"
     11 #include "base/strings/string_util.h"
     12 #include "chrome/browser/chrome_notification_types.h"
     13 #include "chrome/browser/omnibox/omnibox_log.h"
     14 #include "chrome/browser/ui/browser_otr_state.h"
     15 #include "components/metrics/metrics_log.h"
     16 #include "components/metrics/proto/omnibox_event.pb.h"
     17 #include "components/metrics/proto/omnibox_input_type.pb.h"
     18 #include "components/omnibox/autocomplete_match.h"
     19 #include "components/omnibox/autocomplete_provider.h"
     20 #include "components/omnibox/autocomplete_result.h"
     21 #include "content/public/browser/notification_service.h"
     22 
     23 using metrics::OmniboxEventProto;
     24 
     25 namespace {
     26 
     27 OmniboxEventProto::Suggestion::ResultType AsOmniboxEventResultType(
     28     AutocompleteMatch::Type type) {
     29   switch (type) {
     30     case AutocompleteMatchType::URL_WHAT_YOU_TYPED:
     31       return OmniboxEventProto::Suggestion::URL_WHAT_YOU_TYPED;
     32     case AutocompleteMatchType::HISTORY_URL:
     33       return OmniboxEventProto::Suggestion::HISTORY_URL;
     34     case AutocompleteMatchType::HISTORY_TITLE:
     35       return OmniboxEventProto::Suggestion::HISTORY_TITLE;
     36     case AutocompleteMatchType::HISTORY_BODY:
     37       return OmniboxEventProto::Suggestion::HISTORY_BODY;
     38     case AutocompleteMatchType::HISTORY_KEYWORD:
     39       return OmniboxEventProto::Suggestion::HISTORY_KEYWORD;
     40     case AutocompleteMatchType::NAVSUGGEST:
     41       return OmniboxEventProto::Suggestion::NAVSUGGEST;
     42     case AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED:
     43       return OmniboxEventProto::Suggestion::SEARCH_WHAT_YOU_TYPED;
     44     case AutocompleteMatchType::SEARCH_HISTORY:
     45       return OmniboxEventProto::Suggestion::SEARCH_HISTORY;
     46     case AutocompleteMatchType::SEARCH_SUGGEST:
     47       return OmniboxEventProto::Suggestion::SEARCH_SUGGEST;
     48     case AutocompleteMatchType::SEARCH_SUGGEST_ENTITY:
     49       return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_ENTITY;
     50     case AutocompleteMatchType::SEARCH_SUGGEST_INFINITE:
     51       return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_INFINITE;
     52     case AutocompleteMatchType::SEARCH_SUGGEST_PERSONALIZED:
     53       return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_PERSONALIZED;
     54     case AutocompleteMatchType::SEARCH_SUGGEST_PROFILE:
     55       return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_PROFILE;
     56     case AutocompleteMatchType::SEARCH_SUGGEST_ANSWER:
     57       return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_ANSWER;
     58     case AutocompleteMatchType::SEARCH_OTHER_ENGINE:
     59       return OmniboxEventProto::Suggestion::SEARCH_OTHER_ENGINE;
     60     case AutocompleteMatchType::EXTENSION_APP:
     61       return OmniboxEventProto::Suggestion::EXTENSION_APP;
     62     case AutocompleteMatchType::BOOKMARK_TITLE:
     63       return OmniboxEventProto::Suggestion::BOOKMARK_TITLE;
     64     case AutocompleteMatchType::NAVSUGGEST_PERSONALIZED:
     65       return OmniboxEventProto::Suggestion::NAVSUGGEST_PERSONALIZED;
     66     case AutocompleteMatchType::CONTACT_DEPRECATED:
     67     case AutocompleteMatchType::NUM_TYPES:
     68       break;
     69   }
     70   NOTREACHED();
     71   return OmniboxEventProto::Suggestion::UNKNOWN_RESULT_TYPE;
     72 }
     73 
     74 }  // namespace
     75 
     76 OmniboxMetricsProvider::OmniboxMetricsProvider() {
     77 }
     78 
     79 OmniboxMetricsProvider::~OmniboxMetricsProvider() {
     80 }
     81 
     82 void OmniboxMetricsProvider::OnRecordingEnabled() {
     83   registrar_.Add(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL,
     84                  content::NotificationService::AllSources());
     85 }
     86 
     87 void OmniboxMetricsProvider::OnRecordingDisabled() {
     88   registrar_.RemoveAll();
     89 }
     90 
     91 void OmniboxMetricsProvider::ProvideGeneralMetrics(
     92     metrics::ChromeUserMetricsExtension* uma_proto) {
     93   uma_proto->mutable_omnibox_event()->Swap(
     94       omnibox_events_cache.mutable_omnibox_event());
     95 }
     96 
     97 void OmniboxMetricsProvider::Observe(
     98     int type,
     99     const content::NotificationSource& source,
    100     const content::NotificationDetails& details) {
    101   DCHECK_EQ(chrome::NOTIFICATION_OMNIBOX_OPENED_URL, type);
    102 
    103   // We simply don't log events to UMA if there is a single incognito
    104   // session visible. In the future, it may be worth revisiting this to
    105   // still log events from non-incognito sessions.
    106   if (!chrome::IsOffTheRecordSessionActive())
    107     RecordOmniboxOpenedURL(*content::Details<OmniboxLog>(details).ptr());
    108 }
    109 
    110 void OmniboxMetricsProvider::RecordOmniboxOpenedURL(const OmniboxLog& log) {
    111   std::vector<base::string16> terms;
    112   const int num_terms =
    113       static_cast<int>(Tokenize(log.text, base::kWhitespaceUTF16, &terms));
    114 
    115   OmniboxEventProto* omnibox_event = omnibox_events_cache.add_omnibox_event();
    116   omnibox_event->set_time(metrics::MetricsLog::GetCurrentTime());
    117   if (log.tab_id != -1) {
    118     // If we know what tab the autocomplete URL was opened in, log it.
    119     omnibox_event->set_tab_id(log.tab_id);
    120   }
    121   omnibox_event->set_typed_length(log.text.length());
    122   omnibox_event->set_just_deleted_text(log.just_deleted_text);
    123   omnibox_event->set_num_typed_terms(num_terms);
    124   omnibox_event->set_selected_index(log.selected_index);
    125   if (log.completed_length != base::string16::npos)
    126     omnibox_event->set_completed_length(log.completed_length);
    127   const base::TimeDelta default_time_delta =
    128       base::TimeDelta::FromMilliseconds(-1);
    129   if (log.elapsed_time_since_user_first_modified_omnibox !=
    130       default_time_delta) {
    131     // Only upload the typing duration if it is set/valid.
    132     omnibox_event->set_typing_duration_ms(
    133         log.elapsed_time_since_user_first_modified_omnibox.InMilliseconds());
    134   }
    135   if (log.elapsed_time_since_last_change_to_default_match !=
    136       default_time_delta) {
    137     omnibox_event->set_duration_since_last_default_match_update_ms(
    138         log.elapsed_time_since_last_change_to_default_match.InMilliseconds());
    139   }
    140   omnibox_event->set_current_page_classification(
    141       log.current_page_classification);
    142   omnibox_event->set_input_type(log.input_type);
    143   // We consider a paste-and-search/paste-and-go action to have a closed popup
    144   // (as explained in omnibox_event.proto) even if it was not, because such
    145   // actions ignore the contents of the popup so it doesn't matter that it was
    146   // open.
    147   const bool consider_popup_open = log.is_popup_open && !log.is_paste_and_go;
    148   omnibox_event->set_is_popup_open(consider_popup_open);
    149   omnibox_event->set_is_paste_and_go(log.is_paste_and_go);
    150   if (consider_popup_open) {
    151     omnibox_event->set_is_top_result_hidden_in_dropdown(
    152         log.result.ShouldHideTopMatch());
    153   }
    154 
    155   for (AutocompleteResult::const_iterator i(log.result.begin());
    156        i != log.result.end(); ++i) {
    157     OmniboxEventProto::Suggestion* suggestion = omnibox_event->add_suggestion();
    158     suggestion->set_provider(i->provider->AsOmniboxEventProviderType());
    159     suggestion->set_result_type(AsOmniboxEventResultType(i->type));
    160     suggestion->set_relevance(i->relevance);
    161     if (i->typed_count != -1)
    162       suggestion->set_typed_count(i->typed_count);
    163   }
    164   for (ProvidersInfo::const_iterator i(log.providers_info.begin());
    165        i != log.providers_info.end(); ++i) {
    166     OmniboxEventProto::ProviderInfo* provider_info =
    167         omnibox_event->add_provider_info();
    168     provider_info->CopyFrom(*i);
    169   }
    170 }
    171