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

Side by Side Diff: chrome/browser/ui/views/sad_tab_view.cc

Issue 2261793002: Bring the feedback button to the Mac sad tab (Closed) Base URL: https://chromium.googlesource.com/chromium/src@master
Patch Set: Trybots caught this, but not the local presubmit check. Will investigate. Created 4 years, 3 months 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
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/sad_tab_view.h" 5 #include "chrome/browser/ui/views/sad_tab_view.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/metrics/histogram.h"
10 #include "build/build_config.h" 9 #include "build/build_config.h"
11 #include "chrome/browser/ui/browser_finder.h"
12 #include "chrome/browser/ui/chrome_pages.h"
13 #include "chrome/common/url_constants.h"
14 #include "chrome/grit/generated_resources.h"
15 #include "components/feedback/feedback_util.h"
16 #include "components/strings/grit/components_strings.h"
17 #include "content/public/browser/navigation_controller.h"
18 #include "content/public/browser/web_contents.h" 10 #include "content/public/browser/web_contents.h"
19 #include "ui/base/l10n/l10n_util.h" 11 #include "ui/base/l10n/l10n_util.h"
20 #include "ui/base/resource/resource_bundle.h" 12 #include "ui/base/resource/resource_bundle.h"
21 #include "ui/gfx/color_palette.h" 13 #include "ui/gfx/color_palette.h"
22 #include "ui/gfx/paint_vector_icon.h" 14 #include "ui/gfx/paint_vector_icon.h"
23 #include "ui/gfx/vector_icons_public.h" 15 #include "ui/gfx/vector_icons_public.h"
24 #include "ui/native_theme/common_theme.h" 16 #include "ui/native_theme/common_theme.h"
25 #include "ui/native_theme/native_theme.h" 17 #include "ui/native_theme/native_theme.h"
26 #include "ui/views/background.h" 18 #include "ui/views/background.h"
27 #include "ui/views/controls/button/blue_button.h" 19 #include "ui/views/controls/button/blue_button.h"
28 #include "ui/views/controls/image_view.h" 20 #include "ui/views/controls/image_view.h"
29 #include "ui/views/controls/label.h" 21 #include "ui/views/controls/label.h"
30 #include "ui/views/controls/link.h" 22 #include "ui/views/controls/link.h"
31 #include "ui/views/layout/grid_layout.h" 23 #include "ui/views/layout/grid_layout.h"
32 #include "ui/views/layout/layout_constants.h" 24 #include "ui/views/layout/layout_constants.h"
33 #include "ui/views/widget/widget.h" 25 #include "ui/views/widget/widget.h"
34 26
35 #if defined(OS_CHROMEOS)
36 #include "chrome/browser/memory/oom_memory_details.h"
37 #endif
38
39 using content::OpenURLParams;
40 using content::WebContents;
41
42 namespace { 27 namespace {
43 28
44 const int kMaxContentWidth = 600; 29 const int kMaxContentWidth = 600;
45 const int kMinColumnWidth = 120; 30 const int kMinColumnWidth = 120;
46 const char kCategoryTagCrash[] = "Crash";
47 const int kCrashesBeforeFeedbackIsDisplayed = 1;
48
49 void RecordKillCreated() {
50 static int killed = 0;
51 killed++;
52 UMA_HISTOGRAM_COUNTS_1000("Tabs.SadTab.KillCreated", killed);
53 }
54
55 void RecordKillDisplayed() {
56 static int killed = 0;
57 killed++;
58 UMA_HISTOGRAM_COUNTS_1000("Tabs.SadTab.KillDisplayed", killed);
59 }
60
61 #if defined(OS_CHROMEOS)
62 void RecordKillCreatedOOM() {
63 static int oom_killed = 0;
64 oom_killed++;
65 UMA_HISTOGRAM_COUNTS_1000("Tabs.SadTab.KillCreated.OOM", oom_killed);
66 }
67
68 void RecordKillDisplayedOOM() {
69 static int oom_killed = 0;
70 oom_killed++;
71 UMA_HISTOGRAM_COUNTS_1000("Tabs.SadTab.KillDisplayed.OOM", oom_killed);
72 }
73 #endif
74 31
75 } // namespace 32 } // namespace
76 33
77 int SadTabView::total_crashes_ = 0; 34 SadTabView::SadTabView(content::WebContents* web_contents,
78 35 chrome::SadTabKind kind)
79 SadTabView::SadTabView(WebContents* web_contents, chrome::SadTabKind kind) 36 : SadTab(web_contents, kind) {
80 : web_contents_(web_contents),
81 kind_(kind),
82 painted_(false),
83 message_(nullptr),
84 help_link_(nullptr),
85 action_button_(nullptr),
86 title_(nullptr),
87 help_message_(nullptr) {
88 DCHECK(web_contents);
89
90 // These stats should use the same counting approach and bucket size used for
91 // tab discard events in memory::OomPriorityManager so they can be directly
92 // compared.
93 // TODO(jamescook): Maybe track time between sad tabs?
94 total_crashes_++;
95
96 switch (kind_) {
97 case chrome::SAD_TAB_KIND_CRASHED: {
98 static int crashed = 0;
99 crashed++;
100 UMA_HISTOGRAM_COUNTS_1000("Tabs.SadTab.CrashCreated", crashed);
101 break;
102 }
103 case chrome::SAD_TAB_KIND_KILLED: {
104 RecordKillCreated();
105 LOG(WARNING) << "Tab Killed: "
106 << web_contents->GetURL().GetOrigin().spec();
107 break;
108 }
109 case chrome::SAD_TAB_KIND_OOM: {
110 static int crashed_due_to_oom = 0;
111 crashed_due_to_oom++;
112 UMA_HISTOGRAM_COUNTS_1000("Tabs.SadTab.OomCreated", crashed_due_to_oom);
113 break;
114 }
115 #if defined(OS_CHROMEOS)
116 case chrome::SAD_TAB_KIND_KILLED_BY_OOM: {
117 RecordKillCreated();
118 RecordKillCreatedOOM();
119 const std::string spec = web_contents->GetURL().GetOrigin().spec();
120 memory::OomMemoryDetails::Log(
121 "Tab OOM-Killed Memory details: " + spec + ", ", base::Closure());
122 break;
123 }
124 #endif
125 }
126
127 // Set the background color. 37 // Set the background color.
128 set_background( 38 set_background(
129 views::Background::CreateSolidBackground(GetNativeTheme()->GetSystemColor( 39 views::Background::CreateSolidBackground(GetNativeTheme()->GetSystemColor(
130 ui::NativeTheme::kColorId_DialogBackground))); 40 ui::NativeTheme::kColorId_DialogBackground)));
131 41
132 views::GridLayout* layout = new views::GridLayout(this); 42 views::GridLayout* layout = new views::GridLayout(this);
133 SetLayoutManager(layout); 43 SetLayoutManager(layout);
134 44
135 const int column_set_id = 0; 45 const int column_set_id = 0;
136 views::ColumnSet* columns = layout->AddColumnSet(column_set_id); 46 views::ColumnSet* columns = layout->AddColumnSet(column_set_id);
137 columns->AddPaddingColumn(1, views::kPanelSubVerticalSpacing); 47 columns->AddPaddingColumn(1, views::kPanelSubVerticalSpacing);
138 columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::LEADING, 0, 48 columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::LEADING, 0,
139 views::GridLayout::USE_PREF, 0, kMinColumnWidth); 49 views::GridLayout::USE_PREF, 0, kMinColumnWidth);
140 columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::LEADING, 0, 50 columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::LEADING, 0,
141 views::GridLayout::USE_PREF, 0, kMinColumnWidth); 51 views::GridLayout::USE_PREF, 0, kMinColumnWidth);
142 columns->AddPaddingColumn(1, views::kPanelSubVerticalSpacing); 52 columns->AddPaddingColumn(1, views::kPanelSubVerticalSpacing);
143 53
144 views::ImageView* image = new views::ImageView(); 54 views::ImageView* image = new views::ImageView();
145 55
146 image->SetImage(gfx::CreateVectorIcon(gfx::VectorIconId::CRASHED_TAB, 48, 56 image->SetImage(gfx::CreateVectorIcon(gfx::VectorIconId::CRASHED_TAB, 48,
147 gfx::kChromeIconGrey)); 57 gfx::kChromeIconGrey));
148 layout->AddPaddingRow(1, views::kPanelVerticalSpacing); 58 layout->AddPaddingRow(1, views::kPanelVerticalSpacing);
149 layout->StartRow(0, column_set_id); 59 layout->StartRow(0, column_set_id);
150 layout->AddView(image, 2, 1); 60 layout->AddView(image, 2, 1);
151 61
152 title_ = CreateLabel(l10n_util::GetStringUTF16(IDS_SAD_TAB_TITLE)); 62 title_ = CreateLabel(l10n_util::GetStringUTF16(GetTitle()));
153 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 63 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
154 title_->SetFontList(rb.GetFontList(ui::ResourceBundle::LargeFont)); 64 title_->SetFontList(rb.GetFontList(ui::ResourceBundle::LargeFont));
155 title_->SetMultiLine(true); 65 title_->SetMultiLine(true);
156 title_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 66 title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
157 layout->StartRowWithPadding(0, column_set_id, 0, 67 layout->StartRowWithPadding(0, column_set_id, 0,
158 views::kPanelVerticalSpacing); 68 views::kPanelVerticalSpacing);
159 layout->AddView(title_, 2, 1); 69 layout->AddView(title_, 2, 1);
160 70
161 const SkColor text_color = GetNativeTheme()->GetSystemColor( 71 const SkColor text_color = GetNativeTheme()->GetSystemColor(
162 ui::NativeTheme::kColorId_LabelDisabledColor); 72 ui::NativeTheme::kColorId_LabelDisabledColor);
163 73
164 int message_id = IDS_SAD_TAB_MESSAGE; 74 message_ = CreateLabel(l10n_util::GetStringUTF16(GetMessage()));
165 #if defined(OS_CHROMEOS)
166 if (kind_ == chrome::SAD_TAB_KIND_KILLED_BY_OOM)
167 message_id = IDS_KILLED_TAB_BY_OOM_MESSAGE;
168 #endif
169 if (kind_ == chrome::SAD_TAB_KIND_OOM)
170 message_id = IDS_SAD_TAB_OOM_MESSAGE;
171
172 message_ = CreateLabel(l10n_util::GetStringUTF16(message_id));
173 75
174 message_->SetMultiLine(true); 76 message_->SetMultiLine(true);
175 message_->SetEnabledColor(text_color); 77 message_->SetEnabledColor(text_color);
176 message_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 78 message_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
177 message_->SetLineHeight(views::kPanelSubVerticalSpacing); 79 message_->SetLineHeight(views::kPanelSubVerticalSpacing);
178 80
179 layout->StartRowWithPadding(0, column_set_id, 0, views::kPanelVertMargin); 81 layout->StartRowWithPadding(0, column_set_id, 0, views::kPanelVertMargin);
180 layout->AddView(message_, 2, 1, views::GridLayout::LEADING, 82 layout->AddView(message_, 2, 1, views::GridLayout::LEADING,
181 views::GridLayout::LEADING); 83 views::GridLayout::LEADING);
182 84
183 if (web_contents_) { 85 action_button_ =
184 // In the cases of multiple crashes in a session the 'Feedback' button 86 new views::BlueButton(this, l10n_util::GetStringUTF16(GetButtonTitle()));
185 // replaces the 'Reload' button as primary action. 87 help_link_ =
186 int button_type = total_crashes_ > kCrashesBeforeFeedbackIsDisplayed ? 88 CreateLink(l10n_util::GetStringUTF16(GetHelpLinkTitle()), text_color);
187 SAD_TAB_BUTTON_FEEDBACK : SAD_TAB_BUTTON_RELOAD; 89 layout->StartRowWithPadding(0, column_set_id, 0,
188 action_button_ = new views::BlueButton(this, 90 views::kPanelVerticalSpacing);
189 l10n_util::GetStringUTF16(button_type == SAD_TAB_BUTTON_FEEDBACK 91 layout->AddView(help_link_, 1, 1, views::GridLayout::LEADING,
190 ? IDS_CRASHED_TAB_FEEDBACK_LINK 92 views::GridLayout::CENTER);
191 : IDS_SAD_TAB_RELOAD_LABEL)); 93 layout->AddView(action_button_, 1, 1, views::GridLayout::TRAILING,
192 action_button_->set_tag(button_type); 94 views::GridLayout::LEADING);
193 help_link_ = 95
194 CreateLink(l10n_util::GetStringUTF16(IDS_LEARN_MORE), text_color);
195 layout->StartRowWithPadding(0, column_set_id, 0,
196 views::kPanelVerticalSpacing);
197 layout->AddView(help_link_, 1, 1, views::GridLayout::LEADING,
198 views::GridLayout::CENTER);
199 layout->AddView(action_button_, 1, 1, views::GridLayout::TRAILING,
200 views::GridLayout::LEADING);
201 }
202 layout->AddPaddingRow(2, views::kPanelSubVerticalSpacing); 96 layout->AddPaddingRow(2, views::kPanelSubVerticalSpacing);
97
98 views::Widget::InitParams sad_tab_params(
99 views::Widget::InitParams::TYPE_CONTROL);
100
101 // It is not possible to create a native_widget_win that has no parent in
102 // and later re-parent it.
103 // TODO(avi): This is a cheat. Can this be made cleaner?
104 sad_tab_params.parent = web_contents->GetNativeView();
105
106 set_owned_by_client();
107
108 views::Widget* sad_tab = new views::Widget;
109 sad_tab->Init(sad_tab_params);
110 sad_tab->SetContentsView(this);
111
112 views::Widget::ReparentNativeView(sad_tab->GetNativeView(),
113 web_contents->GetNativeView());
114 gfx::Rect bounds = web_contents->GetContainerBounds();
115 sad_tab->SetBounds(gfx::Rect(bounds.size()));
203 } 116 }
204 117
205 SadTabView::~SadTabView() {} 118 SadTabView::~SadTabView() {
119 if (GetWidget())
120 GetWidget()->Close();
121 }
206 122
207 void SadTabView::LinkClicked(views::Link* source, int event_flags) { 123 void SadTabView::LinkClicked(views::Link* source, int event_flags) {
208 DCHECK(web_contents_); 124 PerformAction(Action::HELP_LINK);
209 OpenURLParams params(GURL(total_crashes_ > kCrashesBeforeFeedbackIsDisplayed ?
210 chrome::kCrashReasonFeedbackDisplayedURL :
211 chrome::kCrashReasonURL), content::Referrer(),
212 CURRENT_TAB, ui::PAGE_TRANSITION_LINK, false);
213 web_contents_->OpenURL(params);
214 } 125 }
215 126
216 void SadTabView::ButtonPressed(views::Button* sender, 127 void SadTabView::ButtonPressed(views::Button* sender,
217 const ui::Event& event) { 128 const ui::Event& event) {
218 DCHECK(web_contents_);
219 DCHECK_EQ(action_button_, sender); 129 DCHECK_EQ(action_button_, sender);
220 130 PerformAction(Action::BUTTON);
221 if (action_button_->tag() == SAD_TAB_BUTTON_FEEDBACK) {
222 chrome::ShowFeedbackPage(
223 chrome::FindBrowserWithWebContents(web_contents_),
224 l10n_util::GetStringUTF8(kind_ == chrome::SAD_TAB_KIND_CRASHED ?
225 IDS_CRASHED_TAB_FEEDBACK_MESSAGE : IDS_KILLED_TAB_FEEDBACK_MESSAGE),
226 std::string(kCategoryTagCrash));
227 } else {
228 web_contents_->GetController().Reload(true);
229 }
230 } 131 }
231 132
232 void SadTabView::Layout() { 133 void SadTabView::Layout() {
233 // Specify the maximum message width explicitly. 134 // Specify the maximum message width explicitly.
234 const int max_width = 135 const int max_width =
235 std::min(width() - views::kPanelSubVerticalSpacing * 2, kMaxContentWidth); 136 std::min(width() - views::kPanelSubVerticalSpacing * 2, kMaxContentWidth);
236 message_->SizeToFit(max_width); 137 message_->SizeToFit(max_width);
237 title_->SizeToFit(max_width); 138 title_->SizeToFit(max_width);
238 139
239 if (help_message_ != nullptr)
240 help_message_->SizeToFit(max_width);
241
242 View::Layout(); 140 View::Layout();
243 } 141 }
244 142
245 void SadTabView::OnPaint(gfx::Canvas* canvas) { 143 void SadTabView::OnPaint(gfx::Canvas* canvas) {
246 if (!painted_) { 144 if (!painted_) {
247 // These stats should use the same counting approach and bucket size used 145 RecordFirstPaint();
248 // for tab discard events in memory::OomPriorityManager so they can be
249 // directly compared.
250 switch (kind_) {
251 case chrome::SAD_TAB_KIND_CRASHED: {
252 static int crashed = 0;
253 crashed++;
254 UMA_HISTOGRAM_COUNTS_1000("Tabs.SadTab.CrashDisplayed", crashed);
255 break;
256 }
257 case chrome::SAD_TAB_KIND_OOM: {
258 static int crashed_due_to_oom = 0;
259 crashed_due_to_oom++;
260 UMA_HISTOGRAM_COUNTS_1000(
261 "Tabs.SadTab.OomDisplayed", crashed_due_to_oom);
262 break;
263 }
264 case chrome::SAD_TAB_KIND_KILLED:
265 RecordKillDisplayed();
266 break;
267 #if defined(OS_CHROMEOS)
268 case chrome::SAD_TAB_KIND_KILLED_BY_OOM:
269 RecordKillDisplayed();
270 RecordKillDisplayedOOM();
271 break;
272 #endif
273 }
274 painted_ = true; 146 painted_ = true;
275 } 147 }
276 View::OnPaint(canvas); 148 View::OnPaint(canvas);
277 } 149 }
278 150
279 void SadTabView::Show() {
280 views::Widget::InitParams sad_tab_params(
281 views::Widget::InitParams::TYPE_CONTROL);
282
283 // It is not possible to create a native_widget_win that has no parent in
284 // and later re-parent it.
285 // TODO(avi): This is a cheat. Can this be made cleaner?
286 sad_tab_params.parent = web_contents_->GetNativeView();
287
288 set_owned_by_client();
289
290 views::Widget* sad_tab = new views::Widget;
291 sad_tab->Init(sad_tab_params);
292 sad_tab->SetContentsView(this);
293
294 views::Widget::ReparentNativeView(sad_tab->GetNativeView(),
295 web_contents_->GetNativeView());
296 gfx::Rect bounds = web_contents_->GetContainerBounds();
297 sad_tab->SetBounds(gfx::Rect(bounds.size()));
298 }
299
300 void SadTabView::Close() {
301 if (GetWidget())
302 GetWidget()->Close();
303 }
304
305 views::Label* SadTabView::CreateLabel(const base::string16& text) { 151 views::Label* SadTabView::CreateLabel(const base::string16& text) {
306 views::Label* label = new views::Label(text); 152 views::Label* label = new views::Label(text);
307 label->SetBackgroundColor(background()->get_color()); 153 label->SetBackgroundColor(background()->get_color());
308 return label; 154 return label;
309 } 155 }
310 156
311 views::Link* SadTabView::CreateLink(const base::string16& text, 157 views::Link* SadTabView::CreateLink(const base::string16& text,
312 const SkColor& color) { 158 const SkColor& color) {
313 views::Link* link = new views::Link(text); 159 views::Link* link = new views::Link(text);
314 link->SetBackgroundColor(background()->get_color()); 160 link->SetBackgroundColor(background()->get_color());
315 link->SetEnabledColor(color); 161 link->SetEnabledColor(color);
316 link->set_listener(this); 162 link->set_listener(this);
317 return link; 163 return link;
318 } 164 }
319 165
320 namespace chrome { 166 namespace chrome {
321 167
322 SadTab* SadTab::Create(content::WebContents* web_contents, 168 SadTab* SadTab::Create(content::WebContents* web_contents,
323 SadTabKind kind) { 169 SadTabKind kind) {
324 return new SadTabView(web_contents, kind); 170 return new SadTabView(web_contents, kind);
325 } 171 }
326 172
327 } // namespace chrome 173 } // namespace chrome
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698