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.
5 #include "components/omnibox/browser/omnibox_metrics_provider.h"
10 #include "base/logging.h"
11 #include "base/strings/string16.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/string_util.h"
14 #include "components/metrics/metrics_log.h"
15 #include "components/metrics/proto/omnibox_event.pb.h"
16 #include "components/metrics/proto/omnibox_input_type.pb.h"
17 #include "components/omnibox/browser/autocomplete_match.h"
18 #include "components/omnibox/browser/autocomplete_provider.h"
19 #include "components/omnibox/browser/autocomplete_result.h"
20 #include "components/omnibox/browser/omnibox_log.h"
22 using metrics::OmniboxEventProto
;
26 OmniboxEventProto::Suggestion::ResultType
AsOmniboxEventResultType(
27 AutocompleteMatch::Type type
) {
29 case AutocompleteMatchType::URL_WHAT_YOU_TYPED
:
30 return OmniboxEventProto::Suggestion::URL_WHAT_YOU_TYPED
;
31 case AutocompleteMatchType::HISTORY_URL
:
32 return OmniboxEventProto::Suggestion::HISTORY_URL
;
33 case AutocompleteMatchType::HISTORY_TITLE
:
34 return OmniboxEventProto::Suggestion::HISTORY_TITLE
;
35 case AutocompleteMatchType::HISTORY_BODY
:
36 return OmniboxEventProto::Suggestion::HISTORY_BODY
;
37 case AutocompleteMatchType::HISTORY_KEYWORD
:
38 return OmniboxEventProto::Suggestion::HISTORY_KEYWORD
;
39 case AutocompleteMatchType::NAVSUGGEST
:
40 return OmniboxEventProto::Suggestion::NAVSUGGEST
;
41 case AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED
:
42 return OmniboxEventProto::Suggestion::SEARCH_WHAT_YOU_TYPED
;
43 case AutocompleteMatchType::SEARCH_HISTORY
:
44 return OmniboxEventProto::Suggestion::SEARCH_HISTORY
;
45 case AutocompleteMatchType::SEARCH_SUGGEST
:
46 return OmniboxEventProto::Suggestion::SEARCH_SUGGEST
;
47 case AutocompleteMatchType::SEARCH_SUGGEST_ENTITY
:
48 return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_ENTITY
;
49 case AutocompleteMatchType::SEARCH_SUGGEST_TAIL
:
50 return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_TAIL
;
51 case AutocompleteMatchType::SEARCH_SUGGEST_PERSONALIZED
:
52 return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_PERSONALIZED
;
53 case AutocompleteMatchType::SEARCH_SUGGEST_PROFILE
:
54 return OmniboxEventProto::Suggestion::SEARCH_SUGGEST_PROFILE
;
55 case AutocompleteMatchType::CALCULATOR
:
56 return OmniboxEventProto::Suggestion::CALCULATOR
;
57 case AutocompleteMatchType::SEARCH_OTHER_ENGINE
:
58 return OmniboxEventProto::Suggestion::SEARCH_OTHER_ENGINE
;
59 case AutocompleteMatchType::EXTENSION_APP
:
60 return OmniboxEventProto::Suggestion::EXTENSION_APP
;
61 case AutocompleteMatchType::BOOKMARK_TITLE
:
62 return OmniboxEventProto::Suggestion::BOOKMARK_TITLE
;
63 case AutocompleteMatchType::NAVSUGGEST_PERSONALIZED
:
64 return OmniboxEventProto::Suggestion::NAVSUGGEST_PERSONALIZED
;
65 case AutocompleteMatchType::CLIPBOARD
:
66 return OmniboxEventProto::Suggestion::CLIPBOARD
;
67 case AutocompleteMatchType::CONTACT_DEPRECATED
:
68 case AutocompleteMatchType::NUM_TYPES
:
72 return OmniboxEventProto::Suggestion::UNKNOWN_RESULT_TYPE
;
77 OmniboxMetricsProvider::OmniboxMetricsProvider(
78 const base::Callback
<bool(void)>& is_off_the_record_callback
)
79 : is_off_the_record_callback_(is_off_the_record_callback
) {}
81 OmniboxMetricsProvider::~OmniboxMetricsProvider() {
84 void OmniboxMetricsProvider::OnRecordingEnabled() {
85 subscription_
= OmniboxEventGlobalTracker::GetInstance()->RegisterCallback(
86 base::Bind(&OmniboxMetricsProvider::OnURLOpenedFromOmnibox
,
87 base::Unretained(this)));
90 void OmniboxMetricsProvider::OnRecordingDisabled() {
91 subscription_
.reset();
94 void OmniboxMetricsProvider::ProvideGeneralMetrics(
95 metrics::ChromeUserMetricsExtension
* uma_proto
) {
96 uma_proto
->mutable_omnibox_event()->Swap(
97 omnibox_events_cache
.mutable_omnibox_event());
100 void OmniboxMetricsProvider::OnURLOpenedFromOmnibox(OmniboxLog
* log
) {
101 // Do not log events to UMA if the embedder reports that the user is in an
102 // off-the-record context.
103 if (!is_off_the_record_callback_
.Run())
104 RecordOmniboxOpenedURL(*log
);
107 void OmniboxMetricsProvider::RecordOmniboxOpenedURL(const OmniboxLog
& log
) {
108 std::vector
<base::StringPiece16
> terms
= base::SplitStringPiece(
109 log
.text
, base::kWhitespaceUTF16
,
110 base::KEEP_WHITESPACE
, base::SPLIT_WANT_NONEMPTY
);
112 OmniboxEventProto
* omnibox_event
= omnibox_events_cache
.add_omnibox_event();
113 omnibox_event
->set_time(metrics::MetricsLog::GetCurrentTime());
114 if (log
.tab_id
!= -1) {
115 // If we know what tab the autocomplete URL was opened in, log it.
116 omnibox_event
->set_tab_id(log
.tab_id
);
118 omnibox_event
->set_typed_length(log
.text
.length());
119 omnibox_event
->set_just_deleted_text(log
.just_deleted_text
);
120 omnibox_event
->set_num_typed_terms(static_cast<int>(terms
.size()));
121 omnibox_event
->set_selected_index(log
.selected_index
);
122 if (log
.completed_length
!= base::string16::npos
)
123 omnibox_event
->set_completed_length(log
.completed_length
);
124 const base::TimeDelta default_time_delta
=
125 base::TimeDelta::FromMilliseconds(-1);
126 if (log
.elapsed_time_since_user_first_modified_omnibox
!=
127 default_time_delta
) {
128 // Only upload the typing duration if it is set/valid.
129 omnibox_event
->set_typing_duration_ms(
130 log
.elapsed_time_since_user_first_modified_omnibox
.InMilliseconds());
132 if (log
.elapsed_time_since_last_change_to_default_match
!=
133 default_time_delta
) {
134 omnibox_event
->set_duration_since_last_default_match_update_ms(
135 log
.elapsed_time_since_last_change_to_default_match
.InMilliseconds());
137 omnibox_event
->set_current_page_classification(
138 log
.current_page_classification
);
139 omnibox_event
->set_input_type(log
.input_type
);
140 // We consider a paste-and-search/paste-and-go action to have a closed popup
141 // (as explained in omnibox_event.proto) even if it was not, because such
142 // actions ignore the contents of the popup so it doesn't matter that it was
144 omnibox_event
->set_is_popup_open(log
.is_popup_open
&& !log
.is_paste_and_go
);
145 omnibox_event
->set_is_paste_and_go(log
.is_paste_and_go
);
147 for (AutocompleteResult::const_iterator
i(log
.result
.begin());
148 i
!= log
.result
.end(); ++i
) {
149 OmniboxEventProto::Suggestion
* suggestion
= omnibox_event
->add_suggestion();
150 suggestion
->set_provider(i
->provider
->AsOmniboxEventProviderType());
151 suggestion
->set_result_type(AsOmniboxEventResultType(i
->type
));
152 suggestion
->set_relevance(i
->relevance
);
153 if (i
->typed_count
!= -1)
154 suggestion
->set_typed_count(i
->typed_count
);
156 for (ProvidersInfo::const_iterator
i(log
.providers_info
.begin());
157 i
!= log
.providers_info
.end(); ++i
) {
158 OmniboxEventProto::ProviderInfo
* provider_info
=
159 omnibox_event
->add_provider_info();
160 provider_info
->CopyFrom(*i
);