1 // Copyright 2013 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 "base/compiler_specific.h"
6 #include "chrome/browser/download/download_danger_prompt.h"
7 #include "chrome/browser/download/download_stats.h"
8 #include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
9 #include "chrome/browser/ui/views/constrained_window_views.h"
10 #include "chrome/grit/chromium_strings.h"
11 #include "chrome/grit/generated_resources.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "content/public/browser/download_danger_type.h"
14 #include "content/public/browser/download_item.h"
15 #include "ui/base/l10n/l10n_util.h"
16 #include "ui/base/resource/resource_bundle.h"
17 #include "ui/views/controls/button/label_button.h"
18 #include "ui/views/controls/label.h"
19 #include "ui/views/layout/grid_layout.h"
20 #include "ui/views/view.h"
21 #include "ui/views/widget/widget.h"
22 #include "ui/views/window/dialog_client_view.h"
23 #include "ui/views/window/dialog_delegate.h"
25 using extensions::ExperienceSamplingEvent;
29 const int kMessageWidth = 320;
30 const int kParagraphPadding = 15;
32 // Views-specific implementation of download danger prompt dialog. We use this
33 // class rather than a TabModalConfirmDialog so that we can use custom
34 // formatting on the text in the body of the dialog.
35 class DownloadDangerPromptViews : public DownloadDangerPrompt,
36 public content::DownloadItem::Observer,
37 public views::DialogDelegate {
39 DownloadDangerPromptViews(content::DownloadItem* item,
43 // DownloadDangerPrompt methods:
44 virtual void InvokeActionForTesting(Action action) OVERRIDE;
46 // views::DialogDelegate methods:
47 virtual base::string16 GetDialogButtonLabel(
48 ui::DialogButton button) const OVERRIDE;
49 virtual base::string16 GetWindowTitle() const OVERRIDE;
50 virtual void DeleteDelegate() OVERRIDE;
51 virtual ui::ModalType GetModalType() const OVERRIDE;
52 virtual bool Cancel() OVERRIDE;
53 virtual bool Accept() OVERRIDE;
54 virtual bool Close() OVERRIDE;
55 virtual views::View* GetInitiallyFocusedView() OVERRIDE;
56 virtual views::View* GetContentsView() OVERRIDE;
57 virtual views::Widget* GetWidget() OVERRIDE;
58 virtual const views::Widget* GetWidget() const OVERRIDE;
60 // content::DownloadItem::Observer:
61 virtual void OnDownloadUpdated(content::DownloadItem* download) OVERRIDE;
64 base::string16 GetAcceptButtonTitle() const;
65 base::string16 GetCancelButtonTitle() const;
66 // The message lead is separated from the main text and is bolded.
67 base::string16 GetMessageLead() const;
68 base::string16 GetMessageBody() const;
69 void RunDone(Action action);
71 content::DownloadItem* download_;
75 scoped_ptr<ExperienceSamplingEvent> sampling_event_;
77 views::View* contents_view_;
80 DownloadDangerPromptViews::DownloadDangerPromptViews(
81 content::DownloadItem* item,
85 show_context_(show_context),
87 contents_view_(NULL) {
88 DCHECK(!done_.is_null());
89 download_->AddObserver(this);
91 contents_view_ = new views::View;
93 views::GridLayout* layout = views::GridLayout::CreatePanel(contents_view_);
94 contents_view_->SetLayoutManager(layout);
96 views::ColumnSet* column_set = layout->AddColumnSet(0);
97 column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
98 views::GridLayout::FIXED, kMessageWidth, 0);
100 const base::string16 message_lead = GetMessageLead();
102 if (!message_lead.empty()) {
103 ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
104 views::Label* message_lead_label = new views::Label(
105 message_lead, rb->GetFontList(ui::ResourceBundle::BoldFont));
106 message_lead_label->SetMultiLine(true);
107 message_lead_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
108 message_lead_label->SetAllowCharacterBreak(true);
110 layout->StartRow(0, 0);
111 layout->AddView(message_lead_label);
113 layout->AddPaddingRow(0, kParagraphPadding);
116 views::Label* message_body_label = new views::Label(GetMessageBody());
117 message_body_label->SetMultiLine(true);
118 message_body_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
119 message_body_label->SetAllowCharacterBreak(true);
121 layout->StartRow(0, 0);
122 layout->AddView(message_body_label);
124 RecordOpenedDangerousConfirmDialog(download_->GetDangerType());
126 // ExperienceSampling: A malicious download warning is being shown to the
127 // user, so we start a new SamplingEvent and track it.
128 sampling_event_.reset(new ExperienceSamplingEvent(
129 ExperienceSamplingEvent::kDownloadDangerPrompt,
131 item->GetReferrerUrl(),
132 item->GetBrowserContext()));
135 // DownloadDangerPrompt methods:
136 void DownloadDangerPromptViews::InvokeActionForTesting(Action action) {
153 // views::DialogDelegate methods:
154 base::string16 DownloadDangerPromptViews::GetDialogButtonLabel(
155 ui::DialogButton button) const {
157 case ui::DIALOG_BUTTON_OK:
158 return GetAcceptButtonTitle();
160 case ui::DIALOG_BUTTON_CANCEL:
161 return GetCancelButtonTitle();
164 return DialogDelegate::GetDialogButtonLabel(button);
168 base::string16 DownloadDangerPromptViews::GetWindowTitle() const {
170 return l10n_util::GetStringUTF16(IDS_CONFIRM_KEEP_DANGEROUS_DOWNLOAD_TITLE);
172 return l10n_util::GetStringUTF16(IDS_RESTORE_KEEP_DANGEROUS_DOWNLOAD_TITLE);
175 void DownloadDangerPromptViews::DeleteDelegate() {
176 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
180 ui::ModalType DownloadDangerPromptViews::GetModalType() const {
181 return ui::MODAL_TYPE_CHILD;
184 bool DownloadDangerPromptViews::Cancel() {
185 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
186 // ExperienceSampling: User canceled the warning.
187 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
192 bool DownloadDangerPromptViews::Accept() {
193 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
194 // ExperienceSampling: User proceeded through the warning.
195 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed);
200 bool DownloadDangerPromptViews::Close() {
201 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
202 // ExperienceSampling: User canceled the warning.
203 sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
208 views::View* DownloadDangerPromptViews::GetInitiallyFocusedView() {
209 return GetDialogClientView()->cancel_button();
212 views::View* DownloadDangerPromptViews::GetContentsView() {
213 return contents_view_;
216 views::Widget* DownloadDangerPromptViews::GetWidget() {
217 return contents_view_->GetWidget();
220 const views::Widget* DownloadDangerPromptViews::GetWidget() const {
221 return contents_view_->GetWidget();
224 // content::DownloadItem::Observer:
225 void DownloadDangerPromptViews::OnDownloadUpdated(
226 content::DownloadItem* download) {
227 // If the download is nolonger dangerous (accepted externally) or the download
228 // is in a terminal state, then the download danger prompt is no longer
230 if (!download_->IsDangerous() || download_->IsDone()) {
236 base::string16 DownloadDangerPromptViews::GetAcceptButtonTitle() const {
238 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD);
239 switch (download_->GetDangerType()) {
240 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
241 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
242 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
243 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN_MALICIOUS);
246 return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN);
250 base::string16 DownloadDangerPromptViews::GetCancelButtonTitle() const {
252 return l10n_util::GetStringUTF16(IDS_CANCEL);
253 switch (download_->GetDangerType()) {
254 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
255 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
256 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
257 return l10n_util::GetStringUTF16(IDS_CONFIRM_CANCEL_AGAIN_MALICIOUS);
260 return l10n_util::GetStringUTF16(IDS_CANCEL);
264 base::string16 DownloadDangerPromptViews::GetMessageLead() const {
265 if (!show_context_) {
266 switch (download_->GetDangerType()) {
267 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
268 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
269 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
270 return l10n_util::GetStringUTF16(
271 IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_LEAD);
278 return base::string16();
281 base::string16 DownloadDangerPromptViews::GetMessageBody() const {
283 switch (download_->GetDangerType()) {
284 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: {
285 return l10n_util::GetStringFUTF16(
286 IDS_PROMPT_DANGEROUS_DOWNLOAD,
287 download_->GetFileNameToReportUser().LossyDisplayName());
289 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: // Fall through
290 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
291 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
292 return l10n_util::GetStringFUTF16(
293 IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT,
294 download_->GetFileNameToReportUser().LossyDisplayName());
296 case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: {
297 return l10n_util::GetStringFUTF16(
298 IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT,
299 download_->GetFileNameToReportUser().LossyDisplayName());
301 case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: {
302 return l10n_util::GetStringFUTF16(
303 IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS,
304 download_->GetFileNameToReportUser().LossyDisplayName());
306 case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
307 case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
308 case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
309 case content::DOWNLOAD_DANGER_TYPE_MAX: {
314 switch (download_->GetDangerType()) {
315 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
316 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
317 case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
318 return l10n_util::GetStringUTF16(
319 IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_BODY);
322 return l10n_util::GetStringUTF16(
323 IDS_PROMPT_CONFIRM_KEEP_DANGEROUS_DOWNLOAD);
328 return base::string16();
331 void DownloadDangerPromptViews::RunDone(Action action) {
332 // Invoking the callback can cause the download item state to change or cause
333 // the window to close, and |callback| refers to a member variable.
336 if (download_ != NULL) {
337 download_->RemoveObserver(this);
346 DownloadDangerPrompt* DownloadDangerPrompt::Create(
347 content::DownloadItem* item,
348 content::WebContents* web_contents,
350 const OnDone& done) {
351 DownloadDangerPromptViews* download_danger_prompt =
352 new DownloadDangerPromptViews(item, show_context, done);
353 ShowWebModalDialogViews(download_danger_prompt, web_contents);
354 return download_danger_prompt;