blob: 8c775919cf38a2ce3b35ec1a2ddc46a9acb28349 [file] [log] [blame]
// 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_manager.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_item_model.h"
#include "chrome/browser/download/notification/download_item_notification.h"
#include "chrome/browser/notifications/notification_common.h"
#include "chrome/browser/notifications/notification_display_service.h"
#include "chrome/browser/notifications/notification_display_service_factory.h"
#include "chrome/browser/notifications/notification_handler.h"
#include "chrome/common/chrome_switches.h"
#include "content/public/browser/download_item.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/message_center/notification.h"
#include "ui/message_center/notification_delegate.h"
namespace {
class DownloadNotificationHandler : public NotificationHandler {
public:
explicit DownloadNotificationHandler(
DownloadNotificationManagerForProfile* manager)
: manager_(manager) {}
~DownloadNotificationHandler() override = default;
void OnClose(Profile* profile,
const GURL& origin,
const std::string& notification_id,
bool by_user,
base::OnceClosure completed_closure) override {
if (by_user) {
manager_->GetNotificationItemByGuid(notification_id)
->OnNotificationClose();
}
std::move(completed_closure).Run();
}
void OnClick(Profile* profile,
const GURL& origin,
const std::string& notification_id,
const base::Optional<int>& action_index,
const base::Optional<base::string16>& reply,
base::OnceClosure completed_closure) override {
DownloadItemNotification* item =
manager_->GetNotificationItemByGuid(notification_id);
if (!action_index)
item->OnNotificationClick();
else
item->OnNotificationButtonClick(*action_index);
std::move(completed_closure).Run();
}
private:
DownloadNotificationManagerForProfile* manager_;
DISALLOW_COPY_AND_ASSIGN(DownloadNotificationHandler);
};
} // namespace
///////////////////////////////////////////////////////////////////////////////
// DownloadNotificationManager implementation:
///////////////////////////////////////////////////////////////////////////////
DownloadNotificationManager::DownloadNotificationManager(Profile* profile)
: main_profile_(profile) {}
DownloadNotificationManager::~DownloadNotificationManager() = default;
void DownloadNotificationManager::OnAllDownloadsRemoving(Profile* profile) {
manager_for_profile_.erase(profile);
}
void DownloadNotificationManager::OnNewDownloadReady(
content::DownloadItem* download) {
Profile* profile = Profile::FromBrowserContext(download->GetBrowserContext());
if (manager_for_profile_.find(profile) == manager_for_profile_.end()) {
manager_for_profile_[profile] =
base::MakeUnique<DownloadNotificationManagerForProfile>(profile, this);
}
manager_for_profile_[profile]->OnNewDownloadReady(download);
}
DownloadNotificationManagerForProfile*
DownloadNotificationManager::GetForProfile(Profile* profile) const {
return manager_for_profile_.at(profile).get();
}
///////////////////////////////////////////////////////////////////////////////
// DownloadNotificationManagerForProfile implementation:
///////////////////////////////////////////////////////////////////////////////
DownloadNotificationManagerForProfile::DownloadNotificationManagerForProfile(
Profile* profile,
DownloadNotificationManager* parent_manager)
: profile_(profile), parent_manager_(parent_manager) {
NotificationDisplayService* service =
NotificationDisplayServiceFactory::GetForProfile(profile);
DCHECK(!service->GetNotificationHandler(NotificationCommon::DOWNLOAD));
service->AddNotificationHandler(
NotificationCommon::DOWNLOAD,
std::make_unique<DownloadNotificationHandler>(this));
}
DownloadNotificationManagerForProfile::
~DownloadNotificationManagerForProfile() {
NotificationDisplayServiceFactory::GetForProfile(profile_)
->RemoveNotificationHandler(NotificationCommon::DOWNLOAD);
for (const auto& download : items_) {
download.first->RemoveObserver(this);
}
}
void DownloadNotificationManagerForProfile::OnDownloadUpdated(
content::DownloadItem* changed_download) {
DCHECK(items_.find(changed_download) != items_.end());
items_[changed_download]->OnDownloadUpdated(changed_download);
}
void DownloadNotificationManagerForProfile::OnDownloadOpened(
content::DownloadItem* changed_download) {
items_[changed_download]->OnDownloadUpdated(changed_download);
}
void DownloadNotificationManagerForProfile::OnDownloadRemoved(
content::DownloadItem* download) {
DCHECK(items_.find(download) != items_.end());
std::unique_ptr<DownloadItemNotification> item = std::move(items_[download]);
items_.erase(download);
download->RemoveObserver(this);
// notify
item->OnDownloadRemoved(download);
// This removing might be initiated from DownloadNotificationItem, so delaying
// deleting for item to do remaining cleanups.
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, item.release());
if (items_.size() == 0 && parent_manager_)
parent_manager_->OnAllDownloadsRemoving(profile_);
// |this| is deleted.
}
void DownloadNotificationManagerForProfile::OnDownloadDestroyed(
content::DownloadItem* download) {
// Do nothing. Cleanup is done in OnDownloadRemoved().
std::unique_ptr<DownloadItemNotification> item = std::move(items_[download]);
items_.erase(download);
item->OnDownloadRemoved(download);
// This removing might be initiated from DownloadNotificationItem, so delaying
// deleting for item to do remaining cleanups.
base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, item.release());
if (items_.size() == 0 && parent_manager_)
parent_manager_->OnAllDownloadsRemoving(profile_);
// |this| is deleted.
}
void DownloadNotificationManagerForProfile::OnNewDownloadReady(
content::DownloadItem* download) {
DCHECK_EQ(profile_,
Profile::FromBrowserContext(download->GetBrowserContext()));
download->AddObserver(this);
for (auto& item : items_) {
content::DownloadItem* download_item = item.first;
DownloadItemNotification* download_notification = item.second.get();
if (download_item->GetState() == content::DownloadItem::IN_PROGRESS)
download_notification->DisablePopup();
}
items_[download] = std::make_unique<DownloadItemNotification>(download, this);
}
DownloadItemNotification*
DownloadNotificationManagerForProfile::GetNotificationItemByGuid(
const std::string& guid) {
for (auto& item : items_) {
if (item.first->GetGuid() == guid)
return item.second.get();
}
NOTREACHED();
return nullptr;
}