PageRenderTime 65ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/chrome/browser/ui/views/download/download_danger_prompt_views.cc

https://gitlab.com/hkratz/chromium
C++ | 363 lines | 289 code | 51 blank | 23 comment | 21 complexity | 78da0cb7792c36cf414baa9fdb93ac78 MD5 | raw file
  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.
  4. #include "chrome/browser/download/download_danger_prompt.h"
  5. #include "base/compiler_specific.h"
  6. #include "chrome/browser/download/download_stats.h"
  7. #include "chrome/browser/extensions/api/experience_sampling_private/experience_sampling.h"
  8. #include "chrome/grit/chromium_strings.h"
  9. #include "chrome/grit/generated_resources.h"
  10. #include "components/constrained_window/constrained_window_views.h"
  11. #include "content/public/browser/browser_context.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"
  24. #include "url/gurl.h"
  25. using extensions::ExperienceSamplingEvent;
  26. namespace {
  27. const int kMessageWidth = 320;
  28. const int kParagraphPadding = 15;
  29. // Views-specific implementation of download danger prompt dialog. We use this
  30. // class rather than a TabModalConfirmDialog so that we can use custom
  31. // formatting on the text in the body of the dialog.
  32. class DownloadDangerPromptViews : public DownloadDangerPrompt,
  33. public content::DownloadItem::Observer,
  34. public views::DialogDelegate {
  35. public:
  36. DownloadDangerPromptViews(content::DownloadItem* item,
  37. bool show_context,
  38. const OnDone& done);
  39. // DownloadDangerPrompt methods:
  40. void InvokeActionForTesting(Action action) override;
  41. // views::DialogDelegate methods:
  42. base::string16 GetDialogButtonLabel(ui::DialogButton button) const override;
  43. base::string16 GetWindowTitle() const override;
  44. void DeleteDelegate() override;
  45. ui::ModalType GetModalType() const override;
  46. bool Cancel() override;
  47. bool Accept() override;
  48. bool Close() override;
  49. views::View* GetInitiallyFocusedView() override;
  50. views::View* GetContentsView() override;
  51. views::Widget* GetWidget() override;
  52. const views::Widget* GetWidget() const override;
  53. // content::DownloadItem::Observer:
  54. void OnDownloadUpdated(content::DownloadItem* download) override;
  55. private:
  56. base::string16 GetAcceptButtonTitle() const;
  57. base::string16 GetCancelButtonTitle() const;
  58. // The message lead is separated from the main text and is bolded.
  59. base::string16 GetMessageLead() const;
  60. base::string16 GetMessageBody() const;
  61. void RunDone(Action action);
  62. content::DownloadItem* download_;
  63. bool show_context_;
  64. OnDone done_;
  65. scoped_ptr<ExperienceSamplingEvent> sampling_event_;
  66. views::View* contents_view_;
  67. };
  68. DownloadDangerPromptViews::DownloadDangerPromptViews(
  69. content::DownloadItem* item,
  70. bool show_context,
  71. const OnDone& done)
  72. : download_(item),
  73. show_context_(show_context),
  74. done_(done),
  75. contents_view_(NULL) {
  76. DCHECK(!done_.is_null());
  77. download_->AddObserver(this);
  78. contents_view_ = new views::View;
  79. views::GridLayout* layout = views::GridLayout::CreatePanel(contents_view_);
  80. contents_view_->SetLayoutManager(layout);
  81. views::ColumnSet* column_set = layout->AddColumnSet(0);
  82. column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
  83. views::GridLayout::FIXED, kMessageWidth, 0);
  84. const base::string16 message_lead = GetMessageLead();
  85. if (!message_lead.empty()) {
  86. ui::ResourceBundle* rb = &ui::ResourceBundle::GetSharedInstance();
  87. views::Label* message_lead_label = new views::Label(
  88. message_lead, rb->GetFontList(ui::ResourceBundle::BoldFont));
  89. message_lead_label->SetMultiLine(true);
  90. message_lead_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
  91. message_lead_label->SetAllowCharacterBreak(true);
  92. layout->StartRow(0, 0);
  93. layout->AddView(message_lead_label);
  94. layout->AddPaddingRow(0, kParagraphPadding);
  95. }
  96. views::Label* message_body_label = new views::Label(GetMessageBody());
  97. message_body_label->SetMultiLine(true);
  98. message_body_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
  99. message_body_label->SetAllowCharacterBreak(true);
  100. layout->StartRow(0, 0);
  101. layout->AddView(message_body_label);
  102. RecordOpenedDangerousConfirmDialog(download_->GetDangerType());
  103. // ExperienceSampling: A malicious download warning is being shown to the
  104. // user, so we start a new SamplingEvent and track it.
  105. sampling_event_.reset(new ExperienceSamplingEvent(
  106. ExperienceSamplingEvent::kDownloadDangerPrompt,
  107. item->GetURL(),
  108. item->GetReferrerUrl(),
  109. item->GetBrowserContext()));
  110. }
  111. // DownloadDangerPrompt methods:
  112. void DownloadDangerPromptViews::InvokeActionForTesting(Action action) {
  113. switch (action) {
  114. case ACCEPT:
  115. Accept();
  116. break;
  117. case CANCEL:
  118. case DISMISS:
  119. Cancel();
  120. break;
  121. default:
  122. NOTREACHED();
  123. break;
  124. }
  125. }
  126. // views::DialogDelegate methods:
  127. base::string16 DownloadDangerPromptViews::GetDialogButtonLabel(
  128. ui::DialogButton button) const {
  129. switch (button) {
  130. case ui::DIALOG_BUTTON_OK:
  131. return GetAcceptButtonTitle();
  132. case ui::DIALOG_BUTTON_CANCEL:
  133. return GetCancelButtonTitle();
  134. default:
  135. return DialogDelegate::GetDialogButtonLabel(button);
  136. }
  137. }
  138. base::string16 DownloadDangerPromptViews::GetWindowTitle() const {
  139. if (show_context_)
  140. return l10n_util::GetStringUTF16(IDS_CONFIRM_KEEP_DANGEROUS_DOWNLOAD_TITLE);
  141. else
  142. return l10n_util::GetStringUTF16(IDS_RESTORE_KEEP_DANGEROUS_DOWNLOAD_TITLE);
  143. }
  144. void DownloadDangerPromptViews::DeleteDelegate() {
  145. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  146. delete this;
  147. }
  148. ui::ModalType DownloadDangerPromptViews::GetModalType() const {
  149. return ui::MODAL_TYPE_CHILD;
  150. }
  151. bool DownloadDangerPromptViews::Cancel() {
  152. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  153. // ExperienceSampling: User canceled the warning.
  154. sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
  155. RunDone(CANCEL);
  156. return true;
  157. }
  158. bool DownloadDangerPromptViews::Accept() {
  159. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  160. // ExperienceSampling: User proceeded through the warning.
  161. sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kProceed);
  162. RunDone(ACCEPT);
  163. return true;
  164. }
  165. bool DownloadDangerPromptViews::Close() {
  166. DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
  167. // ExperienceSampling: User canceled the warning.
  168. sampling_event_->CreateUserDecisionEvent(ExperienceSamplingEvent::kDeny);
  169. RunDone(DISMISS);
  170. return true;
  171. }
  172. views::View* DownloadDangerPromptViews::GetInitiallyFocusedView() {
  173. return GetDialogClientView()->cancel_button();
  174. }
  175. views::View* DownloadDangerPromptViews::GetContentsView() {
  176. return contents_view_;
  177. }
  178. views::Widget* DownloadDangerPromptViews::GetWidget() {
  179. return contents_view_->GetWidget();
  180. }
  181. const views::Widget* DownloadDangerPromptViews::GetWidget() const {
  182. return contents_view_->GetWidget();
  183. }
  184. // content::DownloadItem::Observer:
  185. void DownloadDangerPromptViews::OnDownloadUpdated(
  186. content::DownloadItem* download) {
  187. // If the download is nolonger dangerous (accepted externally) or the download
  188. // is in a terminal state, then the download danger prompt is no longer
  189. // necessary.
  190. if (!download_->IsDangerous() || download_->IsDone()) {
  191. RunDone(DISMISS);
  192. Cancel();
  193. }
  194. }
  195. base::string16 DownloadDangerPromptViews::GetAcceptButtonTitle() const {
  196. if (show_context_)
  197. return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD);
  198. switch (download_->GetDangerType()) {
  199. case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
  200. case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
  201. case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
  202. return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN_MALICIOUS);
  203. }
  204. default:
  205. return l10n_util::GetStringUTF16(IDS_CONFIRM_DOWNLOAD_AGAIN);
  206. }
  207. }
  208. base::string16 DownloadDangerPromptViews::GetCancelButtonTitle() const {
  209. if (show_context_)
  210. return l10n_util::GetStringUTF16(IDS_CANCEL);
  211. switch (download_->GetDangerType()) {
  212. case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
  213. case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
  214. case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
  215. return l10n_util::GetStringUTF16(IDS_CONFIRM_CANCEL_AGAIN_MALICIOUS);
  216. }
  217. default:
  218. return l10n_util::GetStringUTF16(IDS_CANCEL);
  219. }
  220. }
  221. base::string16 DownloadDangerPromptViews::GetMessageLead() const {
  222. if (!show_context_) {
  223. switch (download_->GetDangerType()) {
  224. case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
  225. case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
  226. case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST:
  227. return l10n_util::GetStringUTF16(
  228. IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_LEAD);
  229. default:
  230. break;
  231. }
  232. }
  233. return base::string16();
  234. }
  235. base::string16 DownloadDangerPromptViews::GetMessageBody() const {
  236. if (show_context_) {
  237. switch (download_->GetDangerType()) {
  238. case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: {
  239. return l10n_util::GetStringFUTF16(
  240. IDS_PROMPT_DANGEROUS_DOWNLOAD,
  241. download_->GetFileNameToReportUser().LossyDisplayName());
  242. }
  243. case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: // Fall through
  244. case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
  245. case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
  246. return l10n_util::GetStringFUTF16(
  247. IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT,
  248. download_->GetFileNameToReportUser().LossyDisplayName());
  249. }
  250. case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: {
  251. return l10n_util::GetStringFUTF16(
  252. IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT,
  253. download_->GetFileNameToReportUser().LossyDisplayName());
  254. }
  255. case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: {
  256. return l10n_util::GetStringFUTF16(
  257. IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS,
  258. download_->GetFileNameToReportUser().LossyDisplayName());
  259. }
  260. case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
  261. case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
  262. case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
  263. case content::DOWNLOAD_DANGER_TYPE_MAX: {
  264. break;
  265. }
  266. }
  267. } else {
  268. switch (download_->GetDangerType()) {
  269. case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL:
  270. case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
  271. case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
  272. return l10n_util::GetStringUTF16(
  273. IDS_PROMPT_CONFIRM_KEEP_MALICIOUS_DOWNLOAD_BODY);
  274. }
  275. default: {
  276. return l10n_util::GetStringUTF16(
  277. IDS_PROMPT_CONFIRM_KEEP_DANGEROUS_DOWNLOAD);
  278. }
  279. }
  280. }
  281. NOTREACHED();
  282. return base::string16();
  283. }
  284. void DownloadDangerPromptViews::RunDone(Action action) {
  285. // Invoking the callback can cause the download item state to change or cause
  286. // the window to close, and |callback| refers to a member variable.
  287. OnDone done = done_;
  288. done_.Reset();
  289. if (download_ != NULL) {
  290. if (!download_->GetURL().is_empty() &&
  291. !download_->GetBrowserContext()->IsOffTheRecord()) {
  292. SendSafeBrowsingDownloadRecoveryReport(
  293. action == DownloadDangerPrompt::ACCEPT, download_->GetURL());
  294. }
  295. download_->RemoveObserver(this);
  296. download_ = NULL;
  297. }
  298. if (!done.is_null())
  299. done.Run(action);
  300. }
  301. } // namespace
  302. DownloadDangerPrompt* DownloadDangerPrompt::Create(
  303. content::DownloadItem* item,
  304. content::WebContents* web_contents,
  305. bool show_context,
  306. const OnDone& done) {
  307. DownloadDangerPromptViews* download_danger_prompt =
  308. new DownloadDangerPromptViews(item, show_context, done);
  309. constrained_window::ShowWebModalDialogViews(download_danger_prompt,
  310. web_contents);
  311. return download_danger_prompt;
  312. }