diff options
17 files changed, 241 insertions, 8 deletions
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc index 1e54e65..8bb5d71 100644 --- a/chrome/browser/background/background_mode_manager.cc +++ b/chrome/browser/background/background_mode_manager.cc @@ -309,7 +309,12 @@ void BackgroundModeManager::Observe( // treated as new installs. if (extensions::ExtensionSystem::Get(profile)->extension_service()-> is_ready()) { - OnBackgroundAppInstalled(extension); + bool is_being_reloaded = false; + CheckReloadStatus(extension, &is_being_reloaded); + // No need to show the notification if we showed to the user + // previously for this app. + if (!is_being_reloaded) + OnBackgroundAppInstalled(extension); } } } @@ -623,8 +628,25 @@ void BackgroundModeManager::OnBackgroundAppInstalled( CreateStatusTrayIcon(); // Notify the user that a background app has been installed. - if (extension) // NULL when called by unit tests. + if (extension) { // NULL when called by unit tests. DisplayAppInstalledNotification(extension); + } +} + +void BackgroundModeManager::CheckReloadStatus( + const Extension* extension, + bool* is_being_reloaded) { + // Walk the BackgroundModeData for all profiles to see if one of their + // extensions is being reloaded. + for (BackgroundModeInfoMap::const_iterator it = + background_mode_data_.begin(); + it != background_mode_data_.end(); + ++it) { + Profile* profile = it->first; + // If the extension is being reloaded, no need to show a notification. + if (profile->GetExtensionService()->IsBeingReloaded(extension->id())) + *is_being_reloaded = true; + } } void BackgroundModeManager::CreateStatusTrayIcon() { diff --git a/chrome/browser/background/background_mode_manager.h b/chrome/browser/background/background_mode_manager.h index 1600cd1..e1c8051 100644 --- a/chrome/browser/background/background_mode_manager.h +++ b/chrome/browser/background/background_mode_manager.h @@ -85,6 +85,9 @@ class BackgroundModeManager ProfileInfoCacheStorage); FRIEND_TEST_ALL_PREFIXES(BackgroundModeManagerTest, ProfileInfoCacheObserver); + FRIEND_TEST_ALL_PREFIXES(BackgroundAppBrowserTest, + ReloadBackgroundApp); + class BackgroundModeData : public ui::SimpleMenuModel::Delegate { public: explicit BackgroundModeData( @@ -183,7 +186,15 @@ class BackgroundModeManager // Invoked when an extension is installed so we can ensure that // launch-on-startup is enabled if appropriate. |extension| can be NULL when // called from unit tests. - void OnBackgroundAppInstalled(const extensions::Extension* extension); + void OnBackgroundAppInstalled( + const extensions::Extension* extension); + + // Walk the list of profiles and see if an extension or app is being + // currently upgraded or reloaded by any profile. If so, update the + // output variables appropriately. + void CheckReloadStatus( + const extensions::Extension* extension, + bool* is_being_reloaded); // Called to make sure that our launch-on-startup mode is properly set. // (virtual so we can override for tests). @@ -191,7 +202,8 @@ class BackgroundModeManager // Invoked when a background app is installed so we can display a // platform-specific notification to the user. - void DisplayAppInstalledNotification(const extensions::Extension* extension); + virtual void DisplayAppInstalledNotification( + const extensions::Extension* extension); // Invoked to put Chrome in KeepAlive mode - chrome runs in the background // and has a status bar icon. diff --git a/chrome/browser/browser_process.h b/chrome/browser/browser_process.h index d6f8595..0824b1c 100644 --- a/chrome/browser/browser_process.h +++ b/chrome/browser/browser_process.h @@ -13,6 +13,7 @@ #include <string> #include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" #include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/ui/host_desktop.h" @@ -175,6 +176,8 @@ class BrowserProcess { // Returns the object that manages background applications. virtual BackgroundModeManager* background_mode_manager() = 0; + virtual void set_background_mode_manager_for_test( + scoped_ptr<BackgroundModeManager> manager) = 0; // Returns the StatusTray, which provides an API for displaying status icons // in the system status tray. Returns NULL if status icons are not supported diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index 44bf2da..6673807 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc @@ -704,6 +704,11 @@ BackgroundModeManager* BrowserProcessImpl::background_mode_manager() { #endif } +void BrowserProcessImpl::set_background_mode_manager_for_test( + scoped_ptr<BackgroundModeManager> manager) { + background_mode_manager_ = manager.Pass(); +} + StatusTray* BrowserProcessImpl::status_tray() { DCHECK(CalledOnValidThread()); if (!status_tray_.get()) diff --git a/chrome/browser/browser_process_impl.h b/chrome/browser/browser_process_impl.h index 201eb92..020bd42 100644 --- a/chrome/browser/browser_process_impl.h +++ b/chrome/browser/browser_process_impl.h @@ -110,6 +110,8 @@ class BrowserProcessImpl : public BrowserProcess, virtual DownloadStatusUpdater* download_status_updater() OVERRIDE; virtual DownloadRequestLimiter* download_request_limiter() OVERRIDE; virtual BackgroundModeManager* background_mode_manager() OVERRIDE; + virtual void set_background_mode_manager_for_test( + scoped_ptr<BackgroundModeManager> manager) OVERRIDE; virtual StatusTray* status_tray() OVERRIDE; virtual SafeBrowsingService* safe_browsing_service() OVERRIDE; virtual safe_browsing::ClientSideDetectionService* diff --git a/chrome/browser/extensions/background_app_browsertest.cc b/chrome/browser/extensions/background_app_browsertest.cc new file mode 100644 index 0000000..7951e40 --- /dev/null +++ b/chrome/browser/extensions/background_app_browsertest.cc @@ -0,0 +1,78 @@ +// Copyright 2013 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/background/background_mode_manager.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/extensions/extension_browsertest.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/test/base/ui_test_utils.h" + +class TestBackgroundModeManager : public BackgroundModeManager { + public: + TestBackgroundModeManager(CommandLine* command_line, + ProfileInfoCache* profile_cache) + : BackgroundModeManager(command_line, profile_cache), + showed_background_app_installed_notification_for_test_(false) {} + + virtual ~TestBackgroundModeManager() {} + + virtual void DisplayAppInstalledNotification( + const extensions::Extension* extension) OVERRIDE { + showed_background_app_installed_notification_for_test_ = true; + } + + bool showed_background_app_installed_notification_for_test() { + return showed_background_app_installed_notification_for_test_; + } + + void set_showed_background_app_installed_notification_for_test( + bool showed) { + showed_background_app_installed_notification_for_test_ = showed; + } + + private: + // Tracks if we have shown a "Background App Installed" notification to the + // user. Used for unit tests only. + bool showed_background_app_installed_notification_for_test_; + + FRIEND_TEST_ALL_PREFIXES(BackgroundAppBrowserTest, + ReloadBackgroundApp); + + DISALLOW_COPY_AND_ASSIGN(TestBackgroundModeManager); +}; + +class BackgroundAppBrowserTest: public ExtensionBrowserTest {}; + +// Tests that if we reload a background app, we don't get a popup bubble +// telling us that a new background app has been installed. +IN_PROC_BROWSER_TEST_F(BackgroundAppBrowserTest, ReloadBackgroundApp) { + + // Pass this in to the browser test. + scoped_ptr<BackgroundModeManager> test_background_mode_manager( + new TestBackgroundModeManager( + CommandLine::ForCurrentProcess(), + &(g_browser_process->profile_manager()->GetProfileInfoCache()))); + g_browser_process->set_background_mode_manager_for_test( + test_background_mode_manager.Pass()); + TestBackgroundModeManager* manager = + reinterpret_cast<TestBackgroundModeManager*>( + g_browser_process->background_mode_manager()); + + // Load our background extension + ASSERT_FALSE( + manager->showed_background_app_installed_notification_for_test()); + const extensions::Extension* extension = LoadExtension( + test_data_dir_.AppendASCII("background_app")); + ASSERT_FALSE(extension == NULL); + + // Set the test flag to not shown. + manager->set_showed_background_app_installed_notification_for_test(false); + + // Reload our background extension + ReloadExtension(extension->id()); + + // Ensure that we did not see a "Background extension loaded" dialog. + EXPECT_FALSE( + manager->showed_background_app_installed_notification_for_test()); +} diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc index c2ec75b..126f27b 100644 --- a/chrome/browser/extensions/extension_browsertest.cc +++ b/chrome/browser/extensions/extension_browsertest.cc @@ -452,7 +452,7 @@ const Extension* ExtensionBrowserTest::InstallOrUpdateExtension( return service->GetExtensionById(last_loaded_extension_id_, false); } -void ExtensionBrowserTest::ReloadExtension(const std::string& extension_id) { +void ExtensionBrowserTest::ReloadExtension(const std::string extension_id) { ExtensionService* service = extensions::ExtensionSystem::Get( profile())->extension_service(); service->ReloadExtension(extension_id); diff --git a/chrome/browser/extensions/extension_browsertest.h b/chrome/browser/extensions/extension_browsertest.h index ef2b4c8..2b750c3 100644 --- a/chrome/browser/extensions/extension_browsertest.h +++ b/chrome/browser/extensions/extension_browsertest.h @@ -170,7 +170,7 @@ class ExtensionBrowserTest : virtual public InProcessBrowserTest, std::string(), path, INSTALL_UI_TYPE_CANCEL, 0); } - void ReloadExtension(const std::string& extension_id); + void ReloadExtension(const std::string extension_id); void UnloadExtension(const std::string& extension_id); diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index ab91a0b..2458305f 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc @@ -669,7 +669,7 @@ bool ExtensionService::UpdateExtension(const std::string& id, return true; } -void ExtensionService::ReloadExtension(const std::string& extension_id) { +void ExtensionService::ReloadExtension(const std::string extension_id) { CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); // If the extension is already reloading, don't reload again. @@ -713,12 +713,15 @@ void ExtensionService::ReloadExtension(const std::string& extension_id) { // If we're reloading a component extension, use the component extension // loader's reloader. if (component_loader_->Exists(extension_id)) { + SetBeingReloaded(extension_id, true); component_loader_->Reload(extension_id); + SetBeingReloaded(extension_id, false); return; } // Check the installed extensions to see if what we're reloading was already // installed. + SetBeingReloaded(extension_id, true); scoped_ptr<ExtensionInfo> installed_extension( extension_prefs_->GetInstalledExtensionInfo(extension_id)); if (installed_extension.get() && @@ -731,6 +734,8 @@ void ExtensionService::ReloadExtension(const std::string& extension_id) { CHECK(!path.empty()); extensions::UnpackedInstaller::Create(this)->Load(path); } + // When reloading is done, mark this extension as done reloading. + SetBeingReloaded(extension_id, false); } bool ExtensionService::UninstallExtension( @@ -2863,6 +2868,27 @@ void ExtensionService::SetBeingUpgraded(const Extension* extension, extension_runtime_data_[extension->id()].being_upgraded = value; } +bool ExtensionService::IsBeingReloaded( + const std::string& extension_id) const { + return ContainsKey(extensions_being_reloaded_, extension_id); +} + +void ExtensionService::SetBeingReloaded(const std::string& extension_id, + bool isBeingReloaded) { + LOG(INFO) << "****** " << __FUNCTION__; + LOG(INFO) << "****** " << __FUNCTION__ << " extension_id is: " + << extension_id << " and isBeingReloaded is " << isBeingReloaded; + LOG(INFO) << "****** " << __FUNCTION__ << " Set size is " + << extensions_being_reloaded_.size(); + if (isBeingReloaded) { + extensions_being_reloaded_.insert(extension_id); + LOG(INFO) << "****** " << __FUNCTION__ << " insert succeeded."; + } else { + extensions_being_reloaded_.erase(extension_id); + LOG(INFO) << "****** " << __FUNCTION__ << " erase succeeded."; + } +} + bool ExtensionService::HasUsedWebRequest(const Extension* extension) const { ExtensionRuntimeDataMap::const_iterator it = extension_runtime_data_.find(extension->id()); diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h index b21c86a..8d0c6c3 100644 --- a/chrome/browser/extensions/extension_service.h +++ b/chrome/browser/extensions/extension_service.h @@ -249,6 +249,11 @@ class ExtensionService bool IsBeingUpgraded(const extensions::Extension* extension) const; void SetBeingUpgraded(const extensions::Extension* extension, bool value); + // Getter and setter for the flag that specifies whether the extension is + // being reloaded. + bool IsBeingReloaded(const std::string& extension_name) const; + void SetBeingReloaded(const std::string& extension_id, bool value); + // Getter and setter for the flag that specifies if the extension has used // the webrequest API. // TODO(mpcomplete): remove. http://crbug.com/100411 @@ -311,7 +316,7 @@ class ExtensionService // Reloads the specified extension, sending the onLaunched() event to it if it // currently has any window showing. - void ReloadExtension(const std::string& extension_id); + void ReloadExtension(const std::string extension_id); // Uninstalls the specified extension. Callers should only call this method // with extensions that exist. |external_uninstall| is a magical parameter @@ -917,6 +922,10 @@ class ExtensionService extensions::ProcessMap process_map_; + // A set of the extension ids currently being reloaded. We use this to + // avoid showing a "new install" notice for an extension reinstall. + std::set<std::string> extensions_being_reloaded_; + scoped_ptr<ExtensionErrorUI> extension_error_ui_; // Sequenced task runner for extension related file operations. scoped_refptr<base::SequencedTaskRunner> file_task_runner_; diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index d08550c..0521450 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1380,6 +1380,7 @@ 'browser/extensions/api/webstore_private/webstore_private_apitest.cc', 'browser/extensions/app_background_page_apitest.cc', 'browser/extensions/app_process_apitest.cc', + 'browser/extensions/background_app_browsertest.cc', 'browser/extensions/background_page_apitest.cc', 'browser/extensions/background_scripts_apitest.cc', 'browser/extensions/chrome_app_api_browsertest.cc', diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc index 3fe39f2..ea1469b 100644 --- a/chrome/test/base/testing_browser_process.cc +++ b/chrome/test/base/testing_browser_process.cc @@ -7,6 +7,7 @@ #include "base/prefs/pref_service.h" #include "base/strings/string_util.h" #include "build/build_config.h" +#include "chrome/browser/background/background_mode_manager.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/bookmarks/bookmark_prompt_controller.h" @@ -149,6 +150,11 @@ BackgroundModeManager* TestingBrowserProcess::background_mode_manager() { return NULL; } +void TestingBrowserProcess::set_background_mode_manager_for_test( + scoped_ptr<BackgroundModeManager> manager) { + NOTREACHED(); +} + StatusTray* TestingBrowserProcess::status_tray() { return NULL; } diff --git a/chrome/test/base/testing_browser_process.h b/chrome/test/base/testing_browser_process.h index 300f192..983d766 100644 --- a/chrome/test/base/testing_browser_process.h +++ b/chrome/test/base/testing_browser_process.h @@ -62,6 +62,8 @@ class TestingBrowserProcess : public BrowserProcess { virtual GpuModeManager* gpu_mode_manager() OVERRIDE; virtual RenderWidgetSnapshotTaker* GetRenderWidgetSnapshotTaker() OVERRIDE; virtual BackgroundModeManager* background_mode_manager() OVERRIDE; + virtual void set_background_mode_manager_for_test( + scoped_ptr<BackgroundModeManager> manager) OVERRIDE; virtual StatusTray* status_tray() OVERRIDE; virtual SafeBrowsingService* safe_browsing_service() OVERRIDE; virtual safe_browsing::ClientSideDetectionService* diff --git a/chrome/test/data/extensions/background_app/BackgroundApp.html b/chrome/test/data/extensions/background_app/BackgroundApp.html new file mode 100644 index 0000000..dad2443 --- /dev/null +++ b/chrome/test/data/extensions/background_app/BackgroundApp.html @@ -0,0 +1,11 @@ +<!doctype html> +<html> + <head> + <title>Background App Popup</title> + <!-- JavaScript and HTML must be in separate files for security. --> + <script src="BackgroundApp.js"></script> + </head> + <body> + Simple Background App + </body> +</html> diff --git a/chrome/test/data/extensions/background_app/BackgroundApp.js b/chrome/test/data/extensions/background_app/BackgroundApp.js new file mode 100644 index 0000000..d5ee7e2 --- /dev/null +++ b/chrome/test/data/extensions/background_app/BackgroundApp.js @@ -0,0 +1,6 @@ +// Copyright 2013 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. + +// This is a simple v2 app with background permission and a background script. + diff --git a/chrome/test/data/extensions/background_app/background.js b/chrome/test/data/extensions/background_app/background.js new file mode 100644 index 0000000..77efd49 --- /dev/null +++ b/chrome/test/data/extensions/background_app/background.js @@ -0,0 +1,39 @@ +// Copyright 2013 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. + +// This is a minimal sample of a Apps V2 app with background permission. +// +// This function gets called in the packaged app model on launch. +chrome.app.runtime.onLaunched.addListener(function() { + console.log("Background App Launched!"); + + // We'll set up push messaging so we have something to keep the background + // app registered. + setupPush(); +}); + +// This function gets called in the packaged app model on install. +chrome.runtime.onInstalled.addListener(function() { + console.log("Background App installed!"); +}); + +// This function gets called in the packaged app model on shutdown. +chrome.runtime.onSuspend.addListener(function() { + console.log("Background App shutting down"); +}); + +// Register for push messages. +// This should be called every time the Push Messaging App starts up. +function setupPush() { + chrome.pushMessaging.onMessage.addListener(messageCallback); + + // Ensure that adding the listener took effect. + var listeners = chrome.pushMessaging.onMessage.hasListeners(); + console.log('registered listener for push messages ' + listeners); +} + +// This callback recieves the pushed message from the push server. +function messageCallback(message) { + console.log("push messaging callback seen"); +} diff --git a/chrome/test/data/extensions/background_app/manifest.json b/chrome/test/data/extensions/background_app/manifest.json new file mode 100644 index 0000000..eb2ecc3 --- /dev/null +++ b/chrome/test/data/extensions/background_app/manifest.json @@ -0,0 +1,11 @@ +{ + "background": { + "scripts": [ "background.js" ] + }, + "description": "A simple app with background permission set.", + "manifest_version": 2, + "name": "Background App", + "permissions": [ "background" ], + "update_url": "http://clients2.google.com/service/update2/crx", + "version": "1.2" +} |