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

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

Powered by Google App Engine
This is Rietveld 408576698