OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/ui/views/session_crashed_bubble_view.h" | 5 #include "chrome/browser/ui/views/session_crashed_bubble_view.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
11 #include "base/command_line.h" | 11 #include "base/command_line.h" |
12 #include "base/metrics/field_trial.h" | 12 #include "base/metrics/field_trial.h" |
13 #include "base/metrics/histogram.h" | |
13 #include "base/prefs/pref_service.h" | 14 #include "base/prefs/pref_service.h" |
14 #include "chrome/browser/browser_process.h" | 15 #include "chrome/browser/browser_process.h" |
15 #include "chrome/browser/chrome_notification_types.h" | 16 #include "chrome/browser/chrome_notification_types.h" |
16 #include "chrome/browser/sessions/session_restore.h" | 17 #include "chrome/browser/sessions/session_restore.h" |
17 #include "chrome/browser/ui/browser_list.h" | 18 #include "chrome/browser/ui/browser_list.h" |
18 #include "chrome/browser/ui/browser_list_observer.h" | 19 #include "chrome/browser/ui/browser_list_observer.h" |
19 #include "chrome/browser/ui/options/options_util.h" | 20 #include "chrome/browser/ui/options/options_util.h" |
20 #include "chrome/browser/ui/startup/session_crashed_bubble.h" | 21 #include "chrome/browser/ui/startup/session_crashed_bubble.h" |
21 #include "chrome/browser/ui/startup/startup_browser_creator_impl.h" | 22 #include "chrome/browser/ui/startup/startup_browser_creator_impl.h" |
22 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 23 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
58 | 59 |
59 // The color of the text and background of the sub panel to offer UMA optin. | 60 // The color of the text and background of the sub panel to offer UMA optin. |
60 // These values match the BookmarkSyncPromoView colors. | 61 // These values match the BookmarkSyncPromoView colors. |
61 const SkColor kBackgroundColor = SkColorSetRGB(245, 245, 245); | 62 const SkColor kBackgroundColor = SkColorSetRGB(245, 245, 245); |
62 const SkColor kTextColor = SkColorSetRGB(102, 102, 102); | 63 const SkColor kTextColor = SkColorSetRGB(102, 102, 102); |
63 | 64 |
64 // The Finch study name and group name that enables session crashed bubble UI. | 65 // The Finch study name and group name that enables session crashed bubble UI. |
65 const char kEnableBubbleUIFinchName[] = "EnableSessionCrashedBubbleUI"; | 66 const char kEnableBubbleUIFinchName[] = "EnableSessionCrashedBubbleUI"; |
66 const char kEnableBubbleUIGroupEnabled[] = "Enabled"; | 67 const char kEnableBubbleUIGroupEnabled[] = "Enabled"; |
67 | 68 |
69 enum SessionCrashedBubbleHistogramValue { | |
70 SESSION_CRASHED_BUBBLE_SHOWN, | |
71 SESSION_CRASHED_BUBBLE_ERROR, | |
72 SESSION_CRASHED_BUBBLE_RESTORED, | |
73 SESSION_CRASHED_BUBBLE_ALREADY_UMA_OPTIN, | |
jwd
2014/07/09 15:37:52
Is this being used anywhere anymore?
yao
2014/07/09 15:47:03
Done.
| |
74 SESSION_CRASHED_BUBBLE_UMA_OPTIN, | |
75 SESSION_CRASHED_BUBBLE_HELP, | |
76 SESSION_CRASHED_BUBBLE_IGNORED, | |
77 SESSION_CRASHED_BUBBLE_MAX, | |
78 }; | |
79 | |
80 void RecordBubbleHistogramValue(SessionCrashedBubbleHistogramValue value) { | |
81 UMA_HISTOGRAM_ENUMERATION( | |
82 "SessionCrashed.Bubble", value, SESSION_CRASHED_BUBBLE_MAX); | |
83 } | |
84 | |
68 // Whether or not the bubble UI should be used. | 85 // Whether or not the bubble UI should be used. |
69 bool IsBubbleUIEnabled() { | 86 bool IsBubbleUIEnabled() { |
70 const base::CommandLine& command_line = *CommandLine::ForCurrentProcess(); | 87 const base::CommandLine& command_line = *CommandLine::ForCurrentProcess(); |
71 if (command_line.HasSwitch(switches::kDisableSessionCrashedBubble)) | 88 if (command_line.HasSwitch(switches::kDisableSessionCrashedBubble)) |
72 return false; | 89 return false; |
73 if (command_line.HasSwitch(switches::kEnableSessionCrashedBubble)) | 90 if (command_line.HasSwitch(switches::kEnableSessionCrashedBubble)) |
74 return true; | 91 return true; |
75 const std::string group_name = base::FieldTrialList::FindFullName( | 92 const std::string group_name = base::FieldTrialList::FindFullName( |
76 kEnableBubbleUIFinchName); | 93 kEnableBubbleUIFinchName); |
77 return group_name == kEnableBubbleUIGroupEnabled; | 94 return group_name == kEnableBubbleUIGroupEnabled; |
78 } | 95 } |
79 | 96 |
97 // Will be passed in as a callback function to BubbleFrameView. Before the | |
98 // bubble is closed (by the close button), collect the usage stats. | |
99 void BubbleToBeClosed() { | |
100 RecordBubbleHistogramValue(SESSION_CRASHED_BUBBLE_IGNORED); | |
101 } | |
102 | |
80 } // namespace | 103 } // namespace |
81 | 104 |
82 // A helper class that listens to browser removal event. | 105 // A helper class that listens to browser removal event. |
83 class SessionCrashedBubbleView::BrowserRemovalObserver | 106 class SessionCrashedBubbleView::BrowserRemovalObserver |
84 : public chrome::BrowserListObserver { | 107 : public chrome::BrowserListObserver { |
85 public: | 108 public: |
86 explicit BrowserRemovalObserver(Browser* browser) : browser_(browser) { | 109 explicit BrowserRemovalObserver(Browser* browser) : browser_(browser) { |
87 DCHECK(browser_); | 110 DCHECK(browser_); |
88 BrowserList::AddObserver(this); | 111 BrowserList::AddObserver(this); |
89 } | 112 } |
(...skipping 21 matching lines...) Expand all Loading... | |
111 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 134 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
112 if (browser->profile()->IsOffTheRecord()) | 135 if (browser->profile()->IsOffTheRecord()) |
113 return; | 136 return; |
114 | 137 |
115 // Observes browser removal event and will be deallocated in ShowForReal. | 138 // Observes browser removal event and will be deallocated in ShowForReal. |
116 scoped_ptr<BrowserRemovalObserver> browser_observer( | 139 scoped_ptr<BrowserRemovalObserver> browser_observer( |
117 new BrowserRemovalObserver(browser)); | 140 new BrowserRemovalObserver(browser)); |
118 | 141 |
119 // Stats collection only applies to Google Chrome builds. | 142 // Stats collection only applies to Google Chrome builds. |
120 #if defined(GOOGLE_CHROME_BUILD) | 143 #if defined(GOOGLE_CHROME_BUILD) |
121 // Schedule a task to run ShouldOfferMetricsReporting() on FILE thread, since | 144 // Schedule a task to run GoogleUpdateSettings::GetCollectStatsConsent() on |
122 // GoogleUpdateSettings::GetCollectStatsConsent() does IO. Then, call | 145 // FILE thread, since it does IO. Then, call |
123 // SessionCrashedBubbleView::ShowForReal with the result. | 146 // SessionCrashedBubbleView::ShowForReal with the result. |
124 content::BrowserThread::PostTaskAndReplyWithResult( | 147 content::BrowserThread::PostTaskAndReplyWithResult( |
125 content::BrowserThread::FILE, | 148 content::BrowserThread::FILE, |
126 FROM_HERE, | 149 FROM_HERE, |
127 base::Bind(&GoogleUpdateSettings::GetCollectStatsConsent), | 150 base::Bind(&GoogleUpdateSettings::GetCollectStatsConsent), |
128 base::Bind(&SessionCrashedBubbleView::ShowForReal, | 151 base::Bind(&SessionCrashedBubbleView::ShowForReal, |
129 base::Passed(&browser_observer))); | 152 base::Passed(&browser_observer))); |
130 #else | 153 #else |
131 SessionCrashedBubbleView::ShowForReal(browser_observer.Pass(), false); | 154 SessionCrashedBubbleView::ShowForReal(browser_observer.Pass(), false); |
132 #endif // defined(GOOGLE_CHROME_BUILD) | 155 #endif // defined(GOOGLE_CHROME_BUILD) |
133 } | 156 } |
134 | 157 |
135 // static | 158 // static |
136 void SessionCrashedBubbleView::ShowForReal( | 159 void SessionCrashedBubbleView::ShowForReal( |
137 scoped_ptr<BrowserRemovalObserver> browser_observer, | 160 scoped_ptr<BrowserRemovalObserver> browser_observer, |
138 bool uma_opted_in_already) { | 161 bool uma_opted_in_already) { |
139 // Determine whether or not the uma opt-in option should be offered. It is | 162 // Determine whether or not the uma opt-in option should be offered. It is |
140 // offered only when it is a Google chrome build, user hasn't opted in yet, | 163 // offered only when it is a Google chrome build, user hasn't opted in yet, |
141 // and the preference is modifiable by the user. | 164 // and the preference is modifiable by the user. |
142 bool offer_uma_optin = false; | 165 bool offer_uma_optin = false; |
143 | 166 |
144 #if defined(GOOGLE_CHROME_BUILD) | 167 #if defined(GOOGLE_CHROME_BUILD) |
145 if (!uma_opted_in_already) | 168 if (!uma_opted_in_already) |
146 offer_uma_optin = g_browser_process->local_state()->FindPreference( | 169 offer_uma_optin = g_browser_process->local_state()->FindPreference( |
147 prefs::kMetricsReportingEnabled)->IsUserModifiable(); | 170 prefs::kMetricsReportingEnabled)->IsUserModifiable(); |
148 #endif // defined(GOOGLE_CHROME_BUILD) | 171 #endif // defined(GOOGLE_CHROME_BUILD) |
149 | 172 |
150 Browser* browser = browser_observer->browser(); | 173 Browser* browser = browser_observer->browser(); |
151 | 174 |
152 if (!browser) | 175 if (!browser) { |
176 RecordBubbleHistogramValue(SESSION_CRASHED_BUBBLE_ERROR); | |
153 return; | 177 return; |
178 } | |
154 | 179 |
155 views::View* anchor_view = | 180 views::View* anchor_view = |
156 BrowserView::GetBrowserViewForBrowser(browser)->toolbar()->app_menu(); | 181 BrowserView::GetBrowserViewForBrowser(browser)->toolbar()->app_menu(); |
157 content::WebContents* web_contents = | 182 content::WebContents* web_contents = |
158 browser->tab_strip_model()->GetActiveWebContents(); | 183 browser->tab_strip_model()->GetActiveWebContents(); |
159 | 184 |
160 if (!web_contents) | 185 if (!web_contents) { |
186 RecordBubbleHistogramValue(SESSION_CRASHED_BUBBLE_ERROR); | |
161 return; | 187 return; |
188 } | |
162 | 189 |
163 SessionCrashedBubbleView* crash_bubble = | 190 SessionCrashedBubbleView* crash_bubble = |
164 new SessionCrashedBubbleView(anchor_view, browser, web_contents, | 191 new SessionCrashedBubbleView(anchor_view, browser, web_contents, |
165 offer_uma_optin); | 192 offer_uma_optin); |
166 views::BubbleDelegateView::CreateBubble(crash_bubble)->Show(); | 193 views::BubbleDelegateView::CreateBubble(crash_bubble)->Show(); |
194 views::BubbleFrameView* frame_view = crash_bubble->GetBubbleFrameView(); | |
195 if (frame_view) { | |
196 frame_view->set_before_close_callback(base::Bind(&BubbleToBeClosed)); | |
197 } | |
198 RecordBubbleHistogramValue(SESSION_CRASHED_BUBBLE_SHOWN); | |
167 } | 199 } |
168 | 200 |
169 SessionCrashedBubbleView::SessionCrashedBubbleView( | 201 SessionCrashedBubbleView::SessionCrashedBubbleView( |
170 views::View* anchor_view, | 202 views::View* anchor_view, |
171 Browser* browser, | 203 Browser* browser, |
172 content::WebContents* web_contents, | 204 content::WebContents* web_contents, |
173 bool offer_uma_optin) | 205 bool offer_uma_optin) |
174 : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT), | 206 : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_RIGHT), |
175 content::WebContentsObserver(web_contents), | 207 content::WebContentsObserver(web_contents), |
176 browser_(browser), | 208 browser_(browser), |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
320 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); | 352 layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); |
321 layout->StartRow(0, kReportColumnSetId); | 353 layout->StartRow(0, kReportColumnSetId); |
322 layout->AddView(uma_option_); | 354 layout->AddView(uma_option_); |
323 layout->AddView(uma_label); | 355 layout->AddView(uma_label); |
324 } | 356 } |
325 | 357 |
326 void SessionCrashedBubbleView::ButtonPressed(views::Button* sender, | 358 void SessionCrashedBubbleView::ButtonPressed(views::Button* sender, |
327 const ui::Event& event) { | 359 const ui::Event& event) { |
328 DCHECK_EQ(sender, restore_button_); | 360 DCHECK_EQ(sender, restore_button_); |
329 RestorePreviousSession(sender); | 361 RestorePreviousSession(sender); |
362 RecordBubbleHistogramValue(SESSION_CRASHED_BUBBLE_RESTORED); | |
330 } | 363 } |
331 | 364 |
332 void SessionCrashedBubbleView::StyledLabelLinkClicked(const gfx::Range& range, | 365 void SessionCrashedBubbleView::StyledLabelLinkClicked(const gfx::Range& range, |
333 int event_flags) { | 366 int event_flags) { |
334 browser_->OpenURL(content::OpenURLParams( | 367 browser_->OpenURL(content::OpenURLParams( |
335 GURL("https://support.google.com/chrome/answer/96817"), | 368 GURL("https://support.google.com/chrome/answer/96817"), |
336 content::Referrer(), | 369 content::Referrer(), |
337 NEW_FOREGROUND_TAB, | 370 NEW_FOREGROUND_TAB, |
338 content::PAGE_TRANSITION_LINK, | 371 content::PAGE_TRANSITION_LINK, |
339 false)); | 372 false)); |
373 RecordBubbleHistogramValue(SESSION_CRASHED_BUBBLE_HELP); | |
340 } | 374 } |
341 | 375 |
342 void SessionCrashedBubbleView::DidStartNavigationToPendingEntry( | 376 void SessionCrashedBubbleView::DidStartNavigationToPendingEntry( |
343 const GURL& url, | 377 const GURL& url, |
344 content::NavigationController::ReloadType reload_type) { | 378 content::NavigationController::ReloadType reload_type) { |
345 started_navigation_ = true; | 379 started_navigation_ = true; |
346 } | 380 } |
347 | 381 |
348 void SessionCrashedBubbleView::DidFinishLoad( | 382 void SessionCrashedBubbleView::DidFinishLoad( |
349 int64 frame_id, | 383 int64 frame_id, |
350 const GURL& validated_url, | 384 const GURL& validated_url, |
351 bool is_main_frame, | 385 bool is_main_frame, |
352 content::RenderViewHost* render_view_host) { | 386 content::RenderViewHost* render_view_host) { |
353 if (started_navigation_) | 387 if (started_navigation_) { |
388 RecordBubbleHistogramValue(SESSION_CRASHED_BUBBLE_IGNORED); | |
354 CloseBubble(); | 389 CloseBubble(); |
390 } | |
355 } | 391 } |
356 | 392 |
357 void SessionCrashedBubbleView::WasShown() { | 393 void SessionCrashedBubbleView::WasShown() { |
358 GetWidget()->Show(); | 394 GetWidget()->Show(); |
359 } | 395 } |
360 | 396 |
361 void SessionCrashedBubbleView::WasHidden() { | 397 void SessionCrashedBubbleView::WasHidden() { |
362 GetWidget()->Hide(); | 398 GetWidget()->Hide(); |
363 } | 399 } |
364 | 400 |
365 void SessionCrashedBubbleView::Observe( | 401 void SessionCrashedBubbleView::Observe( |
366 int type, | 402 int type, |
367 const content::NotificationSource& source, | 403 const content::NotificationSource& source, |
368 const content::NotificationDetails& details) { | 404 const content::NotificationDetails& details) { |
369 if (type == chrome::NOTIFICATION_TAB_CLOSING) | 405 if (type == chrome::NOTIFICATION_TAB_CLOSING) { |
406 RecordBubbleHistogramValue(SESSION_CRASHED_BUBBLE_IGNORED); | |
370 CloseBubble(); | 407 CloseBubble(); |
408 } | |
371 } | 409 } |
372 | 410 |
373 void SessionCrashedBubbleView::TabDetachedAt(content::WebContents* contents, | 411 void SessionCrashedBubbleView::TabDetachedAt(content::WebContents* contents, |
374 int index) { | 412 int index) { |
375 if (web_contents_ == contents) | 413 if (web_contents_ == contents) { |
414 RecordBubbleHistogramValue(SESSION_CRASHED_BUBBLE_IGNORED); | |
376 CloseBubble(); | 415 CloseBubble(); |
416 } | |
377 } | 417 } |
378 | 418 |
379 void SessionCrashedBubbleView::RestorePreviousSession(views::Button* sender) { | 419 void SessionCrashedBubbleView::RestorePreviousSession(views::Button* sender) { |
380 SessionRestore::RestoreSessionAfterCrash(browser_); | 420 SessionRestore::RestoreSessionAfterCrash(browser_); |
381 | 421 |
382 // Record user's choice for opting in to UMA. | 422 // Record user's choice for opting in to UMA. |
383 // There's no opting-out choice in the crash restore bubble. | 423 // There's no opting-out choice in the crash restore bubble. |
384 if (uma_option_ && uma_option_->checked()) { | 424 if (uma_option_ && uma_option_->checked()) { |
385 // TODO: Clean up function ResolveMetricsReportingEnabled so that user pref | 425 // TODO: Clean up function ResolveMetricsReportingEnabled so that user pref |
386 // is stored automatically. | 426 // is stored automatically. |
387 OptionsUtil::ResolveMetricsReportingEnabled(true); | 427 OptionsUtil::ResolveMetricsReportingEnabled(true); |
388 g_browser_process->local_state()->SetBoolean( | 428 g_browser_process->local_state()->SetBoolean( |
389 prefs::kMetricsReportingEnabled, true); | 429 prefs::kMetricsReportingEnabled, true); |
430 RecordBubbleHistogramValue(SESSION_CRASHED_BUBBLE_UMA_OPTIN); | |
390 } | 431 } |
391 CloseBubble(); | 432 CloseBubble(); |
392 } | 433 } |
393 | 434 |
394 void SessionCrashedBubbleView::CloseBubble() { | 435 void SessionCrashedBubbleView::CloseBubble() { |
395 GetWidget()->Close(); | 436 GetWidget()->Close(); |
396 } | 437 } |
397 | 438 |
398 bool ShowSessionCrashedBubble(Browser* browser) { | 439 bool ShowSessionCrashedBubble(Browser* browser) { |
399 if (IsBubbleUIEnabled()) { | 440 if (IsBubbleUIEnabled()) { |
400 SessionCrashedBubbleView::Show(browser); | 441 SessionCrashedBubbleView::Show(browser); |
401 return true; | 442 return true; |
402 } | 443 } |
403 return false; | 444 return false; |
404 } | 445 } |
OLD | NEW |