Commit 687503b4 authored by asanka@chromium.org's avatar asanka@chromium.org

Implement additional UI changes for dangerous download warnings.

When a download is detected as malicious by the safe browsing service, the download shelf now displays a warning message along with a 'Discard' button and a drop down menu with additional actions.

BUG=102540
TEST=Initiating a download that is flagged as malicious by the safe browsing service causes the new malicious download warning to be displayed on the download shelf.


Review URL: http://codereview.chromium.org/8757007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112954 0039d316-1c4b-4281-b951-d872f2087c98
parent 2c40e1bb
...@@ -2328,11 +2328,11 @@ are declared in build/common.gypi. ...@@ -2328,11 +2328,11 @@ are declared in build/common.gypi.
</message> </message>
<message name="IDS_PROMPT_MALICIOUS_DOWNLOAD_URL" <message name="IDS_PROMPT_MALICIOUS_DOWNLOAD_URL"
desc="Message shown to the user to validate the download when the download url is classified to lead to malware by the safebrowsing database."> desc="Message shown to the user to validate the download when the download url is classified to lead to malware by the safebrowsing database.">
This file is malicious. Do you want to keep it anyway? This file appears malicious.
</message> </message>
<message name="IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT" <message name="IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT"
desc="Message shown to the user to validate the download when the download content is classified to lead to malware by safebrowsing."> desc="Message shown to the user to validate the download when the download content is classified to lead to malware by safebrowsing.">
This file is malicious. Do you want to keep <ph name="FILE_NAME">$1<ex>malware.exe</ex></ph> anyway? <ph name="FILE_NAME">$1<ex>malware.exe</ex></ph> appears malicious.
</message> </message>
<message name="IDS_CONFIRM_DOWNLOAD" <message name="IDS_CONFIRM_DOWNLOAD"
desc="Text for the button used to validate the downloading of a dangerous download."> desc="Text for the button used to validate the downloading of a dangerous download.">
...@@ -2449,6 +2449,18 @@ are declared in build/common.gypi. ...@@ -2449,6 +2449,18 @@ are declared in build/common.gypi.
desc="Download context menu resume download"> desc="Download context menu resume download">
&amp;Resume &amp;Resume
</message> </message>
<message name="IDS_DOWNLOAD_MENU_DISCARD"
desc="Download context menu discard malicious download">
&amp;Discard
</message>
<message name="IDS_DOWNLOAD_MENU_KEEP"
desc="Download context menu keep malicious download">
&amp;Keep
</message>
<message name="IDS_DOWNLOAD_MENU_LEARN_MORE"
desc="Download context menu show information about download scanning">
&amp;Learn more
</message>
</if> </if>
<if expr="pp_ifdef('use_titlecase')"> <if expr="pp_ifdef('use_titlecase')">
<message name="IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE" <message name="IDS_DOWNLOAD_MENU_OPEN_WHEN_COMPLETE"
...@@ -2475,6 +2487,18 @@ are declared in build/common.gypi. ...@@ -2475,6 +2487,18 @@ are declared in build/common.gypi.
desc="In Title Case: Download context menu resume download"> desc="In Title Case: Download context menu resume download">
&amp;Resume &amp;Resume
</message> </message>
<message name="IDS_DOWNLOAD_MENU_DISCARD"
desc="In Title Case: Download context menu discard malicious download">
&amp;Discard
</message>
<message name="IDS_DOWNLOAD_MENU_KEEP"
desc="In Title Case: Download context menu keep malicious download">
&amp;Keep
</message>
<message name="IDS_DOWNLOAD_MENU_LEARN_MORE"
desc="In Title Case: Download context menu show information about download scanning">
&amp;Learn More
</message>
</if> </if>
<!-- GRIT doesn't support nesting <if>...</if> blocks, so these can't --> <!-- GRIT doesn't support nesting <if>...</if> blocks, so these can't -->
<!-- go within the above titlecase checks, instead markup must use --> <!-- go within the above titlecase checks, instead markup must use -->
......
...@@ -6,9 +6,13 @@ ...@@ -6,9 +6,13 @@
#include "chrome/browser/download/download_item_model.h" #include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/download_prefs.h" #include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension.h"
#include "chrome/common/url_constants.h"
#include "content/browser/download/download_item.h" #include "content/browser/download/download_item.h"
#include "content/browser/download/download_manager.h" #include "content/browser/download/download_manager.h"
#include "content/browser/tab_contents/page_navigator.h"
#include "grit/generated_resources.h" #include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util.h"
...@@ -21,8 +25,22 @@ DownloadShelfContextMenu::DownloadShelfContextMenu( ...@@ -21,8 +25,22 @@ DownloadShelfContextMenu::DownloadShelfContextMenu(
} }
ui::SimpleMenuModel* DownloadShelfContextMenu::GetMenuModel() { ui::SimpleMenuModel* DownloadShelfContextMenu::GetMenuModel() {
return download_item_->IsComplete() ? GetFinishedMenuModel() ui::SimpleMenuModel* model = NULL;
: GetInProgressMenuModel();
if (download_item_->GetSafetyState() == DownloadItem::DANGEROUS) {
if (download_item_->GetDangerType() == DownloadStateInfo::DANGEROUS_URL ||
download_item_->GetDangerType() ==
DownloadStateInfo::DANGEROUS_CONTENT) {
model = GetMaliciousMenuModel();
} else {
NOTREACHED();
}
} else if (download_item_->IsComplete()) {
model = GetFinishedMenuModel();
} else {
model = GetInProgressMenuModel();
}
return model;
} }
bool DownloadShelfContextMenu::IsCommandIdEnabled(int command_id) const { bool DownloadShelfContextMenu::IsCommandIdEnabled(int command_id) const {
...@@ -82,6 +100,22 @@ void DownloadShelfContextMenu::ExecuteCommand(int command_id) { ...@@ -82,6 +100,22 @@ void DownloadShelfContextMenu::ExecuteCommand(int command_id) {
if (download_item_->IsPartialDownload()) if (download_item_->IsPartialDownload())
download_item_->TogglePause(); download_item_->TogglePause();
break; break;
case DISCARD:
download_item_->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD);
break;
case KEEP:
download_item_->DangerousDownloadValidated();
break;
case LEARN_MORE: {
Browser* browser = BrowserList::GetLastActive();
DCHECK(browser && browser->is_type_tabbed());
GURL learn_more_url(chrome::kDownloadScanningLearnMoreURL);
OpenURLParams params(google_util::AppendGoogleLocaleParam(learn_more_url),
GURL(), NEW_FOREGROUND_TAB,
content::PAGE_TRANSITION_TYPED, false);
browser->OpenURL(params);
break;
}
default: default:
NOTREACHED(); NOTREACHED();
} }
...@@ -113,6 +147,12 @@ string16 DownloadShelfContextMenu::GetLabelForCommandId(int command_id) const { ...@@ -113,6 +147,12 @@ string16 DownloadShelfContextMenu::GetLabelForCommandId(int command_id) const {
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_RESUME_ITEM); return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_RESUME_ITEM);
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_PAUSE_ITEM); return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_PAUSE_ITEM);
} }
case DISCARD:
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_DISCARD);
case KEEP:
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_KEEP);
case LEARN_MORE:
return l10n_util::GetStringUTF16(IDS_DOWNLOAD_MENU_LEARN_MORE);
default: default:
NOTREACHED(); NOTREACHED();
break; break;
...@@ -161,3 +201,20 @@ ui::SimpleMenuModel* DownloadShelfContextMenu::GetFinishedMenuModel() { ...@@ -161,3 +201,20 @@ ui::SimpleMenuModel* DownloadShelfContextMenu::GetFinishedMenuModel() {
return finished_download_menu_model_.get(); return finished_download_menu_model_.get();
} }
ui::SimpleMenuModel* DownloadShelfContextMenu::GetMaliciousMenuModel() {
if (malicious_download_menu_model_.get())
return malicious_download_menu_model_.get();
malicious_download_menu_model_.reset(new ui::SimpleMenuModel(this));
malicious_download_menu_model_->AddItemWithStringId(
DISCARD, IDS_DOWNLOAD_MENU_DISCARD);
malicious_download_menu_model_->AddItemWithStringId(
KEEP, IDS_DOWNLOAD_MENU_KEEP);
malicious_download_menu_model_->AddSeparator();
malicious_download_menu_model_->AddItemWithStringId(
LEARN_MORE, IDS_DOWNLOAD_MENU_LEARN_MORE);
return malicious_download_menu_model_.get();
}
...@@ -25,6 +25,9 @@ class DownloadShelfContextMenu : public ui::SimpleMenuModel::Delegate { ...@@ -25,6 +25,9 @@ class DownloadShelfContextMenu : public ui::SimpleMenuModel::Delegate {
ALWAYS_OPEN_TYPE, // Default this file extension to always open. ALWAYS_OPEN_TYPE, // Default this file extension to always open.
CANCEL, // Cancel the download. CANCEL, // Cancel the download.
TOGGLE_PAUSE, // Temporarily pause a download. TOGGLE_PAUSE, // Temporarily pause a download.
DISCARD, // Discard the malicious download.
KEEP, // Keep the malicious download.
LEARN_MORE, // Show information about download scanning.
MENU_LAST MENU_LAST
}; };
...@@ -53,11 +56,13 @@ class DownloadShelfContextMenu : public ui::SimpleMenuModel::Delegate { ...@@ -53,11 +56,13 @@ class DownloadShelfContextMenu : public ui::SimpleMenuModel::Delegate {
private: private:
ui::SimpleMenuModel* GetInProgressMenuModel(); ui::SimpleMenuModel* GetInProgressMenuModel();
ui::SimpleMenuModel* GetFinishedMenuModel(); ui::SimpleMenuModel* GetFinishedMenuModel();
ui::SimpleMenuModel* GetMaliciousMenuModel();
// We show slightly different menus if the download is in progress vs. if the // We show slightly different menus if the download is in progress vs. if the
// download has finished. // download has finished.
scoped_ptr<ui::SimpleMenuModel> in_progress_download_menu_model_; scoped_ptr<ui::SimpleMenuModel> in_progress_download_menu_model_;
scoped_ptr<ui::SimpleMenuModel> finished_download_menu_model_; scoped_ptr<ui::SimpleMenuModel> finished_download_menu_model_;
scoped_ptr<ui::SimpleMenuModel> malicious_download_menu_model_;
// A model to control the cancel behavior. // A model to control the cancel behavior.
BaseDownloadItemModel* download_model_; BaseDownloadItemModel* download_model_;
......
...@@ -109,8 +109,13 @@ class DownloadItemView : public views::ButtonListener, ...@@ -109,8 +109,13 @@ class DownloadItemView : public views::ButtonListener,
enum State { enum State {
NORMAL = 0, NORMAL = 0,
HOT, HOT,
PUSHED, PUSHED
DANGEROUS };
enum Mode {
NORMAL_MODE = 0, // Showing download item.
DANGEROUS_MODE, // Displaying the dangerous download warning.
MALICIOUS_MODE // Displaying the malicious download warning.
}; };
// The image set associated with the part containing the icon and text. // The image set associated with the part containing the icon and text.
...@@ -153,13 +158,16 @@ class DownloadItemView : public views::ButtonListener, ...@@ -153,13 +158,16 @@ class DownloadItemView : public views::ButtonListener,
void SetState(State body_state, State drop_down_state); void SetState(State body_state, State drop_down_state);
// Whether we are in the dangerous mode. // Whether we are in the dangerous mode.
bool IsDangerousMode() { return body_state_ == DANGEROUS; } bool IsShowingWarningDialog() {
return mode_ == DANGEROUS_MODE || mode_ == MALICIOUS_MODE;
}
// Reverts from dangerous mode to normal download mode. // Reverts from dangerous mode to normal download mode.
void ClearDangerousMode(); void ClearWarningDialog();
// Start displaying the dangerous download warning. // Start displaying the dangerous download warning or the malicious download
void EnterDangerousMode(); // warning.
void ShowWarningDialog();
// Sets |size| with the size of the Save and Discard buttons (they have the // Sets |size| with the size of the Save and Discard buttons (they have the
// same size). // same size).
...@@ -174,6 +182,9 @@ class DownloadItemView : public views::ButtonListener, ...@@ -174,6 +182,9 @@ class DownloadItemView : public views::ButtonListener,
// open the downloaded file. // open the downloaded file.
void Reenable(); void Reenable();
// Releases drop down button after showing a context menu.
void ReleaseDropDown();
// Given |x|, returns whether |x| is within the x coordinate range of // Given |x|, returns whether |x| is within the x coordinate range of
// the drop-down button or not. // the drop-down button or not.
bool InDropDownButtonXCoordinateRange(int x); bool InDropDownButtonXCoordinateRange(int x);
...@@ -183,11 +194,15 @@ class DownloadItemView : public views::ButtonListener, ...@@ -183,11 +194,15 @@ class DownloadItemView : public views::ButtonListener,
// dangerous download warning message (if any). // dangerous download warning message (if any).
void UpdateAccessibleName(); void UpdateAccessibleName();
// Update the location of the drop down button.
void UpdateDropDownButtonPosition();
// The different images used for the background. // The different images used for the background.
BodyImageSet normal_body_image_set_; BodyImageSet normal_body_image_set_;
BodyImageSet hot_body_image_set_; BodyImageSet hot_body_image_set_;
BodyImageSet pushed_body_image_set_; BodyImageSet pushed_body_image_set_;
BodyImageSet dangerous_mode_body_image_set_; BodyImageSet dangerous_mode_body_image_set_;
BodyImageSet malicious_mode_body_image_set_;
DropDownImageSet normal_drop_down_image_set_; DropDownImageSet normal_drop_down_image_set_;
DropDownImageSet hot_drop_down_image_set_; DropDownImageSet hot_drop_down_image_set_;
DropDownImageSet pushed_drop_down_image_set_; DropDownImageSet pushed_drop_down_image_set_;
...@@ -214,6 +229,9 @@ class DownloadItemView : public views::ButtonListener, ...@@ -214,6 +229,9 @@ class DownloadItemView : public views::ButtonListener,
State body_state_; State body_state_;
State drop_down_state_; State drop_down_state_;
// Mode of the download item view.
Mode mode_;
// In degrees, for downloads with no known total size. // In degrees, for downloads with no known total size.
int progress_angle_; int progress_angle_;
...@@ -278,7 +296,7 @@ class DownloadItemView : public views::ButtonListener, ...@@ -278,7 +296,7 @@ class DownloadItemView : public views::ButtonListener,
// Method factory used to delay reenabling of the item when opening the // Method factory used to delay reenabling of the item when opening the
// downloaded file. // downloaded file.
base::WeakPtrFactory<DownloadItemView> reenable_method_factory_; base::WeakPtrFactory<DownloadItemView> weak_ptr_factory_;
// The currently running download context menu. // The currently running download context menu.
scoped_ptr<DownloadShelfContextMenuView> context_menu_; scoped_ptr<DownloadShelfContextMenuView> context_menu_;
......
...@@ -21,7 +21,7 @@ DownloadShelfContextMenuView::DownloadShelfContextMenuView( ...@@ -21,7 +21,7 @@ DownloadShelfContextMenuView::DownloadShelfContextMenuView(
DownloadShelfContextMenuView::~DownloadShelfContextMenuView() {} DownloadShelfContextMenuView::~DownloadShelfContextMenuView() {}
bool DownloadShelfContextMenuView::Run(views::Widget* parent_widget, void DownloadShelfContextMenuView::Run(views::Widget* parent_widget,
const gfx::Rect& rect) { const gfx::Rect& rect) {
views::MenuModelAdapter menu_model_adapter(GetMenuModel()); views::MenuModelAdapter menu_model_adapter(GetMenuModel());
menu_runner_.reset(new views::MenuRunner(menu_model_adapter.CreateMenu())); menu_runner_.reset(new views::MenuRunner(menu_model_adapter.CreateMenu()));
...@@ -32,14 +32,15 @@ bool DownloadShelfContextMenuView::Run(views::Widget* parent_widget, ...@@ -32,14 +32,15 @@ bool DownloadShelfContextMenuView::Run(views::Widget* parent_widget,
position = views::MenuItemView::TOPRIGHT; position = views::MenuItemView::TOPRIGHT;
else else
position = views::MenuItemView::TOPLEFT; position = views::MenuItemView::TOPLEFT;
return menu_runner_->RunMenuAt(
// The return value of RunMenuAt indicates whether the MenuRunner was deleted
// while running the menu, which indicates that the containing view may have
// been deleted. We ignore the return value because our caller already assumes
// that the view could be deleted by the time we return from here.
ignore_result(menu_runner_->RunMenuAt(
parent_widget, parent_widget,
NULL, NULL,
rect, rect,
position, position,
views::MenuRunner::HAS_MNEMONICS) == views::MenuRunner::MENU_DELETED; views::MenuRunner::HAS_MNEMONICS));
}
void DownloadShelfContextMenuView::Stop() {
set_download_item(NULL);
} }
...@@ -27,15 +27,9 @@ class DownloadShelfContextMenuView : public DownloadShelfContextMenu { ...@@ -27,15 +27,9 @@ class DownloadShelfContextMenuView : public DownloadShelfContextMenu {
explicit DownloadShelfContextMenuView(BaseDownloadItemModel* model); explicit DownloadShelfContextMenuView(BaseDownloadItemModel* model);
virtual ~DownloadShelfContextMenuView(); virtual ~DownloadShelfContextMenuView();
// Returns true if menu has been deleted. |rect| is the bounding area for // |rect| is the bounding area for positioning the menu in screen coordinates.
// positioning the menu in screen coordinates. The menu will be positioned // The menu will be positioned above or below but not overlapping |rect|.
// above or below but not overlapping |rect|. void Run(views::Widget* parent_widget, const gfx::Rect& rect);
bool Run(views::Widget* parent_widget,
const gfx::Rect& rect) WARN_UNUSED_RESULT;
// This method runs when the caller has been deleted and we should not attempt
// to access download_item().
void Stop();
private: private:
scoped_ptr<views::MenuRunner> menu_runner_; scoped_ptr<views::MenuRunner> menu_runner_;
......
...@@ -322,6 +322,9 @@ const char kLearnMoreRegisterProtocolHandlerURL[] = ...@@ -322,6 +322,9 @@ const char kLearnMoreRegisterProtocolHandlerURL[] =
const char kSyncLearnMoreURL[] = const char kSyncLearnMoreURL[] =
"http://www.google.com/support/chrome/bin/answer.py?answer=165139"; "http://www.google.com/support/chrome/bin/answer.py?answer=165139";
const char kDownloadScanningLearnMoreURL[] =
"http://www.google.com/support/chrome/bin/answer.py?answer=99020";
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
const char kCloudPrintLearnMoreURL[] = const char kCloudPrintLearnMoreURL[] =
"https://www.google.com/support/chromeos/bin/topic.py?topic=29023"; "https://www.google.com/support/chromeos/bin/topic.py?topic=29023";
......
...@@ -293,6 +293,9 @@ extern const char kLearnMoreRegisterProtocolHandlerURL[]; ...@@ -293,6 +293,9 @@ extern const char kLearnMoreRegisterProtocolHandlerURL[];
// The URL for the "Learn more" page for sync setup on the personal stuff page. // The URL for the "Learn more" page for sync setup on the personal stuff page.
extern const char kSyncLearnMoreURL[]; extern const char kSyncLearnMoreURL[];
// The URL for the "Learn more" page for download scanning.
extern const char kDownloadScanningLearnMoreURL[];
// "Debug" pages which are dangerous and not for general consumption. // "Debug" pages which are dangerous and not for general consumption.
extern const char* const kChromeDebugURLs[]; extern const char* const kChromeDebugURLs[];
extern int kNumberOfChromeDebugURLs; extern int kNumberOfChromeDebugURLs;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment