summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbenjhayden@chromium.org <benjhayden@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-31 20:00:08 +0000
committerbenjhayden@chromium.org <benjhayden@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-31 20:00:08 +0000
commit423939db27e73f8fe4dd5402a31856932e52cedb (patch)
treee671c21f50e007d86b6866324b4f93b7edf371cd
parentb7f9bbd4e9c2d9835da8765471206f357efde2aa (diff)
downloadchromium_src-423939db27e73f8fe4dd5402a31856932e52cedb.zip
chromium_src-423939db27e73f8fe4dd5402a31856932e52cedb.tar.gz
chromium_src-423939db27e73f8fe4dd5402a31856932e52cedb.tar.bz2
chrome.downloads.setShelfEnabled(boolean)
Reviewers: meacer: basic idea and features sail: profiles sky: browser/ui/* jam: automation/testing_automation_provider.cc asanka: everything Closes and Disables the shelf for every browser window associated with the Profile associated with the extension. ExtensionDownloadsEventRouter manages a vector of Extensions that have disabled the shelf. When this vector is empty, the shelf is enabled. ExtensionDownloadsEventRouter listens for extension unload events so that the shelf will be re-enabled when the extension is disabled or uninstalled. DownloadShelf access this information through DownloadService, which owns ExtensionDownloadsEventRouter. Extensions need to call setShelfEnabled(false) every time the browser is started. There is no persistence. Requires permission "downloads.shelf" with no warning, as suggested by meacer. Changed DownloadServiceFactory::GetForProfile to GetForBrowserContext so that DownloadShelf can use DownloadItem::GetBrowserContext(). R=asanka@chromium.org, asargent@chromium.org, jam@chromium.org, meacer@chromium.org, sky@chromium.org Review URL: https://codereview.chromium.org/20474002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@214810 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/app_controller_mac.mm2
-rw-r--r--chrome/browser/automation/testing_automation_provider.cc6
-rw-r--r--chrome/browser/download/chrome_download_manager_delegate.cc2
-rw-r--r--chrome/browser/download/download_browsertest.cc11
-rw-r--r--chrome/browser/download/download_service.cc13
-rw-r--r--chrome/browser/download/download_service.h6
-rw-r--r--chrome/browser/download/download_service_factory.cc6
-rw-r--r--chrome/browser/download/download_service_factory.h6
-rw-r--r--chrome/browser/download/download_shelf.cc9
-rw-r--r--chrome/browser/download/download_shelf_unittest.cc30
-rw-r--r--chrome/browser/download/download_test_file_activity_observer.cc2
-rw-r--r--chrome/browser/download/save_page_browsertest.cc5
-rw-r--r--chrome/browser/extensions/api/downloads/downloads_api.cc103
-rw-r--r--chrome/browser/extensions/api/downloads/downloads_api.h30
-rw-r--r--chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc24
-rw-r--r--chrome/browser/extensions/extension_function_histogram_value.h1
-rw-r--r--chrome/browser/profiles/off_the_record_profile_impl.cc2
-rw-r--r--chrome/browser/profiles/profile_impl.cc2
-rw-r--r--chrome/browser/ui/browser.cc2
-rw-r--r--chrome/browser/ui/browser_close_browsertest.cc4
-rw-r--r--chrome/common/extensions/api/_permission_features.json8
-rw-r--r--chrome/common/extensions/api/downloads.idl12
-rw-r--r--chrome/common/extensions/docs/examples/api/downloads/download_manager/background.js3
-rw-r--r--chrome/common/extensions/docs/examples/api/downloads/download_manager/manifest.json2
-rw-r--r--chrome/common/extensions/permissions/api_permission.h1
-rw-r--r--chrome/common/extensions/permissions/chrome_api_permissions.cc1
-rw-r--r--chrome/common/extensions/permissions/permission_set_unittest.cc3
-rw-r--r--chrome/test/data/extensions/api_test/downloads_split/manifest.json1
28 files changed, 256 insertions, 41 deletions
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 04590b1..859a539 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -765,7 +765,7 @@ class AppControllerProfileObserver : public ProfileInfoCacheObserver {
std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
for (size_t i = 0; i < profiles.size(); ++i) {
DownloadService* download_service =
- DownloadServiceFactory::GetForProfile(profiles[i]);
+ DownloadServiceFactory::GetForBrowserContext(profiles[i]);
DownloadManager* download_manager =
(download_service->HasCreatedDownloadManager() ?
BrowserContext::GetDownloadManager(profiles[i]) : NULL);
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index 3dc3d20..7f19416 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -2491,7 +2491,7 @@ void TestingAutomationProvider::GetDownloadsInfo(Browser* browser,
ListValue* list_of_downloads = new ListValue;
DownloadService* download_service(
- DownloadServiceFactory::GetForProfile(browser->profile()));
+ DownloadServiceFactory::GetForBrowserContext(browser->profile()));
if (download_service->HasCreatedDownloadManager()) {
std::vector<DownloadItem*> downloads;
@@ -2523,7 +2523,7 @@ void TestingAutomationProvider::WaitForAllDownloadsToComplete(
}
DownloadService* download_service =
- DownloadServiceFactory::GetForProfile(browser->profile());
+ DownloadServiceFactory::GetForBrowserContext(browser->profile());
if (!download_service->HasCreatedDownloadManager()) {
// No download manager, so no downloads to wait for.
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
@@ -2547,7 +2547,7 @@ void TestingAutomationProvider::PerformActionOnDownload(
std::string action;
DownloadService* download_service =
- DownloadServiceFactory::GetForProfile(browser->profile());
+ DownloadServiceFactory::GetForBrowserContext(browser->profile());
if (!download_service->HasCreatedDownloadManager()) {
AutomationJSONReply(this, reply_message).SendError("No download manager.");
return;
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index e1e1f42..a810537 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -422,7 +422,7 @@ void ChromeDownloadManagerDelegate::NotifyExtensions(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
#if !defined(OS_ANDROID)
ExtensionDownloadsEventRouter* router =
- DownloadServiceFactory::GetForProfile(profile_)->
+ DownloadServiceFactory::GetForBrowserContext(profile_)->
GetExtensionEventRouter();
if (router) {
base::Closure original_path_callback =
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index 4a6b6f7..c065b85 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -386,12 +386,13 @@ class HistoryObserver : public DownloadHistory::Observer {
: profile_(profile),
waiting_(false),
seen_stored_(false) {
- DownloadServiceFactory::GetForProfile(profile_)->
+ DownloadServiceFactory::GetForBrowserContext(profile_)->
GetDownloadHistory()->AddObserver(this);
}
virtual ~HistoryObserver() {
- DownloadService* service = DownloadServiceFactory::GetForProfile(profile_);
+ DownloadService* service = DownloadServiceFactory::GetForBrowserContext(
+ profile_);
if (service && service->GetDownloadHistory())
service->GetDownloadHistory()->RemoveObserver(this);
}
@@ -412,7 +413,7 @@ class HistoryObserver : public DownloadHistory::Observer {
}
virtual void OnDownloadHistoryDestroyed() OVERRIDE {
- DownloadServiceFactory::GetForProfile(profile_)->
+ DownloadServiceFactory::GetForBrowserContext(profile_)->
GetDownloadHistory()->RemoveObserver(this);
}
@@ -3064,9 +3065,9 @@ IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadTest_DenyDanger) {
}
IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadPrefs_SaveFilePath) {
- DownloadPrefs* on_prefs = DownloadServiceFactory::GetForProfile(
+ DownloadPrefs* on_prefs = DownloadServiceFactory::GetForBrowserContext(
browser()->profile())->GetDownloadManagerDelegate()->download_prefs();
- DownloadPrefs* off_prefs = DownloadServiceFactory::GetForProfile(
+ DownloadPrefs* off_prefs = DownloadServiceFactory::GetForBrowserContext(
browser()->profile()->GetOffTheRecordProfile())
->GetDownloadManagerDelegate()->download_prefs();
base::FilePath dir(on_prefs->SaveFilePath());
diff --git a/chrome/browser/download/download_service.cc b/chrome/browser/download/download_service.cc
index 34e5c49..bb75459 100644
--- a/chrome/browser/download/download_service.cc
+++ b/chrome/browser/download/download_service.cc
@@ -102,9 +102,9 @@ int DownloadService::DownloadCountAllProfiles() {
int count = 0;
for (std::vector<Profile*>::iterator it = profiles.begin();
it < profiles.end(); ++it) {
- count += DownloadServiceFactory::GetForProfile(*it)->DownloadCount();
+ count += DownloadServiceFactory::GetForBrowserContext(*it)->DownloadCount();
if ((*it)->HasOffTheRecordProfile())
- count += DownloadServiceFactory::GetForProfile(
+ count += DownloadServiceFactory::GetForBrowserContext(
(*it)->GetOffTheRecordProfile())->DownloadCount();
}
@@ -125,6 +125,15 @@ void DownloadService::SetDownloadManagerDelegateForTesting(
}
}
+bool DownloadService::IsShelfEnabled() {
+#if defined(OS_ANDROID)
+ return true;
+#else
+ return !extension_event_router_ ||
+ extension_event_router_->IsShelfEnabled();
+#endif
+}
+
void DownloadService::Shutdown() {
if (download_manager_created_) {
// Normally the DownloadManager would be shutdown later, after the Profile
diff --git a/chrome/browser/download/download_service.h b/chrome/browser/download/download_service.h
index 30e72e3..3c3f6b6 100644
--- a/chrome/browser/download/download_service.h
+++ b/chrome/browser/download/download_service.h
@@ -5,8 +5,6 @@
#ifndef CHROME_BROWSER_DOWNLOAD_DOWNLOAD_SERVICE_H_
#define CHROME_BROWSER_DOWNLOAD_DOWNLOAD_SERVICE_H_
-#include <vector>
-
#include "base/basictypes.h"
#include "base/callback_forward.h"
#include "base/memory/ref_counted.h"
@@ -62,6 +60,10 @@ class DownloadService : public BrowserContextKeyedService {
// of Profile shutdown.
virtual void Shutdown() OVERRIDE;
+ // Returns false if at least one extension has disabled the shelf, true
+ // otherwise.
+ bool IsShelfEnabled();
+
private:
bool download_manager_created_;
Profile* profile_;
diff --git a/chrome/browser/download/download_service_factory.cc b/chrome/browser/download/download_service_factory.cc
index 28bab78..29b3d17 100644
--- a/chrome/browser/download/download_service_factory.cc
+++ b/chrome/browser/download/download_service_factory.cc
@@ -10,10 +10,10 @@
#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
// static
-DownloadService* DownloadServiceFactory::GetForProfile(
- Profile* profile) {
+DownloadService* DownloadServiceFactory::GetForBrowserContext(
+ content::BrowserContext* context) {
return static_cast<DownloadService*>(
- GetInstance()->GetServiceForBrowserContext(profile, true));
+ GetInstance()->GetServiceForBrowserContext(context, true));
}
// static
diff --git a/chrome/browser/download/download_service_factory.h b/chrome/browser/download/download_service_factory.h
index f98803f..ed78587 100644
--- a/chrome/browser/download/download_service_factory.h
+++ b/chrome/browser/download/download_service_factory.h
@@ -10,15 +10,15 @@
#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h"
class DownloadService;
-class Profile;
// Singleton that owns all DownloadServices and associates them with
// Profiles. Listens for the Profile's destruction notification and cleans up
// the associated DownloadService.
class DownloadServiceFactory : public BrowserContextKeyedServiceFactory {
public:
- // Returns the DownloadService for |profile|, creating if not yet created.
- static DownloadService* GetForProfile(Profile* profile);
+ // Returns the DownloadService for |context|, creating if not yet created.
+ static DownloadService* GetForBrowserContext(
+ content::BrowserContext* context);
static DownloadServiceFactory* GetInstance();
diff --git a/chrome/browser/download/download_shelf.cc b/chrome/browser/download/download_shelf.cc
index d6b8fb6..f262e0a 100644
--- a/chrome/browser/download/download_shelf.cc
+++ b/chrome/browser/download/download_shelf.cc
@@ -8,6 +8,8 @@
#include "base/callback.h"
#include "base/message_loop/message_loop.h"
#include "chrome/browser/download/download_item_model.h"
+#include "chrome/browser/download/download_service.h"
+#include "chrome/browser/download/download_service_factory.h"
#include "chrome/browser/download/download_started_animation.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/profiles/profile.h"
@@ -96,15 +98,16 @@ base::TimeDelta DownloadShelf::GetTransientDownloadShowDelay() {
}
content::DownloadManager* DownloadShelf::GetDownloadManager() {
- DCHECK(browser());
return content::BrowserContext::GetDownloadManager(browser()->profile());
}
void DownloadShelf::ShowDownload(DownloadItem* download) {
if (download->GetState() == DownloadItem::COMPLETE &&
- DownloadItemModel(download).ShouldRemoveFromShelfWhenComplete()) {
+ DownloadItemModel(download).ShouldRemoveFromShelfWhenComplete())
+ return;
+ if (!DownloadServiceFactory::GetForBrowserContext(
+ download->GetBrowserContext())->IsShelfEnabled())
return;
- }
if (is_hidden_)
Unhide();
diff --git a/chrome/browser/download/download_shelf_unittest.cc b/chrome/browser/download/download_shelf_unittest.cc
index 3a16773..c16701b 100644
--- a/chrome/browser/download/download_shelf_unittest.cc
+++ b/chrome/browser/download/download_shelf_unittest.cc
@@ -6,8 +6,14 @@
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/download/download_item_model.h"
+#include "chrome/browser/download/download_service.h"
+#include "chrome/browser/download/download_service_factory.h"
#include "chrome/browser/download/test_download_shelf.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/test/base/testing_profile.h"
+#include "content/public/browser/notification_service.h"
#include "content/public/test/mock_download_item.h"
#include "content/public/test/mock_download_manager.h"
#include "content/public/test/test_browser_thread.h"
@@ -22,6 +28,11 @@ using content::DownloadItem;
namespace {
+BrowserContextKeyedService* CreateDownloadService(
+ content::BrowserContext* context) {
+ return new DownloadService(Profile::FromBrowserContext(context));
+}
+
class DownloadShelfTest : public testing::Test {
public:
DownloadShelfTest();
@@ -36,6 +47,17 @@ class DownloadShelfTest : public testing::Test {
TestDownloadShelf* shelf() {
return &shelf_;
}
+ Profile* profile() { return profile_.get(); }
+
+ virtual void SetUp() OVERRIDE {
+ DownloadServiceFactory::GetInstance()->SetTestingFactory(
+ profile(), &CreateDownloadService);
+ }
+
+ virtual void TearDown() OVERRIDE {
+ DownloadServiceFactory::GetInstance()->SetTestingFactory(
+ profile(), NULL);
+ }
private:
scoped_ptr<content::MockDownloadItem> GetInProgressMockDownload();
@@ -45,10 +67,12 @@ class DownloadShelfTest : public testing::Test {
scoped_ptr<content::MockDownloadItem> download_item_;
scoped_ptr<content::MockDownloadManager> download_manager_;
TestDownloadShelf shelf_;
+ scoped_ptr<TestingProfile> profile_;
};
DownloadShelfTest::DownloadShelfTest()
- : ui_thread_(content::BrowserThread::UI, &message_loop_) {
+ : ui_thread_(content::BrowserThread::UI, &message_loop_),
+ profile_(new TestingProfile()) {
download_item_.reset(new ::testing::NiceMock<content::MockDownloadItem>());
ON_CALL(*download_item_, GetAutoOpened()).WillByDefault(Return(false));
ON_CALL(*download_item_, GetMimeType()).WillByDefault(Return("text/plain"));
@@ -62,11 +86,15 @@ DownloadShelfTest::DownloadShelfTest()
ON_CALL(*download_item_, IsTemporary()).WillByDefault(Return(false));
ON_CALL(*download_item_, ShouldOpenFileBasedOnExtension())
.WillByDefault(Return(false));
+ ON_CALL(*download_item_, GetBrowserContext())
+ .WillByDefault(Return(profile()));
download_manager_.reset(
new ::testing::NiceMock<content::MockDownloadManager>());
ON_CALL(*download_manager_, GetDownload(_))
.WillByDefault(Return(download_item_.get()));
+ ON_CALL(*download_manager_, GetBrowserContext())
+ .WillByDefault(Return(profile()));
shelf_.set_download_manager(download_manager_.get());
}
diff --git a/chrome/browser/download/download_test_file_activity_observer.cc b/chrome/browser/download/download_test_file_activity_observer.cc
index ee14166..5768726 100644
--- a/chrome/browser/download/download_test_file_activity_observer.cc
+++ b/chrome/browser/download/download_test_file_activity_observer.cc
@@ -63,7 +63,7 @@ class DownloadTestFileActivityObserver::MockDownloadManagerDelegate
DownloadTestFileActivityObserver::DownloadTestFileActivityObserver(
Profile* profile) {
test_delegate_ = new MockDownloadManagerDelegate(profile);
- DownloadServiceFactory::GetForProfile(profile)->
+ DownloadServiceFactory::GetForBrowserContext(profile)->
SetDownloadManagerDelegateForTesting(test_delegate_.get());
}
diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc
index afaef69..f108f84 100644
--- a/chrome/browser/download/save_page_browsertest.cc
+++ b/chrome/browser/download/save_page_browsertest.cc
@@ -63,12 +63,13 @@ class DownloadPersistedObserver : public DownloadHistory::Observer {
filter_(filter),
waiting_(false),
persisted_(false) {
- DownloadServiceFactory::GetForProfile(profile_)->
+ DownloadServiceFactory::GetForBrowserContext(profile_)->
GetDownloadHistory()->AddObserver(this);
}
virtual ~DownloadPersistedObserver() {
- DownloadService* service = DownloadServiceFactory::GetForProfile(profile_);
+ DownloadService* service = DownloadServiceFactory::GetForBrowserContext(
+ profile_);
if (service && service->GetDownloadHistory())
service->GetDownloadHistory()->RemoveObserver(this);
}
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.cc b/chrome/browser/extensions/api/downloads/downloads_api.cc
index 20af854..2b6c64a 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api.cc
@@ -50,15 +50,19 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/chrome_render_message_filter.h"
#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/cancelable_task_tracker.h"
#include "chrome/common/extensions/api/downloads.h"
+#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/permissions/permissions_data.h"
#include "content/public/browser/download_interrupt_reasons.h"
#include "content/public/browser/download_item.h"
#include "content/public/browser/download_save_info.h"
#include "content/public/browser/download_url_parameters.h"
+#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/resource_context.h"
@@ -101,6 +105,9 @@ const char kNotDangerous[] = "Download must be dangerous";
const char kNotInProgress[] = "Download must be in progress";
const char kNotResumable[] = "DownloadItem.canResume must be true";
const char kOpenPermission[] = "The \"downloads.open\" permission is required";
+const char kShelfDisabled[] = "Another extension has disabled the shelf";
+const char kShelfPermission[] = "downloads.setShelfEnabled requires the "
+ "\"downloads.shelf\" permission";
const char kTooManyListeners[] = "Each extension may have at most one "
"onDeterminingFilename listener between all of its renderer execution "
"contexts.";
@@ -416,7 +423,7 @@ enum DownloadsFunctionName {
DOWNLOADS_FUNCTION_RESUME = 3,
DOWNLOADS_FUNCTION_CANCEL = 4,
DOWNLOADS_FUNCTION_ERASE = 5,
- DOWNLOADS_FUNCTION_SET_DESTINATION = 6,
+ // 6 unused
DOWNLOADS_FUNCTION_ACCEPT_DANGER = 7,
DOWNLOADS_FUNCTION_SHOW = 8,
DOWNLOADS_FUNCTION_DRAG = 9,
@@ -424,6 +431,7 @@ enum DownloadsFunctionName {
DOWNLOADS_FUNCTION_OPEN = 11,
DOWNLOADS_FUNCTION_REMOVE_FILE = 12,
DOWNLOADS_FUNCTION_SHOW_DEFAULT_FOLDER = 13,
+ DOWNLOADS_FUNCTION_SET_SHELF_ENABLED = 14,
// Insert new values here, not at the beginning.
DOWNLOADS_FUNCTION_LAST
};
@@ -1347,6 +1355,64 @@ bool DownloadsDragFunction::RunImpl() {
return true;
}
+DownloadsSetShelfEnabledFunction::DownloadsSetShelfEnabledFunction() {}
+
+DownloadsSetShelfEnabledFunction::~DownloadsSetShelfEnabledFunction() {}
+
+bool DownloadsSetShelfEnabledFunction::RunImpl() {
+ scoped_ptr<extensions::api::downloads::SetShelfEnabled::Params> params(
+ extensions::api::downloads::SetShelfEnabled::Params::Create(*args_));
+ EXTENSION_FUNCTION_VALIDATE(params.get());
+ if (!GetExtension()->HasAPIPermission(
+ extensions::APIPermission::kDownloadsShelf)) {
+ error_ = download_extension_errors::kShelfPermission;
+ return false;
+ }
+
+ RecordApiFunctions(DOWNLOADS_FUNCTION_SET_SHELF_ENABLED);
+ DownloadManager* manager = NULL;
+ DownloadManager* incognito_manager = NULL;
+ GetManagers(profile(), include_incognito(), &manager, &incognito_manager);
+ DownloadService* service = NULL;
+ DownloadService* incognito_service = NULL;
+ if (manager) {
+ service = DownloadServiceFactory::GetForBrowserContext(
+ manager->GetBrowserContext());
+ service->GetExtensionEventRouter()->SetShelfEnabled(
+ GetExtension(), params->enabled);
+ }
+ if (incognito_manager) {
+ incognito_service = DownloadServiceFactory::GetForBrowserContext(
+ incognito_manager->GetBrowserContext());
+ incognito_service->GetExtensionEventRouter()->SetShelfEnabled(
+ GetExtension(), params->enabled);
+ }
+
+ BrowserList* browsers = BrowserList::GetInstance(chrome::GetActiveDesktop());
+ if (browsers) {
+ for (BrowserList::const_iterator iter = browsers->begin();
+ iter != browsers->end(); ++iter) {
+ const Browser* browser = *iter;
+ DownloadService* current_service =
+ DownloadServiceFactory::GetForBrowserContext(browser->profile());
+ if (((current_service == service) ||
+ (current_service == incognito_service)) &&
+ browser->window()->IsDownloadShelfVisible() &&
+ !current_service->IsShelfEnabled())
+ browser->window()->GetDownloadShelf()->Close(DownloadShelf::AUTOMATIC);
+ }
+ }
+
+ if (params->enabled &&
+ ((manager && !service->IsShelfEnabled()) ||
+ (incognito_manager && !incognito_service->IsShelfEnabled()))) {
+ error_ = download_extension_errors::kShelfDisabled;
+ return false;
+ }
+
+ return true;
+}
+
DownloadsGetFileIconFunction::DownloadsGetFileIconFunction()
: icon_extractor_(new DownloadFileIconExtractorImpl()) {
}
@@ -1404,6 +1470,8 @@ ExtensionDownloadsEventRouter::ExtensionDownloadsEventRouter(
notifier_(manager, this) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(profile_);
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
+ content::Source<Profile>(profile_));
extensions::EventRouter* router = extensions::ExtensionSystem::Get(profile_)->
event_router();
if (router)
@@ -1418,6 +1486,22 @@ ExtensionDownloadsEventRouter::~ExtensionDownloadsEventRouter() {
router->UnregisterObserver(this);
}
+void ExtensionDownloadsEventRouter::SetShelfEnabled(
+ const extensions::Extension* extension, bool enabled) {
+ std::set<const extensions::Extension*>::iterator iter =
+ shelf_disabling_extensions_.find(extension);
+ if (iter == shelf_disabling_extensions_.end()) {
+ if (!enabled)
+ shelf_disabling_extensions_.insert(extension);
+ } else if (enabled) {
+ shelf_disabling_extensions_.erase(extension);
+ }
+}
+
+bool ExtensionDownloadsEventRouter::IsShelfEnabled() const {
+ return shelf_disabling_extensions_.empty();
+}
+
// The method by which extensions hook into the filename determination process
// is based on the method by which the omnibox API allows extensions to hook
// into the omnibox autocompletion process. Extensions that wish to play a part
@@ -1707,3 +1791,20 @@ void ExtensionDownloadsEventRouter::DispatchEvent(
content_source,
content::Details<std::string>(&json_args));
}
+
+void ExtensionDownloadsEventRouter::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ switch (type) {
+ case chrome::NOTIFICATION_EXTENSION_UNLOADED: {
+ extensions::UnloadedExtensionInfo* unloaded =
+ content::Details<extensions::UnloadedExtensionInfo>(details).ptr();
+ std::set<const extensions::Extension*>::iterator iter =
+ shelf_disabling_extensions_.find(unloaded->extension);
+ if (iter != shelf_disabling_extensions_.end())
+ shelf_disabling_extensions_.erase(iter);
+ break;
+ }
+ }
+}
diff --git a/chrome/browser/extensions/api/downloads/downloads_api.h b/chrome/browser/extensions/api/downloads/downloads_api.h
index 9d8674e..16575f8 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api.h
+++ b/chrome/browser/extensions/api/downloads/downloads_api.h
@@ -5,6 +5,7 @@
#ifndef CHROME_BROWSER_EXTENSIONS_API_DOWNLOADS_DOWNLOADS_API_H_
#define CHROME_BROWSER_EXTENSIONS_API_DOWNLOADS_DOWNLOADS_API_H_
+#include <set>
#include <string>
#include "base/files/file_path.h"
@@ -19,6 +20,8 @@
#include "chrome/common/extensions/api/downloads.h"
#include "content/public/browser/download_item.h"
#include "content/public/browser/download_manager.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
class DownloadFileIconExtractor;
class DownloadQuery;
@@ -54,6 +57,8 @@ extern const char kNotDangerous[];
extern const char kNotInProgress[];
extern const char kNotResumable[];
extern const char kOpenPermission[];
+extern const char kShelfDisabled[];
+extern const char kShelfPermission[];
extern const char kTooManyListeners[];
extern const char kUnexpectedDeterminer[];
@@ -239,6 +244,20 @@ class DownloadsOpenFunction : public SyncExtensionFunction {
DISALLOW_COPY_AND_ASSIGN(DownloadsOpenFunction);
};
+class DownloadsSetShelfEnabledFunction : public SyncExtensionFunction {
+ public:
+ DECLARE_EXTENSION_FUNCTION("downloads.setShelfEnabled",
+ DOWNLOADS_SETSHELFENABLED)
+ DownloadsSetShelfEnabledFunction();
+ virtual bool RunImpl() OVERRIDE;
+
+ protected:
+ virtual ~DownloadsSetShelfEnabledFunction();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DownloadsSetShelfEnabledFunction);
+};
+
class DownloadsDragFunction : public AsyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("downloads.drag", DOWNLOADS_DRAG)
@@ -272,6 +291,7 @@ class DownloadsGetFileIconFunction : public AsyncExtensionFunction {
// Observes a single DownloadManager and many DownloadItems and dispatches
// onCreated and onErased events.
class ExtensionDownloadsEventRouter : public extensions::EventRouter::Observer,
+ public content::NotificationObserver,
public AllDownloadItemNotifier::Observer {
public:
typedef base::Callback<void(
@@ -298,6 +318,9 @@ class ExtensionDownloadsEventRouter : public extensions::EventRouter::Observer,
Profile* profile, content::DownloadManager* manager);
virtual ~ExtensionDownloadsEventRouter();
+ void SetShelfEnabled(const extensions::Extension* extension, bool enabled);
+ bool IsShelfEnabled() const;
+
// Called by ChromeDownloadManagerDelegate during the filename determination
// process, allows extensions to change the item's target filename. If no
// extension wants to change the target filename, then |no_change| will be
@@ -339,8 +362,15 @@ class ExtensionDownloadsEventRouter : public extensions::EventRouter::Observer,
const extensions::Event::WillDispatchCallback& will_dispatch_callback,
base::Value* json_arg);
+ // content::NotificationObserver
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
Profile* profile_;
AllDownloadItemNotifier notifier_;
+ std::set<const extensions::Extension*> shelf_disabling_extensions_;
+ content::NotificationRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(ExtensionDownloadsEventRouter);
};
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
index 2838bbd..0d950da 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -527,8 +527,12 @@ class DownloadExtensionTest : public ExtensionApiTest {
const std::string& args) {
scoped_refptr<UIThreadExtensionFunction> delete_function(function);
SetUpExtensionFunction(function);
- return extension_function_test_utils::RunFunction(
+ bool result = extension_function_test_utils::RunFunction(
function, args, browser(), GetFlags());
+ if (!result) {
+ LOG(ERROR) << function->GetError();
+ }
+ return result;
}
extension_function_test_utils::RunFunctionFlags GetFlags() {
@@ -3592,6 +3596,23 @@ IN_PROC_BROWSER_TEST_F(
item->GetId())));
}
+IN_PROC_BROWSER_TEST_F(DownloadExtensionTest,
+ DownloadExtensionTest_SetShelfEnabled) {
+ LoadExtension("downloads_split");
+ EXPECT_TRUE(RunFunction(new DownloadsSetShelfEnabledFunction(), "[false]"));
+ EXPECT_FALSE(DownloadServiceFactory::GetForBrowserContext(
+ browser()->profile())->IsShelfEnabled());
+ EXPECT_TRUE(RunFunction(new DownloadsSetShelfEnabledFunction(), "[true]"));
+ EXPECT_TRUE(DownloadServiceFactory::GetForBrowserContext(
+ browser()->profile())->IsShelfEnabled());
+ // TODO(benjhayden) Test that existing shelves are hidden.
+ // TODO(benjhayden) Test multiple extensions.
+ // TODO(benjhayden) Test disabling extensions.
+ // TODO(benjhayden) Test that browsers associated with other profiles are not
+ // affected.
+ // TODO(benjhayden) Test incognito.
+}
+
// TODO(benjhayden) Figure out why DisableExtension() does not fire
// OnListenerRemoved.
@@ -3611,7 +3632,6 @@ IN_PROC_BROWSER_TEST_F(DownloadsApiTest, DownloadsApiTest) {
ASSERT_TRUE(RunExtensionTest("downloads")) << message_;
}
-
TEST(DownloadInterruptReasonEnumsSynced,
DownloadInterruptReasonEnumsSynced) {
#define INTERRUPT_REASON(name, value) \
diff --git a/chrome/browser/extensions/extension_function_histogram_value.h b/chrome/browser/extensions/extension_function_histogram_value.h
index d969cbf..480f813 100644
--- a/chrome/browser/extensions/extension_function_histogram_value.h
+++ b/chrome/browser/extensions/extension_function_histogram_value.h
@@ -581,6 +581,7 @@ enum HistogramValue {
DOWNLOADS_REMOVEFILE,
DOWNLOADS_SHOWDEFAULTFOLDER,
INFOBARS_SHOW,
+ DOWNLOADS_SETSHELFENABLED,
ENUM_BOUNDARY // Last entry: Add new entries above.
};
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index 5ead5e3..46df82e 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -243,7 +243,7 @@ PrefService* OffTheRecordProfileImpl::GetOffTheRecordPrefs() {
}
DownloadManagerDelegate* OffTheRecordProfileImpl::GetDownloadManagerDelegate() {
- return DownloadServiceFactory::GetForProfile(this)->
+ return DownloadServiceFactory::GetForBrowserContext(this)->
GetDownloadManagerDelegate();
}
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 9092e56..64492fc 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -912,7 +912,7 @@ content::GeolocationPermissionContext*
}
DownloadManagerDelegate* ProfileImpl::GetDownloadManagerDelegate() {
- return DownloadServiceFactory::GetForProfile(this)->
+ return DownloadServiceFactory::GetForBrowserContext(this)->
GetDownloadManagerDelegate();
}
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index a9835f4..1d4ca5d 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -718,7 +718,7 @@ Browser::DownloadClosePreventionType Browser::OkToCloseWithInProgressDownloads(
// profile, and there are downloads associated with that profile,
// those downloads would be cancelled by our window (-> profile) close.
DownloadService* download_service =
- DownloadServiceFactory::GetForProfile(profile());
+ DownloadServiceFactory::GetForBrowserContext(profile());
if ((profile_window_count == 0) &&
(download_service->DownloadCount() > 0) &&
profile()->IsOffTheRecord()) {
diff --git a/chrome/browser/ui/browser_close_browsertest.cc b/chrome/browser/ui/browser_close_browsertest.cc
index 608c48d..4f2b145 100644
--- a/chrome/browser/ui/browser_close_browsertest.cc
+++ b/chrome/browser/ui/browser_close_browsertest.cc
@@ -151,7 +151,7 @@ class BrowserCloseTest : public InProcessBrowserTest {
for (std::vector<Profile*>::const_iterator pit = profiles.begin();
pit != profiles.end(); ++pit) {
DownloadService* download_service =
- DownloadServiceFactory::GetForProfile(*pit);
+ DownloadServiceFactory::GetForBrowserContext(*pit);
if (download_service->HasCreatedDownloadManager()) {
DownloadManager *mgr = BrowserContext::GetDownloadManager(*pit);
scoped_refptr<content::DownloadTestFlushObserver> observer(
@@ -160,7 +160,7 @@ class BrowserCloseTest : public InProcessBrowserTest {
}
if ((*pit)->HasOffTheRecordProfile()) {
DownloadService* incognito_download_service =
- DownloadServiceFactory::GetForProfile(
+ DownloadServiceFactory::GetForBrowserContext(
(*pit)->GetOffTheRecordProfile());
if (incognito_download_service->HasCreatedDownloadManager()) {
DownloadManager *mgr = BrowserContext::GetDownloadManager(
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index 59c1025..815177b 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -189,14 +189,16 @@
],
"downloads": {
"channel": "beta",
- "extension_types": [
- "extension"
- ]
+ "extension_types": ["extension"]
},
"downloads.open": {
"channel": "beta",
"extension_types": ["extension"]
},
+ "downloads.shelf": {
+ "channel": "beta",
+ "extension_types": ["extension"]
+ },
"dial": {
"channel": "stable",
"extension_types": ["extension"],
diff --git a/chrome/common/extensions/api/downloads.idl b/chrome/common/extensions/api/downloads.idl
index 173a7b6..e13d3aa 100644
--- a/chrome/common/extensions/api/downloads.idl
+++ b/chrome/common/extensions/api/downloads.idl
@@ -111,7 +111,9 @@ namespace downloads {
// <dt>accepted</dt>
// <dd>The user has accepted the dangerous download.</dd>
// </dl>
- enum DangerType {file, url, content, uncommon, host, unwanted, safe, accepted};
+ enum DangerType {
+ file, url, content, uncommon, host, unwanted, safe, accepted
+ };
// <dl><dt>in_progress</dt>
// <dd>The download is currently receiving data from the server.</dd>
@@ -489,6 +491,14 @@ namespace downloads {
// Initiate dragging the downloaded file to another application. Call in a
// javascript <code>ondragstart</code> handler.
static void drag(long downloadId);
+
+ // Enable or disable the gray shelf at the bottom of every window associated
+ // with the current browser profile. The shelf will be disabled as long as
+ // at least one extension has disabled it. Enabling the shelf while at least
+ // one other extension has disabled it will return an error through
+ // $ref:runtime.lastError. Requires the <code>"downloads.shelf"</code>
+ // permission in addition to the <code>"downloads"</code> permission.
+ static void setShelfEnabled(boolean enabled);
};
interface Events {
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_manager/background.js b/chrome/common/extensions/docs/examples/api/downloads/download_manager/background.js
index ffc2a4d..28e6075 100644
--- a/chrome/common/extensions/docs/examples/api/downloads/download_manager/background.js
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_manager/background.js
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+if (chrome.downloads.setShelfEnabled)
+ chrome.downloads.setShelfEnabled(false);
+
var colors = {
progressColor: '#0d0',
arrow: '#555',
diff --git a/chrome/common/extensions/docs/examples/api/downloads/download_manager/manifest.json b/chrome/common/extensions/docs/examples/api/downloads/download_manager/manifest.json
index 85f2d0e..1141c0d 100644
--- a/chrome/common/extensions/docs/examples/api/downloads/download_manager/manifest.json
+++ b/chrome/common/extensions/docs/examples/api/downloads/download_manager/manifest.json
@@ -11,4 +11,4 @@
"default_popup": "popup.html"},
"background": {"persistent": false, "scripts": ["background.js"]},
"default_locale": "en",
- "permissions": ["management", "downloads", "downloads.open"]}
+ "permissions": ["management", "downloads", "downloads.open", "downloads.shelf"]}
diff --git a/chrome/common/extensions/permissions/api_permission.h b/chrome/common/extensions/permissions/api_permission.h
index 2266a27..e14ce92 100644
--- a/chrome/common/extensions/permissions/api_permission.h
+++ b/chrome/common/extensions/permissions/api_permission.h
@@ -69,6 +69,7 @@ class APIPermission {
kDownloads,
kDownloadsInternal,
kDownloadsOpen,
+ kDownloadsShelf,
kEchoPrivate,
kEnterprisePlatformKeysPrivate,
kExperimental,
diff --git a/chrome/common/extensions/permissions/chrome_api_permissions.cc b/chrome/common/extensions/permissions/chrome_api_permissions.cc
index 45ad574..53a22be 100644
--- a/chrome/common/extensions/permissions/chrome_api_permissions.cc
+++ b/chrome/common/extensions/permissions/chrome_api_permissions.cc
@@ -54,6 +54,7 @@ std::vector<APIPermissionInfo*> ChromeAPIPermissions::GetAllPermissions()
APIPermissionInfo::kFlagNone,
IDS_EXTENSION_PROMPT_WARNING_DOWNLOADS_OPEN,
PermissionMessage::kDownloadsOpen },
+ { APIPermission::kDownloadsShelf, "downloads.shelf" },
{ APIPermission::kIdentity, "identity" },
{ APIPermission::kExperimental, "experimental",
APIPermissionInfo::kFlagCannotBeOptional },
diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc
index 9e784fc..8c4540b 100644
--- a/chrome/common/extensions/permissions/permission_set_unittest.cc
+++ b/chrome/common/extensions/permissions/permission_set_unittest.cc
@@ -643,6 +643,7 @@ TEST(PermissionsTest, PermissionMessages) {
skip.insert(APIPermission::kBrowsingData);
skip.insert(APIPermission::kContextMenus);
skip.insert(APIPermission::kDiagnostics);
+ skip.insert(APIPermission::kDownloadsShelf);
skip.insert(APIPermission::kFontSettings);
skip.insert(APIPermission::kFullscreen);
skip.insert(APIPermission::kIdle);
@@ -650,8 +651,8 @@ TEST(PermissionsTest, PermissionMessages) {
skip.insert(APIPermission::kPointerLock);
skip.insert(APIPermission::kPower);
skip.insert(APIPermission::kPushMessaging);
- skip.insert(APIPermission::kSessionRestore);
skip.insert(APIPermission::kScreensaver);
+ skip.insert(APIPermission::kSessionRestore);
skip.insert(APIPermission::kStorage);
skip.insert(APIPermission::kSystemCpu);
skip.insert(APIPermission::kSystemDisplay);
diff --git a/chrome/test/data/extensions/api_test/downloads_split/manifest.json b/chrome/test/data/extensions/api_test/downloads_split/manifest.json
index 96e4cde..1eaa6e1 100644
--- a/chrome/test/data/extensions/api_test/downloads_split/manifest.json
+++ b/chrome/test/data/extensions/api_test/downloads_split/manifest.json
@@ -8,6 +8,7 @@
"permissions": [
"downloads",
"downloads.open",
+ "downloads.shelf",
"http://*/*",
"file://*"
]