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

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: Address second wave of comments, turn off feedback in non-Chrome builds 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
« no previous file with comments | « chrome/browser/ui/views/sad_tab_view.h ('k') | chrome/test/BUILD.gn » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_macros.h" 9 #include "base/metrics/histogram_macros.h"
10 #include "build/build_config.h" 10 #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" 11 #include "content/public/browser/web_contents.h"
19 #include "ui/base/l10n/l10n_util.h" 12 #include "ui/base/l10n/l10n_util.h"
20 #include "ui/base/resource/resource_bundle.h" 13 #include "ui/base/resource/resource_bundle.h"
21 #include "ui/gfx/color_palette.h" 14 #include "ui/gfx/color_palette.h"
22 #include "ui/gfx/paint_vector_icon.h" 15 #include "ui/gfx/paint_vector_icon.h"
23 #include "ui/gfx/vector_icons_public.h" 16 #include "ui/gfx/vector_icons_public.h"
24 #include "ui/native_theme/common_theme.h" 17 #include "ui/native_theme/common_theme.h"
25 #include "ui/native_theme/native_theme.h" 18 #include "ui/native_theme/native_theme.h"
26 #include "ui/views/background.h" 19 #include "ui/views/background.h"
27 #include "ui/views/controls/button/md_text_button.h" 20 #include "ui/views/controls/button/md_text_button.h"
28 #include "ui/views/controls/image_view.h" 21 #include "ui/views/controls/image_view.h"
29 #include "ui/views/controls/label.h" 22 #include "ui/views/controls/label.h"
30 #include "ui/views/controls/link.h" 23 #include "ui/views/controls/link.h"
31 #include "ui/views/layout/grid_layout.h" 24 #include "ui/views/layout/grid_layout.h"
32 #include "ui/views/layout/layout_constants.h" 25 #include "ui/views/layout/layout_constants.h"
33 #include "ui/views/widget/widget.h" 26 #include "ui/views/widget/widget.h"
34 27
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 { 28 namespace {
43 29
44 const int kMaxContentWidth = 600; 30 const int kMaxContentWidth = 600;
45 const int kMinColumnWidth = 120; 31 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 32
75 } // namespace 33 } // namespace
76 34
77 int SadTabView::total_crashes_ = 0; 35 SadTabView::SadTabView(content::WebContents* web_contents,
78 36 chrome::SadTabKind kind)
79 SadTabView::SadTabView(WebContents* web_contents, chrome::SadTabKind kind) 37 : 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. 38 // Set the background color.
128 set_background( 39 set_background(
129 views::Background::CreateSolidBackground(GetNativeTheme()->GetSystemColor( 40 views::Background::CreateSolidBackground(GetNativeTheme()->GetSystemColor(
130 ui::NativeTheme::kColorId_DialogBackground))); 41 ui::NativeTheme::kColorId_DialogBackground)));
131 42
132 views::GridLayout* layout = new views::GridLayout(this); 43 views::GridLayout* layout = new views::GridLayout(this);
133 SetLayoutManager(layout); 44 SetLayoutManager(layout);
134 45
135 const int column_set_id = 0; 46 const int column_set_id = 0;
136 views::ColumnSet* columns = layout->AddColumnSet(column_set_id); 47 views::ColumnSet* columns = layout->AddColumnSet(column_set_id);
137 columns->AddPaddingColumn(1, views::kPanelSubVerticalSpacing); 48 columns->AddPaddingColumn(1, views::kPanelSubVerticalSpacing);
138 columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::LEADING, 0, 49 columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::LEADING, 0,
139 views::GridLayout::USE_PREF, 0, kMinColumnWidth); 50 views::GridLayout::USE_PREF, 0, kMinColumnWidth);
140 columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::LEADING, 0, 51 columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::LEADING, 0,
141 views::GridLayout::USE_PREF, 0, kMinColumnWidth); 52 views::GridLayout::USE_PREF, 0, kMinColumnWidth);
142 columns->AddPaddingColumn(1, views::kPanelSubVerticalSpacing); 53 columns->AddPaddingColumn(1, views::kPanelSubVerticalSpacing);
143 54
144 views::ImageView* image = new views::ImageView(); 55 views::ImageView* image = new views::ImageView();
145 56
146 image->SetImage(gfx::CreateVectorIcon(gfx::VectorIconId::CRASHED_TAB, 48, 57 image->SetImage(gfx::CreateVectorIcon(gfx::VectorIconId::CRASHED_TAB, 48,
147 gfx::kChromeIconGrey)); 58 gfx::kChromeIconGrey));
148 layout->AddPaddingRow(1, views::kPanelVerticalSpacing); 59 layout->AddPaddingRow(1, views::kPanelVerticalSpacing);
149 layout->StartRow(0, column_set_id); 60 layout->StartRow(0, column_set_id);
150 layout->AddView(image, 2, 1); 61 layout->AddView(image, 2, 1);
151 62
152 title_ = CreateLabel(l10n_util::GetStringUTF16(IDS_SAD_TAB_TITLE)); 63 title_ = CreateLabel(l10n_util::GetStringUTF16(GetTitle()));
153 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 64 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
154 title_->SetFontList(rb.GetFontList(ui::ResourceBundle::LargeFont)); 65 title_->SetFontList(rb.GetFontList(ui::ResourceBundle::LargeFont));
155 title_->SetMultiLine(true); 66 title_->SetMultiLine(true);
156 title_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 67 title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
157 layout->StartRowWithPadding(0, column_set_id, 0, 68 layout->StartRowWithPadding(0, column_set_id, 0,
158 views::kPanelVerticalSpacing); 69 views::kPanelVerticalSpacing);
159 layout->AddView(title_, 2, 1); 70 layout->AddView(title_, 2, 1);
160 71
161 const SkColor text_color = GetNativeTheme()->GetSystemColor( 72 const SkColor text_color = GetNativeTheme()->GetSystemColor(
162 ui::NativeTheme::kColorId_LabelDisabledColor); 73 ui::NativeTheme::kColorId_LabelDisabledColor);
163 74
164 int message_id = IDS_SAD_TAB_MESSAGE; 75 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 76
174 message_->SetMultiLine(true); 77 message_->SetMultiLine(true);
175 message_->SetEnabledColor(text_color); 78 message_->SetEnabledColor(text_color);
176 message_->SetHorizontalAlignment(gfx::ALIGN_LEFT); 79 message_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
177 message_->SetLineHeight(views::kPanelSubVerticalSpacing); 80 message_->SetLineHeight(views::kPanelSubVerticalSpacing);
178 81
179 layout->StartRowWithPadding(0, column_set_id, 0, views::kPanelVertMargin); 82 layout->StartRowWithPadding(0, column_set_id, 0, views::kPanelVertMargin);
180 layout->AddView(message_, 2, 1, views::GridLayout::LEADING, 83 layout->AddView(message_, 2, 1, views::GridLayout::LEADING,
181 views::GridLayout::LEADING); 84 views::GridLayout::LEADING);
182 85
183 if (web_contents_) { 86 action_button_ = views::MdTextButton::CreateSecondaryUiBlueButton(
184 // In the cases of multiple crashes in a session the 'Feedback' button 87 this, l10n_util::GetStringUTF16(GetButtonTitle()));
185 // replaces the 'Reload' button as primary action. 88 help_link_ =
186 int button_type = total_crashes_ > kCrashesBeforeFeedbackIsDisplayed ? 89 CreateLink(l10n_util::GetStringUTF16(GetHelpLinkTitle()), text_color);
187 SAD_TAB_BUTTON_FEEDBACK : SAD_TAB_BUTTON_RELOAD; 90 layout->StartRowWithPadding(0, column_set_id, 0,
188 action_button_ = views::MdTextButton::CreateSecondaryUiBlueButton(this, 91 views::kPanelVerticalSpacing);
189 l10n_util::GetStringUTF16(button_type == SAD_TAB_BUTTON_FEEDBACK 92 layout->AddView(help_link_, 1, 1, views::GridLayout::LEADING,
190 ? IDS_CRASHED_TAB_FEEDBACK_LINK 93 views::GridLayout::CENTER);
191 : IDS_SAD_TAB_RELOAD_LABEL)); 94 layout->AddView(action_button_, 1, 1, views::GridLayout::TRAILING,
192 action_button_->set_tag(button_type); 95 views::GridLayout::LEADING);
193 help_link_ = 96
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); 97 layout->AddPaddingRow(2, views::kPanelSubVerticalSpacing);
98
99 views::Widget::InitParams sad_tab_params(
100 views::Widget::InitParams::TYPE_CONTROL);
101
102 // It is not possible to create a native_widget_win that has no parent in
103 // and later re-parent it.
104 // TODO(avi): This is a cheat. Can this be made cleaner?
105 sad_tab_params.parent = web_contents->GetNativeView();
106
107 set_owned_by_client();
108
109 views::Widget* sad_tab = new views::Widget;
110 sad_tab->Init(sad_tab_params);
111 sad_tab->SetContentsView(this);
112
113 views::Widget::ReparentNativeView(sad_tab->GetNativeView(),
114 web_contents->GetNativeView());
115 gfx::Rect bounds = web_contents->GetContainerBounds();
116 sad_tab->SetBounds(gfx::Rect(bounds.size()));
203 } 117 }
204 118
205 SadTabView::~SadTabView() {} 119 SadTabView::~SadTabView() {
120 if (GetWidget())
121 GetWidget()->Close();
122 }
206 123
207 void SadTabView::LinkClicked(views::Link* source, int event_flags) { 124 void SadTabView::LinkClicked(views::Link* source, int event_flags) {
208 DCHECK(web_contents_); 125 PerformAction(Action::HELP_LINK);
209 OpenURLParams params(GURL(total_crashes_ > kCrashesBeforeFeedbackIsDisplayed
210 ? chrome::kCrashReasonFeedbackDisplayedURL
211 : chrome::kCrashReasonURL),
212 content::Referrer(), WindowOpenDisposition::CURRENT_TAB,
213 ui::PAGE_TRANSITION_LINK, false);
214 web_contents_->OpenURL(params);
215 } 126 }
216 127
217 void SadTabView::ButtonPressed(views::Button* sender, 128 void SadTabView::ButtonPressed(views::Button* sender,
218 const ui::Event& event) { 129 const ui::Event& event) {
219 DCHECK(web_contents_);
220 DCHECK_EQ(action_button_, sender); 130 DCHECK_EQ(action_button_, sender);
221 131 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 } 132 }
232 133
233 void SadTabView::Layout() { 134 void SadTabView::Layout() {
234 // Specify the maximum message width explicitly. 135 // Specify the maximum message width explicitly.
235 const int max_width = 136 const int max_width =
236 std::min(width() - views::kPanelSubVerticalSpacing * 2, kMaxContentWidth); 137 std::min(width() - views::kPanelSubVerticalSpacing * 2, kMaxContentWidth);
237 message_->SizeToFit(max_width); 138 message_->SizeToFit(max_width);
238 title_->SizeToFit(max_width); 139 title_->SizeToFit(max_width);
239 140
240 if (help_message_ != nullptr)
241 help_message_->SizeToFit(max_width);
242
243 View::Layout(); 141 View::Layout();
244 } 142 }
245 143
246 void SadTabView::OnPaint(gfx::Canvas* canvas) { 144 void SadTabView::OnPaint(gfx::Canvas* canvas) {
247 if (!painted_) { 145 if (!painted_) {
248 // These stats should use the same counting approach and bucket size used 146 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; 147 painted_ = true;
276 } 148 }
277 View::OnPaint(canvas); 149 View::OnPaint(canvas);
278 } 150 }
279 151
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) { 152 views::Label* SadTabView::CreateLabel(const base::string16& text) {
307 views::Label* label = new views::Label(text); 153 views::Label* label = new views::Label(text);
308 label->SetBackgroundColor(background()->get_color()); 154 label->SetBackgroundColor(background()->get_color());
309 return label; 155 return label;
310 } 156 }
311 157
312 views::Link* SadTabView::CreateLink(const base::string16& text, 158 views::Link* SadTabView::CreateLink(const base::string16& text,
313 const SkColor& color) { 159 const SkColor& color) {
314 views::Link* link = new views::Link(text); 160 views::Link* link = new views::Link(text);
315 link->SetBackgroundColor(background()->get_color()); 161 link->SetBackgroundColor(background()->get_color());
316 link->SetEnabledColor(color); 162 link->SetEnabledColor(color);
317 link->set_listener(this); 163 link->set_listener(this);
318 return link; 164 return link;
319 } 165 }
320 166
321 namespace chrome { 167 namespace chrome {
322 168
323 SadTab* SadTab::Create(content::WebContents* web_contents, 169 SadTab* SadTab::Create(content::WebContents* web_contents,
324 SadTabKind kind) { 170 SadTabKind kind) {
325 return new SadTabView(web_contents, kind); 171 return new SadTabView(web_contents, kind);
326 } 172 }
327 173
328 } // namespace chrome 174 } // namespace chrome
OLDNEW
« no previous file with comments | « chrome/browser/ui/views/sad_tab_view.h ('k') | chrome/test/BUILD.gn » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698