Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(638)

Side by Side Diff: ios/chrome/browser/metrics/first_user_action_recorder.cc

Issue 2585233003: Upstream Chrome on iOS source code [2/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2013 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 "ios/chrome/browser/metrics/first_user_action_recorder.h"
6
7 #include "base/bind.h"
8 #include "base/location.h"
9 #include "base/metrics/histogram.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/threading/thread_task_runner_handle.h"
13 #include "ios/chrome/browser/ui/ui_util.h"
14 #include "ios/web/public/web_thread.h"
15
16 const char* kFirstUserActionNewTaskHistogramName[] = {
17 "FirstUserAction.BackgroundTimeNewTaskHandset",
18 "FirstUserAction.BackgroundTimeNewTaskTablet",
19 };
20 const char* kFirstUserActionContinuationHistogramName[] = {
21 "FirstUserAction.BackgroundTimeContinuationHandset",
22 "FirstUserAction.BackgroundTimeContinuationTablet",
23 };
24 const char* kFirstUserActionExpirationHistogramName[] = {
25 "FirstUserAction.BackgroundTimeExpirationHandset",
26 "FirstUserAction.BackgroundTimeExpirationTablet",
27 };
28 const char* kFirstUserActionTypeHistogramName[] = {
29 "FirstUserAction.HandsetUserActionType",
30 "FirstUserAction.TabletUserActionType",
31 };
32
33 namespace {
34 // A list of actions that don't provide information about the user starting a
35 // task or continuing an existing task.
36 const char* kIgnoredActions[] = {
37 "MobileOmniboxUse",
38 "MobileBreakpadUploadAttempt",
39 "MobileFirstUserAction_Continuation",
40 "MobileFirstUserAction_Expiration",
41 "MobileFirstUserAction_NewTask",
42 "MobileMenuCloseAllTabs",
43 "MobileMenuCloseAllIncognitoTabs",
44 "MobileMenuCloseTab",
45 "MobileNewTabOpened",
46 "MobileTabClosed",
47 "MobileTabStripCloseTab",
48 "MobilePageLoaded",
49 "MobilePageLoadedWithKeyboard",
50 "MobileStackViewCloseTab",
51 "MobileToolbarShowMenu",
52 "MobileToolbarShowStackView",
53 };
54
55 // A list of actions that should be 'rethrown' because subsequent actions may
56 // be more indicative of the first user action type. 'Rethrowing' an action
57 // puts a call to OnUserAction in the message queue so it is processed after
58 // any other actions currently in the message queue.
59 const char* kRethrownActions[] = {
60 "MobileTabSwitched",
61 };
62
63 // A list of actions that indicate a new task has been started.
64 const char* kNewTaskActions[] = {
65 "MobileMenuAllBookmarks", "MobileMenuHistory",
66 "MobileMenuNewIncognitoTab", "MobileMenuNewTab",
67 "MobileMenuOpenTabs", "MobileMenuVoiceSearch",
68 "MobileNTPBookmark", "MobileNTPForeignSession",
69 "MobileNTPMostVisited", "MobileNTPShowBookmarks",
70 "MobileNTPShowMostVisited", "MobileNTPShowOpenTabs",
71 "MobileNTPSwitchToBookmarks", "MobileNTPSwitchToMostVisited",
72 "MobileNTPSwitchToOpenTabs", "MobileTabStripNewTab",
73 "MobileToolbarNewTab", "MobileToolbarStackViewNewTab",
74 "MobileToolbarVoiceSearch", "OmniboxInputInProgress",
75 };
76
77 // Min and max values (in minutes) for the buckets in the duration histograms.
78 const int kDurationHistogramMin = 5;
79 const int kDurationHistogramMax = 48 * 60;
80
81 // Number of buckets in the duration histograms.
82 const int kDurationHistogramBucketCount = 50;
83
84 } // namespace
85
86 FirstUserActionRecorder::FirstUserActionRecorder(
87 base::TimeDelta background_duration)
88 : device_family_(IsIPadIdiom() ? TABLET : HANDSET),
89 recorded_action_(false),
90 action_pending_(false),
91 background_duration_(background_duration),
92 action_callback_(base::Bind(&FirstUserActionRecorder::OnUserAction,
93 base::Unretained(this))) {
94 base::SetRecordActionTaskRunner(
95 web::WebThread::GetTaskRunnerForThread(web::WebThread::UI));
96 base::AddActionCallback(action_callback_);
97 }
98
99 FirstUserActionRecorder::~FirstUserActionRecorder() {
100 base::RemoveActionCallback(action_callback_);
101 }
102
103 void FirstUserActionRecorder::Expire() {
104 std::string log_message = "Recording 'Expiration' for first user action type";
105 RecordAction(EXPIRATION, log_message);
106 }
107
108 void FirstUserActionRecorder::RecordStartOnNTP() {
109 std::string log_message =
110 "Recording 'Start on NTP' for first user action type";
111 RecordAction(START_ON_NTP, log_message);
112 }
113
114 void FirstUserActionRecorder::OnUserAction(const std::string& action_name) {
115 if (ShouldProcessAction(action_name)) {
116 if (ArrayContainsString(kNewTaskActions, arraysize(kNewTaskActions),
117 action_name.c_str())) {
118 std::string log_message = base::StringPrintf(
119 "Recording 'New task' for first user action type"
120 " (user action: %s)",
121 action_name.c_str());
122 RecordAction(NEW_TASK, log_message);
123 } else {
124 std::string log_message = base::StringPrintf(
125 "Recording 'Continuation' for first user action "
126 " type (user action: %s)",
127 action_name.c_str());
128 RecordAction(CONTINUATION, log_message);
129 }
130 }
131 }
132
133 void FirstUserActionRecorder::RecordAction(
134 const FirstUserActionType& action_type,
135 const std::string& log_message) {
136 if (!recorded_action_) {
137 DVLOG(1) << log_message
138 << " (background duration: " << background_duration_.InMinutes()
139 << " minutes)";
140 UMA_HISTOGRAM_ENUMERATION(kFirstUserActionTypeHistogramName[device_family_],
141 action_type, FIRST_USER_ACTION_TYPE_COUNT);
142 recorded_action_ = true;
143 switch (action_type) {
144 case NEW_TASK:
145 UMA_HISTOGRAM_CUSTOM_COUNTS(
146 kFirstUserActionNewTaskHistogramName[device_family_],
147 background_duration_.InMinutes(), kDurationHistogramMin,
148 kDurationHistogramMax, kDurationHistogramBucketCount);
149 break;
150 case CONTINUATION:
151 UMA_HISTOGRAM_CUSTOM_COUNTS(
152 kFirstUserActionContinuationHistogramName[device_family_],
153 background_duration_.InMinutes(), kDurationHistogramMin,
154 kDurationHistogramMax, kDurationHistogramBucketCount);
155 break;
156 case EXPIRATION:
157 UMA_HISTOGRAM_CUSTOM_COUNTS(
158 kFirstUserActionExpirationHistogramName[device_family_],
159 background_duration_.InMinutes(), kDurationHistogramMin,
160 kDurationHistogramMax, kDurationHistogramBucketCount);
161 break;
162 case START_ON_NTP:
163 break;
164 default:
165 NOTREACHED();
166 break;
167 }
168 }
169 }
170
171 bool FirstUserActionRecorder::ShouldProcessAction(
172 const std::string& action_name) {
173 if (recorded_action_)
174 return false;
175
176 if (!action_pending_ &&
177 ArrayContainsString(kRethrownActions, arraysize(kRethrownActions),
178 action_name.c_str())) {
179 base::ThreadTaskRunnerHandle::Get()->PostTask(
180 FROM_HERE, base::Bind(&FirstUserActionRecorder::OnUserAction,
181 base::Unretained(this), action_name));
182 action_pending_ = true;
183 return false;
184 }
185
186 // Processed actions must either start with 'Mobile' or be in the
187 // |new_task_actions_| whitelist.
188 bool known_mobile_action =
189 base::StartsWith(action_name, "Mobile", base::CompareCase::SENSITIVE) ||
190 ArrayContainsString(kNewTaskActions, arraysize(kNewTaskActions),
191 action_name.c_str());
192
193 return known_mobile_action &&
194 !ArrayContainsString(kIgnoredActions, arraysize(kIgnoredActions),
195 action_name.c_str());
196 }
197
198 bool FirstUserActionRecorder::ArrayContainsString(const char* to_search[],
199 const size_t to_search_size,
200 const char* to_find) {
201 for (size_t i = 0; i < to_search_size; ++i) {
202 if (strcmp(to_find, to_search[i]) == 0)
203 return true;
204 }
205 return false;
206 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698