OLD | NEW |
(Empty) | |
| 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/autocomplete/autocomplete_input.h" |
| 13 #include "chrome/browser/autocomplete/autocomplete_match.h" |
| 14 #include "chrome/browser/autocomplete/autocomplete_provider.h" |
| 15 #include "chrome/browser/autocomplete/autocomplete_result.h" |
| 16 #include "chrome/browser/chrome_notification_types.h" |
| 17 #include "chrome/browser/omnibox/omnibox_log.h" |
| 18 #include "chrome/browser/ui/browser_otr_state.h" |
| 19 #include "components/metrics/metrics_log_base.h" |
| 20 #include "content/public/browser/notification_service.h" |
| 21 |
| 22 using metrics::OmniboxEventProto; |
| 23 |
| 24 namespace { |
| 25 |
| 26 OmniboxEventProto::InputType AsOmniboxEventInputType( |
| 27 AutocompleteInput::Type type) { |
| 28 switch (type) { |
| 29 case AutocompleteInput::INVALID: |
| 30 return OmniboxEventProto::INVALID; |
| 31 case AutocompleteInput::UNKNOWN: |
| 32 return OmniboxEventProto::UNKNOWN; |
| 33 case AutocompleteInput::URL: |
| 34 return OmniboxEventProto::URL; |
| 35 case AutocompleteInput::QUERY: |
| 36 return OmniboxEventProto::QUERY; |
| 37 case AutocompleteInput::FORCED_QUERY: |
| 38 return OmniboxEventProto::FORCED_QUERY; |
| 39 } |
| 40 NOTREACHED(); |
| 41 return OmniboxEventProto::INVALID; |
| 42 } |
| 43 |
| 44 OmniboxEventProto::Suggestion::ResultType AsOmniboxEventResultType( |
| 45 AutocompleteMatch::Type type) { |
| 46 switch (type) { |
| 47 case AutocompleteMatchType::URL_WHAT_YOU_TYPED: |
| 48 return OmniboxEventProto::Suggestion::URL_WHAT_YOU_TYPED; |
| 49 case AutocompleteMatchType::HISTORY_URL: |
| 50 return OmniboxEventProto::Suggestion::HISTORY_URL; |
| 51 case AutocompleteMatchType::HISTORY_TITLE: |
| 52 return OmniboxEventProto::Suggestion::HISTORY_TITLE; |
| 53 case AutocompleteMatchType::HISTORY_BODY: |
| 54 return OmniboxEventProto::Suggestion::HISTORY_BODY; |
| 55 case AutocompleteMatchType::HISTORY_KEYWORD: |
| 56 return OmniboxEventProto::Suggestion::HISTORY_KEYWORD; |
| 57 case AutocompleteMatchType::NAVSUGGEST: |
| 58 return OmniboxEventProto::Suggestion::NAVSUGGEST; |
| 59 case AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED: |
| 60 return OmniboxEventProto::Suggestion::SEARCH_WHAT_YOU_TYPED; |
| 61 case AutocompleteMatchType::SEARCH_HISTORY: |
| 62 return OmniboxEventProto::Suggestion::SEARCH_HISTORY; |
| 63 case AutocompleteMatchType::SEARCH_SUGGEST: |
| 64 return OmniboxEventProto::Suggestion::SEARCH_SUGGEST; |
| 65 case AutocompleteMatchType::SEARCH_SUGGEST_ENTITY: |
| 66 return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_ENTITY; |
| 67 case AutocompleteMatchType::SEARCH_SUGGEST_INFINITE: |
| 68 return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_INFINITE; |
| 69 case AutocompleteMatchType::SEARCH_SUGGEST_PERSONALIZED: |
| 70 return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_PERSONALIZED; |
| 71 case AutocompleteMatchType::SEARCH_SUGGEST_PROFILE: |
| 72 return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_PROFILE; |
| 73 case AutocompleteMatchType::SEARCH_OTHER_ENGINE: |
| 74 return OmniboxEventProto::Suggestion::SEARCH_OTHER_ENGINE; |
| 75 case AutocompleteMatchType::EXTENSION_APP: |
| 76 return OmniboxEventProto::Suggestion::EXTENSION_APP; |
| 77 case AutocompleteMatchType::BOOKMARK_TITLE: |
| 78 return OmniboxEventProto::Suggestion::BOOKMARK_TITLE; |
| 79 case AutocompleteMatchType::NAVSUGGEST_PERSONALIZED: |
| 80 return OmniboxEventProto::Suggestion::NAVSUGGEST_PERSONALIZED; |
| 81 case AutocompleteMatchType::CONTACT_DEPRECATED: |
| 82 case AutocompleteMatchType::NUM_TYPES: |
| 83 break; |
| 84 } |
| 85 NOTREACHED(); |
| 86 return OmniboxEventProto::Suggestion::UNKNOWN_RESULT_TYPE; |
| 87 } |
| 88 |
| 89 OmniboxEventProto::PageClassification AsOmniboxEventPageClassification( |
| 90 AutocompleteInput::PageClassification page_classification) { |
| 91 switch (page_classification) { |
| 92 case AutocompleteInput::INVALID_SPEC: |
| 93 return OmniboxEventProto::INVALID_SPEC; |
| 94 case AutocompleteInput::NTP: |
| 95 return OmniboxEventProto::NTP; |
| 96 case AutocompleteInput::BLANK: |
| 97 return OmniboxEventProto::BLANK; |
| 98 case AutocompleteInput::HOME_PAGE: |
| 99 return OmniboxEventProto::HOME_PAGE; |
| 100 case AutocompleteInput::OTHER: |
| 101 return OmniboxEventProto::OTHER; |
| 102 case AutocompleteInput::SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT: |
| 103 return OmniboxEventProto:: |
| 104 SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT; |
| 105 case AutocompleteInput::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS: |
| 106 return OmniboxEventProto::INSTANT_NTP_WITH_OMNIBOX_AS_STARTING_FOCUS; |
| 107 case AutocompleteInput::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS: |
| 108 return OmniboxEventProto::INSTANT_NTP_WITH_FAKEBOX_AS_STARTING_FOCUS; |
| 109 case AutocompleteInput::SEARCH_RESULT_PAGE_NO_SEARCH_TERM_REPLACEMENT: |
| 110 return OmniboxEventProto:: |
| 111 SEARCH_RESULT_PAGE_NO_SEARCH_TERM_REPLACEMENT; |
| 112 } |
| 113 NOTREACHED(); |
| 114 return OmniboxEventProto::INVALID_SPEC; |
| 115 } |
| 116 |
| 117 } // namespace |
| 118 |
| 119 OmniboxMetricsProvider::OmniboxMetricsProvider() { |
| 120 } |
| 121 |
| 122 OmniboxMetricsProvider::~OmniboxMetricsProvider() { |
| 123 } |
| 124 |
| 125 void OmniboxMetricsProvider::OnRecordingEnabled() { |
| 126 registrar_.Add(this, chrome::NOTIFICATION_OMNIBOX_OPENED_URL, |
| 127 content::NotificationService::AllSources()); |
| 128 } |
| 129 |
| 130 void OmniboxMetricsProvider::OnRecordingDisabled() { |
| 131 registrar_.RemoveAll(); |
| 132 } |
| 133 |
| 134 void OmniboxMetricsProvider::ProvideGeneralMetrics( |
| 135 metrics::ChromeUserMetricsExtension* uma_proto) { |
| 136 uma_proto->mutable_omnibox_event()->Swap( |
| 137 omnibox_events_cache.mutable_omnibox_event()); |
| 138 } |
| 139 |
| 140 void OmniboxMetricsProvider::Observe( |
| 141 int type, |
| 142 const content::NotificationSource& source, |
| 143 const content::NotificationDetails& details) { |
| 144 DCHECK_EQ(chrome::NOTIFICATION_OMNIBOX_OPENED_URL, type); |
| 145 |
| 146 // We simply don't log events to UMA if there is a single incognito |
| 147 // session visible. In the future, it may be worth revisiting this to |
| 148 // still log events from non-incognito sessions. |
| 149 if (!chrome::IsOffTheRecordSessionActive()) |
| 150 RecordOmniboxOpenedURL(*content::Details<OmniboxLog>(details).ptr()); |
| 151 } |
| 152 |
| 153 void OmniboxMetricsProvider::RecordOmniboxOpenedURL(const OmniboxLog& log) { |
| 154 std::vector<base::string16> terms; |
| 155 const int num_terms = |
| 156 static_cast<int>(Tokenize(log.text, base::kWhitespaceUTF16, &terms)); |
| 157 |
| 158 OmniboxEventProto* omnibox_event = omnibox_events_cache.add_omnibox_event(); |
| 159 omnibox_event->set_time(metrics::MetricsLogBase::GetCurrentTime()); |
| 160 if (log.tab_id != -1) { |
| 161 // If we know what tab the autocomplete URL was opened in, log it. |
| 162 omnibox_event->set_tab_id(log.tab_id); |
| 163 } |
| 164 omnibox_event->set_typed_length(log.text.length()); |
| 165 omnibox_event->set_just_deleted_text(log.just_deleted_text); |
| 166 omnibox_event->set_num_typed_terms(num_terms); |
| 167 omnibox_event->set_selected_index(log.selected_index); |
| 168 if (log.completed_length != base::string16::npos) |
| 169 omnibox_event->set_completed_length(log.completed_length); |
| 170 const base::TimeDelta default_time_delta = |
| 171 base::TimeDelta::FromMilliseconds(-1); |
| 172 if (log.elapsed_time_since_user_first_modified_omnibox != |
| 173 default_time_delta) { |
| 174 // Only upload the typing duration if it is set/valid. |
| 175 omnibox_event->set_typing_duration_ms( |
| 176 log.elapsed_time_since_user_first_modified_omnibox.InMilliseconds()); |
| 177 } |
| 178 if (log.elapsed_time_since_last_change_to_default_match != |
| 179 default_time_delta) { |
| 180 omnibox_event->set_duration_since_last_default_match_update_ms( |
| 181 log.elapsed_time_since_last_change_to_default_match.InMilliseconds()); |
| 182 } |
| 183 omnibox_event->set_current_page_classification( |
| 184 AsOmniboxEventPageClassification(log.current_page_classification)); |
| 185 omnibox_event->set_input_type(AsOmniboxEventInputType(log.input_type)); |
| 186 // We consider a paste-and-search/paste-and-go action to have a closed popup |
| 187 // (as explained in omnibox_event.proto) even if it was not, because such |
| 188 // actions ignore the contents of the popup so it doesn't matter that it was |
| 189 // open. |
| 190 const bool consider_popup_open = log.is_popup_open && !log.is_paste_and_go; |
| 191 omnibox_event->set_is_popup_open(consider_popup_open); |
| 192 omnibox_event->set_is_paste_and_go(log.is_paste_and_go); |
| 193 if (consider_popup_open) { |
| 194 omnibox_event->set_is_top_result_hidden_in_dropdown( |
| 195 log.result.ShouldHideTopMatch()); |
| 196 } |
| 197 |
| 198 for (AutocompleteResult::const_iterator i(log.result.begin()); |
| 199 i != log.result.end(); ++i) { |
| 200 OmniboxEventProto::Suggestion* suggestion = omnibox_event->add_suggestion(); |
| 201 suggestion->set_provider(i->provider->AsOmniboxEventProviderType()); |
| 202 suggestion->set_result_type(AsOmniboxEventResultType(i->type)); |
| 203 suggestion->set_relevance(i->relevance); |
| 204 if (i->typed_count != -1) |
| 205 suggestion->set_typed_count(i->typed_count); |
| 206 suggestion->set_is_starred(i->starred); |
| 207 } |
| 208 for (ProvidersInfo::const_iterator i(log.providers_info.begin()); |
| 209 i != log.providers_info.end(); ++i) { |
| 210 OmniboxEventProto::ProviderInfo* provider_info = |
| 211 omnibox_event->add_provider_info(); |
| 212 provider_info->CopyFrom(*i); |
| 213 } |
| 214 } |
OLD | NEW |