AccessibilityManager must be deleted after ash Shell, but before InputMethodManager.
[chromium-blink-merge.git] / chrome / browser / ui / views / sad_tab_view.cc
blobe736aa715a8d68fdecbd9f0c91f4a0daf7bf952a
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
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/views/sad_tab_view.h"
7 #include <string>
9 #include "base/metrics/histogram.h"
10 #include "chrome/browser/ui/browser_finder.h"
11 #include "chrome/browser/ui/chrome_pages.h"
12 #include "chrome/common/url_constants.h"
13 #include "chrome/grit/generated_resources.h"
14 #include "components/feedback/feedback_util.h"
15 #include "content/public/browser/navigation_controller.h"
16 #include "content/public/browser/web_contents.h"
17 #include "grit/components_strings.h"
18 #include "grit/theme_resources.h"
19 #include "ui/base/l10n/l10n_util.h"
20 #include "ui/base/resource/resource_bundle.h"
21 #include "ui/views/background.h"
22 #include "ui/views/controls/button/blue_button.h"
23 #include "ui/views/controls/image_view.h"
24 #include "ui/views/controls/label.h"
25 #include "ui/views/controls/link.h"
26 #include "ui/views/layout/grid_layout.h"
27 #include "ui/views/layout/layout_constants.h"
28 #include "ui/views/widget/widget.h"
30 #if defined(OS_CHROMEOS)
31 #include "chrome/browser/memory/oom_memory_details.h"
32 #endif
34 using content::OpenURLParams;
35 using content::WebContents;
37 namespace {
39 const int kMaxContentWidth = 600;
40 const int kMinColumnWidth = 120;
41 const char kCategoryTagCrash[] = "Crash";
42 const int kCrashesBeforeFeedbackIsDisplayed = 1;
44 void RecordKillCreated() {
45 static int killed = 0;
46 killed++;
47 UMA_HISTOGRAM_CUSTOM_COUNTS(
48 "Tabs.SadTab.KillCreated", killed, 1, 1000, 50);
51 void RecordKillDisplayed() {
52 static int killed = 0;
53 killed++;
54 UMA_HISTOGRAM_CUSTOM_COUNTS(
55 "Tabs.SadTab.KillDisplayed", killed, 1, 1000, 50);
58 #if defined(OS_CHROMEOS)
59 void RecordKillCreatedOOM() {
60 static int oom_killed = 0;
61 oom_killed++;
62 UMA_HISTOGRAM_CUSTOM_COUNTS(
63 "Tabs.SadTab.KillCreated.OOM", oom_killed, 1, 1000, 50);
66 void RecordKillDisplayedOOM() {
67 static int oom_killed = 0;
68 oom_killed++;
69 UMA_HISTOGRAM_CUSTOM_COUNTS(
70 "Tabs.SadTab.KillDisplayed.OOM", oom_killed, 1, 1000, 50);
72 #endif
74 } // namespace
76 int SadTabView::total_crashes_ = 0;
78 SadTabView::SadTabView(WebContents* web_contents, chrome::SadTabKind kind)
79 : web_contents_(web_contents),
80 kind_(kind),
81 painted_(false),
82 message_(nullptr),
83 help_link_(nullptr),
84 action_button_(nullptr),
85 title_(nullptr),
86 help_message_(nullptr) {
87 DCHECK(web_contents);
89 // These stats should use the same counting approach and bucket size used for
90 // tab discard events in memory::OomPriorityManager so they can be directly
91 // compared.
92 // TODO(jamescook): Maybe track time between sad tabs?
93 total_crashes_++;
95 switch (kind_) {
96 case chrome::SAD_TAB_KIND_CRASHED: {
97 static int crashed = 0;
98 crashed++;
99 UMA_HISTOGRAM_CUSTOM_COUNTS(
100 "Tabs.SadTab.CrashCreated", crashed, 1, 1000, 50);
101 break;
103 case chrome::SAD_TAB_KIND_KILLED: {
104 RecordKillCreated();
105 LOG(WARNING) << "Tab Killed: "
106 << web_contents->GetURL().GetOrigin().spec();
107 break;
109 #if defined(OS_CHROMEOS)
110 case chrome::SAD_TAB_KIND_KILLED_BY_OOM: {
111 RecordKillCreated();
112 RecordKillCreatedOOM();
113 const std::string spec = web_contents->GetURL().GetOrigin().spec();
114 memory::OomMemoryDetails::Log(
115 "Tab OOM-Killed Memory details: " + spec + ", ", base::Closure());
116 break;
118 #endif
121 // Set the background color.
122 set_background(
123 views::Background::CreateSolidBackground(GetNativeTheme()->GetSystemColor(
124 ui::NativeTheme::kColorId_DialogBackground)));
126 views::GridLayout* layout = new views::GridLayout(this);
127 SetLayoutManager(layout);
129 const int column_set_id = 0;
130 views::ColumnSet* columns = layout->AddColumnSet(column_set_id);
131 columns->AddPaddingColumn(1, views::kPanelSubVerticalSpacing);
132 columns->AddColumn(views::GridLayout::LEADING, views::GridLayout::LEADING, 0,
133 views::GridLayout::USE_PREF, 0, kMinColumnWidth);
134 columns->AddColumn(views::GridLayout::TRAILING, views::GridLayout::LEADING, 0,
135 views::GridLayout::USE_PREF, 0, kMinColumnWidth);
136 columns->AddPaddingColumn(1, views::kPanelSubVerticalSpacing);
138 views::ImageView* image = new views::ImageView();
139 image->SetImage(
140 ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(IDR_SAD_TAB));
141 layout->AddPaddingRow(1, views::kPanelVerticalSpacing);
142 layout->StartRow(0, column_set_id);
143 layout->AddView(image, 2, 1);
145 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
147 title_ = CreateLabel(l10n_util::GetStringUTF16(IDS_SAD_TAB_TITLE));
148 title_->SetFontList(rb.GetFontList(ui::ResourceBundle::LargeFont));
149 title_->SetMultiLine(true);
150 title_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
151 layout->StartRowWithPadding(0, column_set_id, 0,
152 views::kPanelVerticalSpacing);
153 layout->AddView(title_, 2, 1);
155 const SkColor text_color = GetNativeTheme()->GetSystemColor(
156 ui::NativeTheme::kColorId_LabelDisabledColor);
158 int message_id = IDS_SAD_TAB_MESSAGE;
159 #if defined(OS_CHROMEOS)
160 if (kind_ == chrome::SAD_TAB_KIND_KILLED_BY_OOM)
161 message_id = IDS_KILLED_TAB_BY_OOM_MESSAGE;
162 #endif
164 message_ = CreateLabel(l10n_util::GetStringUTF16(message_id));
166 message_->SetMultiLine(true);
167 message_->SetEnabledColor(text_color);
168 message_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
169 message_->SetLineHeight(views::kPanelSubVerticalSpacing);
171 layout->StartRowWithPadding(0, column_set_id, 0, views::kPanelVertMargin);
172 layout->AddView(message_, 2, 1, views::GridLayout::LEADING,
173 views::GridLayout::LEADING);
175 if (web_contents_) {
176 // In the cases of multiple crashes in a session the 'Feedback' button
177 // replaces the 'Reload' button as primary action.
178 int button_type = total_crashes_ > kCrashesBeforeFeedbackIsDisplayed ?
179 SAD_TAB_BUTTON_FEEDBACK : SAD_TAB_BUTTON_RELOAD;
180 action_button_ = new views::BlueButton(this,
181 l10n_util::GetStringUTF16(button_type == SAD_TAB_BUTTON_FEEDBACK
182 ? IDS_CRASHED_TAB_FEEDBACK_LINK
183 : IDS_SAD_TAB_RELOAD_LABEL));
184 action_button_->set_tag(button_type);
185 help_link_ =
186 CreateLink(l10n_util::GetStringUTF16(IDS_LEARN_MORE), text_color);
187 layout->StartRowWithPadding(0, column_set_id, 0,
188 views::kPanelVerticalSpacing);
189 layout->AddView(help_link_, 1, 1, views::GridLayout::LEADING,
190 views::GridLayout::CENTER);
191 layout->AddView(action_button_, 1, 1, views::GridLayout::TRAILING,
192 views::GridLayout::LEADING);
194 layout->AddPaddingRow(2, views::kPanelSubVerticalSpacing);
197 SadTabView::~SadTabView() {}
199 void SadTabView::LinkClicked(views::Link* source, int event_flags) {
200 DCHECK(web_contents_);
201 OpenURLParams params(GURL(total_crashes_ > kCrashesBeforeFeedbackIsDisplayed ?
202 chrome::kCrashReasonFeedbackDisplayedURL :
203 chrome::kCrashReasonURL), content::Referrer(),
204 CURRENT_TAB, ui::PAGE_TRANSITION_LINK, false);
205 web_contents_->OpenURL(params);
208 void SadTabView::ButtonPressed(views::Button* sender,
209 const ui::Event& event) {
210 DCHECK(web_contents_);
211 DCHECK_EQ(action_button_, sender);
213 if (action_button_->tag() == SAD_TAB_BUTTON_FEEDBACK) {
214 chrome::ShowFeedbackPage(
215 chrome::FindBrowserWithWebContents(web_contents_),
216 l10n_util::GetStringUTF8(kind_ == chrome::SAD_TAB_KIND_CRASHED ?
217 IDS_CRASHED_TAB_FEEDBACK_MESSAGE : IDS_KILLED_TAB_FEEDBACK_MESSAGE),
218 std::string(kCategoryTagCrash));
219 } else {
220 web_contents_->GetController().Reload(true);
224 void SadTabView::Layout() {
225 // Specify the maximum message width explicitly.
226 const int max_width =
227 std::min(width() - views::kPanelSubVerticalSpacing * 2, kMaxContentWidth);
228 message_->SizeToFit(max_width);
229 title_->SizeToFit(max_width);
231 if (help_message_ != nullptr)
232 help_message_->SizeToFit(max_width);
234 View::Layout();
237 void SadTabView::OnPaint(gfx::Canvas* canvas) {
238 if (!painted_) {
239 // These stats should use the same counting approach and bucket size used
240 // for tab discard events in memory::OomPriorityManager so they can be
241 // directly compared.
242 switch (kind_) {
243 case chrome::SAD_TAB_KIND_CRASHED: {
244 static int crashed = 0;
245 UMA_HISTOGRAM_CUSTOM_COUNTS(
246 "Tabs.SadTab.CrashDisplayed", ++crashed, 1, 1000, 50);
247 break;
249 case chrome::SAD_TAB_KIND_KILLED:
250 RecordKillDisplayed();
251 break;
252 #if defined(OS_CHROMEOS)
253 case chrome::SAD_TAB_KIND_KILLED_BY_OOM:
254 RecordKillDisplayed();
255 RecordKillDisplayedOOM();
256 break;
257 #endif
259 painted_ = true;
261 View::OnPaint(canvas);
264 void SadTabView::Show() {
265 views::Widget::InitParams sad_tab_params(
266 views::Widget::InitParams::TYPE_CONTROL);
268 // It is not possible to create a native_widget_win that has no parent in
269 // and later re-parent it.
270 // TODO(avi): This is a cheat. Can this be made cleaner?
271 sad_tab_params.parent = web_contents_->GetNativeView();
273 set_owned_by_client();
275 views::Widget* sad_tab = new views::Widget;
276 sad_tab->Init(sad_tab_params);
277 sad_tab->SetContentsView(this);
279 views::Widget::ReparentNativeView(sad_tab->GetNativeView(),
280 web_contents_->GetNativeView());
281 gfx::Rect bounds = web_contents_->GetContainerBounds();
282 sad_tab->SetBounds(gfx::Rect(bounds.size()));
285 void SadTabView::Close() {
286 if (GetWidget())
287 GetWidget()->Close();
290 views::Label* SadTabView::CreateLabel(const base::string16& text) {
291 views::Label* label = new views::Label(text);
292 label->SetBackgroundColor(background()->get_color());
293 return label;
296 views::Link* SadTabView::CreateLink(const base::string16& text,
297 const SkColor& color) {
298 views::Link* link = new views::Link(text);
299 link->SetBackgroundColor(background()->get_color());
300 link->SetEnabledColor(color);
301 link->set_listener(this);
302 return link;
305 namespace chrome {
307 SadTab* SadTab::Create(content::WebContents* web_contents,
308 SadTabKind kind) {
309 return new SadTabView(web_contents, kind);
312 } // namespace chrome