| Index: chrome/browser/download/notification/download_notification_item.cc
|
| diff --git a/chrome/browser/download/notification/download_notification_item.cc b/chrome/browser/download/notification/download_notification_item.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e3bd6beec4d83090b0b2e3f74b5e731d91821372
|
| --- /dev/null
|
| +++ b/chrome/browser/download/notification/download_notification_item.cc
|
| @@ -0,0 +1,457 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chrome/browser/download/notification/download_notification_item.h"
|
| +
|
| +#include "base/strings/string_number_conversions.h"
|
| +#include "chrome/browser/download/download_crx_util.h"
|
| +#include "chrome/browser/download/download_item_model.h"
|
| +#include "chrome/grit/chromium_strings.h"
|
| +#include "chrome/grit/generated_resources.h"
|
| +#include "content/public/browser/browser_context.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +#include "content/public/browser/download_item.h"
|
| +#include "content/public/browser/web_contents.h"
|
| +#include "grit/theme_resources.h"
|
| +#include "ui/base/l10n/l10n_util.h"
|
| +#include "ui/base/resource/resource_bundle.h"
|
| +#include "ui/message_center/message_center.h"
|
| +#include "ui/message_center/notification.h"
|
| +#include "ui/message_center/notification_delegate.h"
|
| +
|
| +using message_center::Notification;
|
| +
|
| +namespace {
|
| +
|
| +const char kDownloadNotificationNotifierId[] =
|
| + "chrome://settings/display/notification/id-notifier";
|
| +const char kDownloadNotificationIdBase[] =
|
| + "chrome://settings/display/notification/id-";
|
| +
|
| +} // anonymous namespace
|
| +
|
| +DownloadNotificationItem::NotificationWatcher::NotificationWatcher(
|
| + DownloadNotificationItem* item)
|
| + : item_(item) {
|
| +}
|
| +
|
| +DownloadNotificationItem::NotificationWatcher::~NotificationWatcher() {
|
| +}
|
| +
|
| +void DownloadNotificationItem::NotificationWatcher::Close(bool by_user) {
|
| + item_->OnNotificationClose(by_user);
|
| +}
|
| +
|
| +void DownloadNotificationItem::NotificationWatcher::Click() {
|
| + item_->OnNotificationClick();
|
| +}
|
| +
|
| +bool DownloadNotificationItem::NotificationWatcher::HasClickedListener() {
|
| + return true;
|
| +}
|
| +
|
| +void DownloadNotificationItem::NotificationWatcher::ButtonClick(
|
| + int button_index) {
|
| + item_->OnNotificationButtonClick(button_index);
|
| +}
|
| +
|
| +void DownloadNotificationItem::NotificationWatcher::OnNotificationRemoved(
|
| + const std::string& id,
|
| + bool by_user) {
|
| + if (id != item_->notification_->id())
|
| + return;
|
| + item_->OnNotificationRemoved(by_user);
|
| +}
|
| +
|
| +DownloadNotificationItem::DownloadNotificationItem(content::DownloadItem* item,
|
| + Delegate* delegate)
|
| + : openable_(false),
|
| + downloading_(false),
|
| + reshow_after_remove_(false),
|
| + image_resource_id_(0),
|
| + watcher_(new NotificationWatcher(this)),
|
| + item_(item),
|
| + delegate_(delegate) {
|
| + item->AddObserver(this);
|
| +
|
| + message_center_ = message_center::MessageCenter::Get();
|
| + message_center_->AddObserver(watcher_.get());
|
| +
|
| + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
|
| +
|
| + const base::string16 timeout_message =
|
| + l10n_util::GetStringUTF16(IDS_DOWNLOAD_STATUS_CRX_INSTALL_RUNNING);
|
| + const base::string16 message =
|
| + l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL);
|
| +
|
| + std::string id(kDownloadNotificationIdBase);
|
| + id += base::UintToString(item_->GetId());
|
| +
|
| + message_center::RichNotificationData data;
|
| + notification_.reset(new Notification(
|
| + message_center::NOTIFICATION_TYPE_PROGRESS, id, message, timeout_message,
|
| + bundle.GetImageNamed(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING),
|
| + base::string16() /* display_source */,
|
| + message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT,
|
| + kDownloadNotificationNotifierId),
|
| + data, watcher_.get()));
|
| +
|
| + notification_->set_progress(0);
|
| + notification_->set_never_timeout(false);
|
| +
|
| + UpdateNotificationData();
|
| +
|
| + scoped_ptr<Notification> notification(new Notification(*notification_));
|
| + message_center_->AddNotification(notification.Pass());
|
| +}
|
| +
|
| +DownloadNotificationItem::~DownloadNotificationItem() {
|
| + if (item_)
|
| + item_->RemoveObserver(this);
|
| + message_center_->RemoveObserver(watcher_.get());
|
| +}
|
| +
|
| +void DownloadNotificationItem::OnNotificationClose(bool by_user) {
|
| + if (item_->GetState() != content::DownloadItem::IN_PROGRESS) {
|
| + reshow_after_remove_ = false;
|
| + } else {
|
| + bool popup = false;
|
| +
|
| + const std::string id = notification_->id();
|
| + message_center::NotificationList::PopupNotifications popups =
|
| + message_center_->GetPopupNotifications();
|
| + for (auto it = popups.begin(); it != popups.end(); it++) {
|
| + if ((*it)->id() == id) {
|
| + popup = true;
|
| + break;
|
| + }
|
| + }
|
| +
|
| + // Reshows the notification in the notification center, if the download is
|
| + // in progress and the notifitation being closed is a popup.
|
| + reshow_after_remove_ = popup;
|
| + }
|
| +
|
| + // OnNotificationRemoved() will be called soon, just after the notification
|
| + // is removed.
|
| +}
|
| +
|
| +void DownloadNotificationItem::OnNotificationRemoved(bool by_user) {
|
| + if (reshow_after_remove_) {
|
| + // Sets the notification as read.
|
| + notification_->set_is_read(true);
|
| +
|
| + // Reshows the notification.
|
| + scoped_ptr<Notification> notification(new Notification(*notification_));
|
| + message_center_->AddNotification(notification.Pass());
|
| + // Show the reshown notification as a non-popup.
|
| + message_center_->MarkSinglePopupAsShown(notification_->id(), true);
|
| +
|
| + reshow_after_remove_ = false;
|
| + } else {
|
| + // Cancels the download.
|
| + item_->Cancel(by_user);
|
| + delegate_->OnDownloadRemoved(this);
|
| + }
|
| +}
|
| +
|
| +void DownloadNotificationItem::OnNotificationClick() {
|
| + if (openable_) {
|
| + if (item_->IsDone())
|
| + item_->OpenDownload();
|
| + else
|
| + item_->SetOpenWhenComplete(!item_->GetOpenWhenComplete()); // Toggle
|
| + }
|
| +
|
| + if (item_->IsDone())
|
| + message_center_->RemoveNotification(notification_->id(), true);
|
| +}
|
| +
|
| +void DownloadNotificationItem::OnNotificationButtonClick(int button_index) {
|
| + if (button_index < 0 ||
|
| + static_cast<size_t>(button_index) >= button_actions_->size()) {
|
| + // Out of boundary.
|
| + NOTREACHED();
|
| + return;
|
| + }
|
| +
|
| + DownloadCommands::Command command = button_actions_->at(button_index);
|
| + DownloadCommands(item_).ExecuteCommand(command);
|
| +}
|
| +
|
| +// DownloadItem::Observer methods
|
| +void DownloadNotificationItem::OnDownloadUpdated(content::DownloadItem* item) {
|
| + DCHECK_EQ(item, item_);
|
| +
|
| + UpdateNotificationData();
|
| +
|
| + // Updates notification.
|
| + scoped_ptr<Notification> notification(new Notification(*notification_));
|
| + std::string id = notification->id();
|
| + message_center_->UpdateNotification(id, notification.Pass());
|
| +}
|
| +
|
| +void DownloadNotificationItem::UpdateNotificationData() {
|
| + DownloadItemModel model(item_);
|
| + DownloadCommands command(item_);
|
| +
|
| + if (!downloading_) {
|
| + if (item_->GetState() == content::DownloadItem::IN_PROGRESS) {
|
| + delegate_->OnDownloadStarted(this);
|
| + downloading_ = true;
|
| + }
|
| + } else {
|
| + if (item_->GetState() != content::DownloadItem::IN_PROGRESS) {
|
| + delegate_->OnDownloadStopped(this);
|
| + downloading_ = false;
|
| + }
|
| + }
|
| +
|
| + if (item_->IsDangerous()) {
|
| + notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE);
|
| + notification_->set_title(GetTitle());
|
| + notification_->set_message(GetWarningText());
|
| +
|
| + // Show icon.
|
| + SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_MALICIOUS);
|
| + } else {
|
| + notification_->set_title(GetTitle());
|
| + notification_->set_message(model.GetStatusText());
|
| +
|
| + bool is_off_the_record = item_->GetBrowserContext() &&
|
| + item_->GetBrowserContext()->IsOffTheRecord();
|
| +
|
| + switch (item_->GetState()) {
|
| + case content::DownloadItem::IN_PROGRESS:
|
| + notification_->set_type(message_center::NOTIFICATION_TYPE_PROGRESS);
|
| + notification_->set_progress(item_->PercentComplete());
|
| + if (is_off_the_record) {
|
| + // TODO(yoshiki): Replace the tentative image.
|
| + SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_INCOGNITO);
|
| + } else {
|
| + SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING);
|
| + }
|
| + break;
|
| + case content::DownloadItem::COMPLETE:
|
| + notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE);
|
| + if (is_off_the_record) {
|
| + // TODO(yoshiki): Replace the tentative image.
|
| + SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_INCOGNITO);
|
| + } else {
|
| + SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_DOWNLOADING);
|
| + }
|
| +
|
| + // TODO(yoshiki): Popup a notification again.
|
| + break;
|
| + case content::DownloadItem::CANCELLED:
|
| + notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE);
|
| + SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_WARNING);
|
| + break;
|
| + case content::DownloadItem::INTERRUPTED:
|
| + notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE);
|
| + SetNotificationImage(IDR_DOWNLOAD_NOTIFICATION_WARNING);
|
| +
|
| + // TODO(yoshiki): Popup a notification again.
|
| + break;
|
| + case content::DownloadItem::MAX_DOWNLOAD_STATE: // sentinel
|
| + NOTREACHED();
|
| + }
|
| + }
|
| +
|
| + std::vector<message_center::ButtonInfo> notification_actions;
|
| + scoped_ptr<std::vector<DownloadCommands::Command>> actions(
|
| + GetPossibleActions().Pass());
|
| +
|
| + openable_ = false;
|
| + button_actions_.reset(new std::vector<DownloadCommands::Command>);
|
| + for (auto it = actions->begin(); it != actions->end(); it++) {
|
| + if (*it == DownloadCommands::OPEN_WHEN_COMPLETE) {
|
| + openable_ = true;
|
| + } else {
|
| + button_actions_->push_back(*it);
|
| + message_center::ButtonInfo button_info =
|
| + message_center::ButtonInfo(GetCommandLabel(*it));
|
| + button_info.icon = command.GetCommandIcon(*it);
|
| + notification_actions.push_back(button_info);
|
| + }
|
| + }
|
| + notification_->set_buttons(notification_actions);
|
| +
|
| + if (item_->IsDone()) {
|
| + // TODO(yoshiki): If the downloaded file is an image, show the thumbnail.
|
| + }
|
| +}
|
| +
|
| +void DownloadNotificationItem::OnDownloadOpened(content::DownloadItem* item) {
|
| + DCHECK_EQ(item, item_);
|
| + // Do nothing.
|
| +}
|
| +
|
| +void DownloadNotificationItem::OnDownloadRemoved(content::DownloadItem* item) {
|
| + DCHECK_EQ(item, item_);
|
| +
|
| + // Removing the notification causes calling both |OnNotificationClose()| and
|
| + // |OnNotificationRemoved()|.
|
| + message_center_->RemoveNotification(notification_->id(), false);
|
| +}
|
| +
|
| +void DownloadNotificationItem::OnDownloadDestroyed(
|
| + content::DownloadItem* item) {
|
| + DCHECK_EQ(item, item_);
|
| +
|
| + item_ = nullptr;
|
| +}
|
| +
|
| +void DownloadNotificationItem::SetNotificationImage(int resource_id) {
|
| + if (image_resource_id_ == resource_id)
|
| + return;
|
| + ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
|
| + image_resource_id_ = resource_id;
|
| + notification_->set_icon(bundle.GetImageNamed(image_resource_id_));
|
| +}
|
| +
|
| +scoped_ptr<std::vector<DownloadCommands::Command>>
|
| +DownloadNotificationItem::GetPossibleActions() const {
|
| + scoped_ptr<std::vector<DownloadCommands::Command>> actions(
|
| + new std::vector<DownloadCommands::Command>());
|
| +
|
| + if (item_->IsDangerous()) {
|
| + actions->push_back(DownloadCommands::DISCARD);
|
| + actions->push_back(DownloadCommands::KEEP);
|
| + return actions.Pass();
|
| + }
|
| +
|
| + switch (item_->GetState()) {
|
| + case content::DownloadItem::IN_PROGRESS:
|
| + actions->push_back(DownloadCommands::OPEN_WHEN_COMPLETE);
|
| + if (!item_->IsPaused())
|
| + actions->push_back(DownloadCommands::PAUSE);
|
| + else
|
| + actions->push_back(DownloadCommands::RESUME);
|
| + break;
|
| + case content::DownloadItem::CANCELLED:
|
| + case content::DownloadItem::INTERRUPTED:
|
| + actions->push_back(DownloadCommands::RETRY);
|
| + break;
|
| + case content::DownloadItem::COMPLETE:
|
| + actions->push_back(DownloadCommands::OPEN_WHEN_COMPLETE);
|
| + actions->push_back(DownloadCommands::SHOW_IN_FOLDER);
|
| + break;
|
| + case content::DownloadItem::MAX_DOWNLOAD_STATE:
|
| + NOTREACHED();
|
| + }
|
| + return actions.Pass();
|
| +}
|
| +
|
| +base::string16 DownloadNotificationItem::GetTitle() const {
|
| + base::string16 title_text;
|
| + base::string16 file_name =
|
| + item_->GetFileNameToReportUser().LossyDisplayName();
|
| + switch (item_->GetState()) {
|
| + case content::DownloadItem::IN_PROGRESS:
|
| + title_text = l10n_util::GetStringFUTF16(
|
| + IDS_DOWNLOAD_STATUS_IN_PROGRESS_TITLE, file_name);
|
| + break;
|
| + case content::DownloadItem::COMPLETE:
|
| + title_text = l10n_util::GetStringFUTF16(
|
| + IDS_DOWNLOAD_STATUS_DOWNLOADED_TITLE, file_name);
|
| + case content::DownloadItem::INTERRUPTED:
|
| + title_text = l10n_util::GetStringFUTF16(
|
| + IDS_DOWNLOAD_STATUS_DOWNLOADED_TITLE, file_name);
|
| + break;
|
| + case content::DownloadItem::CANCELLED:
|
| + title_text = l10n_util::GetStringFUTF16(
|
| + IDS_DOWNLOAD_STATUS_DOWNLOAD_FAILED_TITLE, file_name);
|
| + break;
|
| + case content::DownloadItem::MAX_DOWNLOAD_STATE:
|
| + NOTREACHED();
|
| + }
|
| + return title_text;
|
| +}
|
| +
|
| +base::string16 DownloadNotificationItem::GetCommandLabel(
|
| + DownloadCommands::Command command) const {
|
| + int id = -1;
|
| + switch (command) {
|
| + case DownloadCommands::OPEN_WHEN_COMPLETE:
|
| + if (item_ && !item_->IsDone())
|
| + id = IDS_DOWNLOAD_STATUS_OPEN_WHEN_COMPLETE;
|
| + else
|
| + id = IDS_DOWNLOAD_STATUS_OPEN_WHEN_COMPLETE;
|
| + break;
|
| + case DownloadCommands::PAUSE:
|
| + // Only for non menu.
|
| + id = IDS_DOWNLOAD_LINK_PAUSE;
|
| + break;
|
| + case DownloadCommands::RESUME:
|
| + // Only for non menu.
|
| + id = IDS_DOWNLOAD_LINK_RESUME;
|
| + break;
|
| + case DownloadCommands::SHOW_IN_FOLDER:
|
| + id = IDS_DOWNLOAD_LINK_SHOW;
|
| + break;
|
| + case DownloadCommands::RETRY:
|
| + // Only for non menu.
|
| + id = IDS_DOWNLOAD_LINK_RETRY;
|
| + break;
|
| + case DownloadCommands::DISCARD:
|
| + id = IDS_DISCARD_DOWNLOAD;
|
| + break;
|
| + case DownloadCommands::KEEP:
|
| + id = IDS_CONFIRM_DOWNLOAD;
|
| + break;
|
| + case DownloadCommands::ALWAYS_OPEN_TYPE:
|
| + case DownloadCommands::PLATFORM_OPEN:
|
| + case DownloadCommands::CANCEL:
|
| + case DownloadCommands::LEARN_MORE_SCANNING:
|
| + case DownloadCommands::LEARN_MORE_INTERRUPTED:
|
| + // Only for menu.
|
| + NOTREACHED();
|
| + return base::string16();
|
| + }
|
| + CHECK(id != -1);
|
| + return l10n_util::GetStringUTF16(id);
|
| +}
|
| +
|
| +base::string16 DownloadNotificationItem::GetWarningText() const {
|
| + // Should only be called if IsDangerous().
|
| + DCHECK(item_->IsDangerous());
|
| + base::string16 elided_filename =
|
| + item_->GetFileNameToReportUser().LossyDisplayName();
|
| + switch (item_->GetDangerType()) {
|
| + case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_URL: {
|
| + return l10n_util::GetStringUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_URL);
|
| + }
|
| + case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE: {
|
| + if (download_crx_util::IsExtensionDownload(*item_)) {
|
| + return l10n_util::GetStringUTF16(
|
| + IDS_PROMPT_DANGEROUS_DOWNLOAD_EXTENSION);
|
| + } else {
|
| + return l10n_util::GetStringFUTF16(IDS_PROMPT_DANGEROUS_DOWNLOAD,
|
| + elided_filename);
|
| + }
|
| + }
|
| + case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT:
|
| + case content::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST: {
|
| + return l10n_util::GetStringFUTF16(IDS_PROMPT_MALICIOUS_DOWNLOAD_CONTENT,
|
| + elided_filename);
|
| + }
|
| + case content::DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT: {
|
| + return l10n_util::GetStringFUTF16(IDS_PROMPT_UNCOMMON_DOWNLOAD_CONTENT,
|
| + elided_filename);
|
| + }
|
| + case content::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED: {
|
| + return l10n_util::GetStringFUTF16(IDS_PROMPT_DOWNLOAD_CHANGES_SETTINGS,
|
| + elided_filename);
|
| + }
|
| + case content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS:
|
| + case content::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT:
|
| + case content::DOWNLOAD_DANGER_TYPE_USER_VALIDATED:
|
| + case content::DOWNLOAD_DANGER_TYPE_MAX: {
|
| + break;
|
| + }
|
| + }
|
| + NOTREACHED();
|
| + return base::string16();
|
| +}
|
|
|