diff options
author | Torne (Richard Coles) <torne@google.com> | 2013-06-11 10:57:03 +0100 |
---|---|---|
committer | Torne (Richard Coles) <torne@google.com> | 2013-06-11 10:57:03 +0100 |
commit | 868fa2fe829687343ffae624259930155e16dbd8 (patch) | |
tree | 54d316199dd9739c57c3aacd131853bbd6554a94 /apps | |
parent | bb1bdbd796f966b5bf11f40ecbea12621c7bfac9 (diff) | |
download | chromium_org-868fa2fe829687343ffae624259930155e16dbd8.tar.gz |
Merge from Chromium at DEPS revision r205460
This commit was generated by merge_to_master.py.
Change-Id: I4a744a5e426bd3bb378d887cfa56fe054742a540
Diffstat (limited to 'apps')
28 files changed, 690 insertions, 152 deletions
@@ -11,12 +11,15 @@ include_rules = [ "+chrome/browser/profiles", "+chrome/browser/shell_integration.h", "+chrome/browser/ui/extensions/application_launch.h", + "+chrome/browser/ui/extensions/native_app_window.h", "+chrome/browser/ui/extensions/shell_window.h", "+chrome/browser/ui/host_desktop.h", "+chrome/browser/ui/web_applications/web_app_ui.h", "+chrome/browser/web_applications/web_app.h", + "+chrome/browser/web_applications/web_app_mac.h", "+chrome/common/chrome_notification_types.h", "+chrome/common/chrome_paths.h", + "+chrome/common/chrome_switches.h", "+chrome/common/extensions", "+chrome/common/mac/app_mode_common.h", "+chrome/installer", diff --git a/apps/app_host/update.cc b/apps/app_host/update.cc index ee97dfb7e9..990e5b4923 100644 --- a/apps/app_host/update.cc +++ b/apps/app_host/update.cc @@ -10,8 +10,8 @@ #include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "base/process_util.h" -#include "base/string16.h" -#include "base/string_util.h" +#include "base/strings/string16.h" +#include "base/strings/string_util.h" #include "base/version.h" #include "base/win/registry.h" #include "chrome/installer/launcher_support/chrome_launcher_support.h" diff --git a/apps/app_launcher.cc b/apps/app_launcher.cc index 77a75fc858..0493c65aa4 100644 --- a/apps/app_launcher.cc +++ b/apps/app_launcher.cc @@ -5,13 +5,10 @@ #include "apps/app_launcher.h" #include "apps/pref_names.h" -#include "base/command_line.h" #include "base/prefs/pref_registry_simple.h" #include "base/prefs/pref_service.h" -#include "base/threading/sequenced_worker_pool.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/ui/host_desktop.h" -#include "content/public/browser/browser_thread.h" #if defined(OS_WIN) #include "chrome/installer/launcher_support/chrome_launcher_support.h" @@ -20,54 +17,22 @@ namespace apps { -namespace { - -enum AppLauncherState { - APP_LAUNCHER_UNKNOWN, - APP_LAUNCHER_ENABLED, - APP_LAUNCHER_DISABLED, -}; - -AppLauncherState SynchronousAppLauncherChecks() { +bool IsAppLauncherEnabled() { #if defined(USE_ASH) && !defined(OS_WIN) - return APP_LAUNCHER_ENABLED; + return true; #elif !defined(OS_WIN) - return APP_LAUNCHER_DISABLED; + return false; #else #if defined(USE_ASH) if (chrome::GetActiveDesktop() == chrome::HOST_DESKTOP_TYPE_ASH) - return APP_LAUNCHER_ENABLED; + return true; #endif PrefService* prefs = g_browser_process->local_state(); // In some tests, the prefs aren't initialised. if (!prefs) - return APP_LAUNCHER_UNKNOWN; - return prefs->GetBoolean(prefs::kAppLauncherHasBeenEnabled) ? - APP_LAUNCHER_ENABLED : APP_LAUNCHER_DISABLED; + return false; + return prefs->GetBoolean(prefs::kAppLauncherHasBeenEnabled); #endif } -} // namespace - -bool MaybeIsAppLauncherEnabled() { - return SynchronousAppLauncherChecks() == APP_LAUNCHER_ENABLED; -} - -void GetIsAppLauncherEnabled( - const OnAppLauncherEnabledCompleted& completion_callback) { - DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - - AppLauncherState state = SynchronousAppLauncherChecks(); - - if (state != APP_LAUNCHER_UNKNOWN) { - completion_callback.Run(state == APP_LAUNCHER_ENABLED); - return; - } - NOTREACHED(); -} - -bool WasAppLauncherEnabled() { - return SynchronousAppLauncherChecks() == APP_LAUNCHER_ENABLED; -} - } // namespace apps diff --git a/apps/app_launcher.h b/apps/app_launcher.h index 0ccc1bfd5d..07f6b6ea46 100644 --- a/apps/app_launcher.h +++ b/apps/app_launcher.h @@ -9,31 +9,8 @@ namespace apps { -// Called on the UI thread after determining if the launcher is enabled. A -// boolean flag is passed, which is true if the app launcher is enabled. -typedef base::Callback<void(bool)> OnAppLauncherEnabledCompleted; - -// TODO(calamity): Remove all the "uncertain" apis because windows app launcher -// enabled is now just a single pref that we can check synchronously and with -// confidence. This includes changing GetIsAppLauncherEnabled to a synchronous -// API. - -// A synchronous check to determine if the app launcher is enabled. If the -// registry needs to be determined to find an accurate answer, this function -// will NOT do so; instead if will default to false (the app launcher is not -// enabled). -// This function does not use the cached preference of whether the launcher -// was enabled or not. -bool MaybeIsAppLauncherEnabled(); - -// Determine whether the app launcher is enabled or not. This may involve a trip -// to a blocking thread. |completion_callback| is called when an answer is -// ready. This needs to be called on the UI thread. -void GetIsAppLauncherEnabled( - const OnAppLauncherEnabledCompleted& completion_callback); - -// Returns whether the app launcher was enabled the last time it was checked. -bool WasAppLauncherEnabled(); +// Returns whether the app launcher has been enabled. +bool IsAppLauncherEnabled(); } // namespace apps diff --git a/apps/app_load_service.cc b/apps/app_load_service.cc new file mode 100644 index 0000000000..1d78554120 --- /dev/null +++ b/apps/app_load_service.cc @@ -0,0 +1,110 @@ +// 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 "apps/app_load_service.h" + +#include "apps/app_load_service_factory.h" +#include "chrome/browser/extensions/extension_prefs.h" +#include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_system.h" +#include "chrome/browser/extensions/platform_app_launcher.h" +#include "chrome/browser/extensions/shell_window_registry.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/extension_constants.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_types.h" + +using extensions::Extension; +using extensions::ExtensionPrefs; + +namespace { + +enum PostReloadAction { + RELOAD_ACTION_LAUNCH, + RELOAD_ACTION_RESTART, +}; + +} // namespace + +namespace apps { + +AppLoadService::AppLoadService(Profile* profile) + : profile_(profile) { + registrar_.Add( + this, chrome::NOTIFICATION_EXTENSION_LOADED, + content::NotificationService::AllSources()); + registrar_.Add( + this, chrome::NOTIFICATION_EXTENSION_UNLOADED, + content::NotificationService::AllSources()); +} + +AppLoadService::~AppLoadService() {} + +void AppLoadService::RestartApplication(const std::string& extension_id) { + reload_actions_[extension_id] = RELOAD_ACTION_RESTART; + ExtensionService* service = extensions::ExtensionSystem::Get(profile_)-> + extension_service(); + DCHECK(service); + service->ReloadExtension(extension_id); +} + +void AppLoadService::ScheduleLaunchOnLoad(const std::string& extension_id) { + reload_actions_[extension_id] = RELOAD_ACTION_LAUNCH; +} + +// static +AppLoadService* AppLoadService::Get(Profile* profile) { + return apps::AppLoadServiceFactory::GetForProfile(profile); +} + +void AppLoadService::Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + switch (type) { + case chrome::NOTIFICATION_EXTENSION_LOADED: { + const Extension* extension = content::Details<Extension>(details).ptr(); + std::map<std::string, int>::iterator it = reload_actions_.find( + extension->id()); + if (it == reload_actions_.end()) + break; + + switch (it->second) { + case RELOAD_ACTION_LAUNCH: + extensions::LaunchPlatformApp(profile_, extension); + break; + case RELOAD_ACTION_RESTART: + extensions::RestartPlatformApp(profile_, extension); + break; + default: + NOTREACHED(); + } + + reload_actions_.erase(it); + break; + } + case chrome::NOTIFICATION_EXTENSION_UNLOADED: { + const extensions::UnloadedExtensionInfo* unload_info = + content::Details<extensions::UnloadedExtensionInfo>(details).ptr(); + if (!unload_info->extension->is_platform_app()) + break; + + if (unload_info->reason == extension_misc::UNLOAD_REASON_DISABLE) { + ExtensionPrefs* prefs = ExtensionPrefs::Get(profile_); + if ((prefs->GetDisableReasons(unload_info->extension->id()) & + Extension::DISABLE_RELOAD) && + !extensions::ShellWindowRegistry::Get(profile_)-> + GetShellWindowsForApp(unload_info->extension->id()).empty()) { + reload_actions_[unload_info->extension->id()] = RELOAD_ACTION_LAUNCH; + } + } + break; + } + default: + NOTREACHED(); + } +} + +} // namespace apps diff --git a/apps/app_load_service.h b/apps/app_load_service.h new file mode 100644 index 0000000000..c7e75c6e1a --- /dev/null +++ b/apps/app_load_service.h @@ -0,0 +1,54 @@ +// 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. + +#ifndef APPS_APP_LOAD_SERVICE_H_ +#define APPS_APP_LOAD_SERVICE_H_ + +#include <map> +#include <string> + +#include "components/browser_context_keyed_service/browser_context_keyed_service.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" + +class Profile; + +namespace apps { + +// Monitors apps being reloaded and performs app specific actions (like launch +// or restart) on them. Also provides an interface to schedule these actions. +class AppLoadService : public BrowserContextKeyedService, + public content::NotificationObserver { + public: + explicit AppLoadService(Profile* profile); + virtual ~AppLoadService(); + + // Reload the application with the given id and then send it the OnRestarted + // event. + void RestartApplication(const std::string& extension_id); + + // Schedule a launch to happen for the extension with id |extension_id| + // when it loads next. This does not cause the extension to be reloaded. + void ScheduleLaunchOnLoad(const std::string& extension_id); + + static AppLoadService* Get(Profile* profile); + + private: + // content::NotificationObserver. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + // Map of extension id to reload action. Absence from the map implies + // no action. + std::map<std::string, int> reload_actions_; + content::NotificationRegistrar registrar_; + Profile* profile_; + + DISALLOW_COPY_AND_ASSIGN(AppLoadService); +}; + +} // namespace apps + +#endif // APPS_APP_LOAD_SERVICE_H_ diff --git a/apps/app_load_service_factory.cc b/apps/app_load_service_factory.cc new file mode 100644 index 0000000000..37c2d459a5 --- /dev/null +++ b/apps/app_load_service_factory.cc @@ -0,0 +1,57 @@ +// 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 "apps/app_load_service_factory.h" + +#include "apps/app_load_service.h" +#include "chrome/browser/extensions/extension_prefs_factory.h" +#include "chrome/browser/extensions/extension_system_factory.h" +#include "chrome/browser/extensions/shell_window_registry.h" +#include "chrome/browser/profiles/incognito_helpers.h" +#include "chrome/browser/profiles/profile.h" +#include "components/browser_context_keyed_service/browser_context_dependency_manager.h" + +namespace apps { + +// static +AppLoadService* AppLoadServiceFactory::GetForProfile(Profile* profile) { + return static_cast<AppLoadService*>( + GetInstance()->GetServiceForBrowserContext(profile, true)); +} + +AppLoadServiceFactory* AppLoadServiceFactory::GetInstance() { + return Singleton<AppLoadServiceFactory>::get(); +} + +AppLoadServiceFactory::AppLoadServiceFactory() + : BrowserContextKeyedServiceFactory( + "AppLoadService", + BrowserContextDependencyManager::GetInstance()) { + DependsOn(extensions::ExtensionPrefsFactory::GetInstance()); + DependsOn(extensions::ExtensionSystemFactory::GetInstance()); + DependsOn(extensions::ShellWindowRegistry::Factory::GetInstance()); +} + +AppLoadServiceFactory::~AppLoadServiceFactory() { +} + +BrowserContextKeyedService* AppLoadServiceFactory::BuildServiceInstanceFor( + content::BrowserContext* profile) const { + return new AppLoadService(static_cast<Profile*>(profile)); +} + +bool AppLoadServiceFactory::ServiceIsNULLWhileTesting() const { + return false; +} + +bool AppLoadServiceFactory::ServiceIsCreatedWithBrowserContext() const { + return true; +} + +content::BrowserContext* AppLoadServiceFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + return chrome::GetBrowserContextRedirectedInIncognito(context); +} + +} // namespace apps diff --git a/apps/app_load_service_factory.h b/apps/app_load_service_factory.h new file mode 100644 index 0000000000..453c4a3cae --- /dev/null +++ b/apps/app_load_service_factory.h @@ -0,0 +1,40 @@ +// 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. + +#ifndef APPS_APP_LOAD_SERVICE_FACTORY_H_ +#define APPS_APP_LOAD_SERVICE_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "components/browser_context_keyed_service/browser_context_keyed_service_factory.h" + +class Profile; + +namespace apps { + +class AppLoadService; + +class AppLoadServiceFactory : public BrowserContextKeyedServiceFactory { + public: + static AppLoadService* GetForProfile(Profile* profile); + + static AppLoadServiceFactory* GetInstance(); + + private: + friend struct DefaultSingletonTraits<AppLoadServiceFactory>; + + AppLoadServiceFactory(); + virtual ~AppLoadServiceFactory(); + + // BrowserContextKeyedServiceFactory: + virtual BrowserContextKeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const OVERRIDE; + virtual bool ServiceIsCreatedWithBrowserContext() const OVERRIDE; + virtual bool ServiceIsNULLWhileTesting() const OVERRIDE; + virtual content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const OVERRIDE; +}; + +} // namespace apps + +#endif // APPS_APP_LOAD_SERVICE_FACTORY_H_ diff --git a/apps/app_restore_service.cc b/apps/app_restore_service.cc index 88ac811840..37a463be45 100644 --- a/apps/app_restore_service.cc +++ b/apps/app_restore_service.cc @@ -4,6 +4,7 @@ #include "apps/app_restore_service.h" +#include "apps/app_restore_service_factory.h" #include "apps/saved_files_service.h" #include "chrome/browser/extensions/api/app_runtime/app_runtime_api.h" #include "chrome/browser/extensions/event_router.h" @@ -84,6 +85,16 @@ void AppRestoreService::HandleStartup(bool should_restore_apps) { } } +bool AppRestoreService::IsAppRestorable(const std::string& extension_id) { + return extensions::ExtensionPrefs::Get(profile_) ->IsExtensionRunning( + extension_id); +} + +// static +AppRestoreService* AppRestoreService::Get(Profile* profile) { + return apps::AppRestoreServiceFactory::GetForProfile(profile); +} + void AppRestoreService::Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) { diff --git a/apps/app_restore_service.h b/apps/app_restore_service.h index 65d3de2e58..bf538293a8 100644 --- a/apps/app_restore_service.h +++ b/apps/app_restore_service.h @@ -36,6 +36,12 @@ class AppRestoreService : public BrowserContextKeyedService, // from apps to prevent them being restarted in subsequent restarts. void HandleStartup(bool should_restore_apps); + // Returns whether this extension is running or, at startup, whether it was + // running when Chrome was last terminated. + bool IsAppRestorable(const std::string& extension_id); + + static AppRestoreService* Get(Profile* profile); + private: // content::NotificationObserver. virtual void Observe(int type, diff --git a/apps/app_shim/app_shim_handler_mac.h b/apps/app_shim/app_shim_handler_mac.h index 507fe5f841..c24b340d9b 100644 --- a/apps/app_shim/app_shim_handler_mac.h +++ b/apps/app_shim/app_shim_handler_mac.h @@ -7,6 +7,8 @@ #include <string> +#include "apps/app_shim/app_shim_launch.h" + class Profile; namespace apps { @@ -46,8 +48,9 @@ class AppShimHandler { // Invoked by the shim host when the shim process is launched. The handler // must return true if successful, or false to indicate back to the shim - // process that it should close. - virtual bool OnShimLaunch(Host* host) = 0; + // process that it should close. |launch_now| indicates whether to launch the + // associated app. + virtual bool OnShimLaunch(Host* host, AppShimLaunchType launch_type) = 0; // Invoked by the shim host when the connection to the shim process is closed. virtual void OnShimClose(Host* host) = 0; @@ -55,6 +58,9 @@ class AppShimHandler { // Invoked by the shim host when the shim process receives a focus event. virtual void OnShimFocus(Host* host) = 0; + // Invoked by the shim host when the shim process receives a quit event. + virtual void OnShimQuit(Host* host) = 0; + protected: AppShimHandler() {} virtual ~AppShimHandler() {} diff --git a/apps/app_shim/app_shim_host_mac.cc b/apps/app_shim/app_shim_host_mac.cc index ad63e93038..7ae2dd69b0 100644 --- a/apps/app_shim/app_shim_host_mac.cc +++ b/apps/app_shim/app_shim_host_mac.cc @@ -47,6 +47,7 @@ bool AppShimHost::OnMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(AppShimHost, message) IPC_MESSAGE_HANDLER(AppShimHostMsg_LaunchApp, OnLaunchApp) IPC_MESSAGE_HANDLER(AppShimHostMsg_FocusApp, OnFocus) + IPC_MESSAGE_HANDLER(AppShimHostMsg_QuitApp, OnQuit) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -62,7 +63,9 @@ bool AppShimHost::Send(IPC::Message* message) { return channel_->Send(message); } -void AppShimHost::OnLaunchApp(std::string profile_dir, std::string app_id) { +void AppShimHost::OnLaunchApp(base::FilePath profile_dir, + std::string app_id, + apps::AppShimLaunchType launch_type) { DCHECK(CalledOnValidThread()); DCHECK(!profile_); if (profile_) { @@ -71,10 +74,15 @@ void AppShimHost::OnLaunchApp(std::string profile_dir, std::string app_id) { return; } - profile_ = FetchProfileForDirectory(profile_dir); + if (!(profile_ = FetchProfileForDirectory(profile_dir))) { + Send(new AppShimMsg_LaunchApp_Done(false)); + return; + } + app_id_ = app_id; + apps::AppShimHandler* handler = apps::AppShimHandler::GetForAppMode(app_id_); - bool success = handler && handler->OnShimLaunch(this); + bool success = handler && handler->OnShimLaunch(this, launch_type); Send(new AppShimMsg_LaunchApp_Done(success)); } @@ -85,24 +93,29 @@ void AppShimHost::OnFocus() { handler->OnShimFocus(this); } -Profile* AppShimHost::FetchProfileForDirectory(const std::string& profile_dir) { +void AppShimHost::OnQuit() { + DCHECK(CalledOnValidThread()); + apps::AppShimHandler* handler = apps::AppShimHandler::GetForAppMode(app_id_); + if (handler) + handler->OnShimQuit(this); +} + +Profile* AppShimHost::FetchProfileForDirectory( + const base::FilePath& profile_dir) { ProfileManager* profileManager = g_browser_process->profile_manager(); - // Even though the name of this function is "unsafe", there's no security - // issue here -- the check for the profile name in the profile info cache - // ensures that we never access any directory that isn't a known profile. - base::FilePath path = base::FilePath::FromUTF8Unsafe(profile_dir); - path = profileManager->user_data_dir().Append(path); + // Check for the profile name in the profile info cache to ensure that we + // never access any directory that isn't a known profile. + base::FilePath path = profileManager->user_data_dir().Append(profile_dir); ProfileInfoCache& cache = profileManager->GetProfileInfoCache(); - // This ensures that the given profile path is acutally a profile that we - // already know about. if (cache.GetIndexOfProfileWithPath(path) == std::string::npos) { LOG(ERROR) << "Requested directory is not a known profile '" - << profile_dir << "'."; + << profile_dir.value() << "'."; return NULL; } Profile* profile = profileManager->GetProfile(path); if (!profile) { - LOG(ERROR) << "Couldn't get profile for directory '" << profile_dir << "'."; + LOG(ERROR) << "Couldn't get profile for directory '" + << profile_dir.value() << "'."; return NULL; } return profile; diff --git a/apps/app_shim/app_shim_host_mac.h b/apps/app_shim/app_shim_host_mac.h index e68380c314..ce5ce5b4d1 100644 --- a/apps/app_shim/app_shim_host_mac.h +++ b/apps/app_shim/app_shim_host_mac.h @@ -8,6 +8,7 @@ #include <string> #include "apps/app_shim/app_shim_handler_mac.h" +#include "base/files/file_path.h" #include "base/memory/scoped_ptr.h" #include "base/threading/non_thread_safe.h" #include "ipc/ipc_listener.h" @@ -41,7 +42,7 @@ class AppShimHost : public IPC::Listener, protected: // Used internally; virtual so they can be mocked for testing. - virtual Profile* FetchProfileForDirectory(const std::string& profile_dir); + virtual Profile* FetchProfileForDirectory(const base::FilePath& profile_dir); // IPC::Listener implementation. virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; @@ -51,17 +52,22 @@ class AppShimHost : public IPC::Listener, virtual bool Send(IPC::Message* message) OVERRIDE; private: - // The app shim process is requesting that an app be launched. Once it has - // done so the |profile| and |app_id| are stored, and all future messages - // from the app shim relate to the app it launched. It is an error for the - // app shim to send multiple launch messages. - void OnLaunchApp(std::string profile, std::string app_id); + // The app shim process is requesting to be associated with the given profile + // and app_id. Once the profile and app_id are stored, and all future + // messages from the app shim relate to this app. The app is launched + // immediately if |launch_now| is true. + void OnLaunchApp(base::FilePath profile_dir, + std::string app_id, + apps::AppShimLaunchType launch_type); // Called when the app shim process notifies that the app should be brought // to the front (i.e. the user has clicked on the app's icon in the dock or // Cmd+Tabbed to it.) void OnFocus(); + // Called when the app shim process notifies that the app should quit. + void OnQuit(); + // apps::AppShimHandler::Host overrides: virtual void OnAppClosed() OVERRIDE; virtual Profile* GetProfile() const OVERRIDE; diff --git a/apps/app_shim/app_shim_host_mac_unittest.cc b/apps/app_shim/app_shim_host_mac_unittest.cc index f9a8e4dcc7..6b1d0498bc 100644 --- a/apps/app_shim/app_shim_host_mac_unittest.cc +++ b/apps/app_shim/app_shim_host_mac_unittest.cc @@ -28,19 +28,14 @@ class TestingAppShimHost : public AppShimHost { fails_profile_ = fails_profile; } - void set_fails_launch(bool fails_launch) { - fails_launch_ = fails_launch; - } - protected: - virtual Profile* FetchProfileForDirectory(const std::string& profile_dir) + virtual Profile* FetchProfileForDirectory(const base::FilePath& profile_dir) OVERRIDE; virtual bool Send(IPC::Message* message) OVERRIDE; private: Profile* test_profile_; bool fails_profile_; - bool fails_launch_; ScopedVector<IPC::Message> sent_messages_; @@ -49,8 +44,7 @@ class TestingAppShimHost : public AppShimHost { TestingAppShimHost::TestingAppShimHost(Profile* profile) : test_profile_(profile), - fails_profile_(false), - fails_launch_(false) { + fails_profile_(false) { } bool TestingAppShimHost::ReceiveMessage(IPC::Message* message) { @@ -65,18 +59,33 @@ bool TestingAppShimHost::Send(IPC::Message* message) { } Profile* TestingAppShimHost::FetchProfileForDirectory( - const std::string& profile_dir) { + const base::FilePath& profile_dir) { return fails_profile_ ? NULL : test_profile_; } +const char kTestAppId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; +const char kTestProfileDir[] = "Default"; + class AppShimHostTest : public testing::Test, public apps::AppShimHandler { public: - AppShimHostTest() : launch_count_(0), close_count_(0), focus_count_(0) {} + AppShimHostTest() : fail_launch_(false), + launch_count_(0), + launch_now_count_(0), + close_count_(0), + focus_count_(0), + quit_count_(0) {} TestingAppShimHost* host() { return host_.get(); } TestingProfile* profile() { return profile_.get(); } + void LaunchApp(bool launch_now) { + EXPECT_TRUE(host()->ReceiveMessage(new AppShimHostMsg_LaunchApp( + base::FilePath(kTestProfileDir), kTestAppId, + launch_now ? apps::APP_SHIM_LAUNCH_NORMAL : + apps::APP_SHIM_LAUNCH_REGISTER_ONLY))); + } + bool LaunchWasSuccessful() { EXPECT_EQ(1u, host()->sent_messages().size()); IPC::Message* message = host()->sent_messages()[0]; @@ -91,17 +100,24 @@ class AppShimHostTest : public testing::Test, } protected: - virtual bool OnShimLaunch(Host* host) OVERRIDE { + virtual bool OnShimLaunch(Host* host, + apps::AppShimLaunchType launch_type) OVERRIDE { ++launch_count_; - return true; + if (launch_type == apps::APP_SHIM_LAUNCH_NORMAL) + ++launch_now_count_; + return !fail_launch_; } virtual void OnShimClose(Host* host) OVERRIDE { ++close_count_; } virtual void OnShimFocus(Host* host) OVERRIDE { ++focus_count_; } + virtual void OnShimQuit(Host* host) OVERRIDE { ++quit_count_; } + bool fail_launch_; int launch_count_; + int launch_now_count_; int close_count_; int focus_count_; + int quit_count_; private: virtual void SetUp() OVERRIDE { @@ -116,40 +132,54 @@ class AppShimHostTest : public testing::Test, DISALLOW_COPY_AND_ASSIGN(AppShimHostTest); }; -const char kTestAppId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; -const char kTestProfileDir[] = "Default"; } // namespace TEST_F(AppShimHostTest, TestLaunchAppWithHandler) { apps::AppShimHandler::RegisterHandler(kTestAppId, this); - EXPECT_TRUE(host()->ReceiveMessage( - new AppShimHostMsg_LaunchApp(kTestProfileDir, kTestAppId))); + LaunchApp(true); EXPECT_EQ(kTestAppId, implicit_cast<apps::AppShimHandler::Host*>(host())->GetAppId()); EXPECT_TRUE(LaunchWasSuccessful()); EXPECT_EQ(1, launch_count_); + EXPECT_EQ(1, launch_now_count_); EXPECT_EQ(0, focus_count_); EXPECT_EQ(0, close_count_); EXPECT_TRUE(host()->ReceiveMessage(new AppShimHostMsg_FocusApp())); EXPECT_EQ(1, focus_count_); + EXPECT_TRUE(host()->ReceiveMessage(new AppShimHostMsg_QuitApp())); + EXPECT_EQ(1, quit_count_); + SimulateDisconnect(); EXPECT_EQ(1, close_count_); apps::AppShimHandler::RemoveHandler(kTestAppId); } +TEST_F(AppShimHostTest, TestNoLaunchNow) { + apps::AppShimHandler::RegisterHandler(kTestAppId, this); + LaunchApp(false); + EXPECT_EQ(kTestAppId, + implicit_cast<apps::AppShimHandler::Host*>(host())->GetAppId()); + EXPECT_TRUE(LaunchWasSuccessful()); + EXPECT_EQ(1, launch_count_); + EXPECT_EQ(0, launch_now_count_); + EXPECT_EQ(0, focus_count_); + EXPECT_EQ(0, close_count_); + apps::AppShimHandler::RemoveHandler(kTestAppId); +} + TEST_F(AppShimHostTest, TestFailProfile) { host()->set_fails_profile(true); - host()->ReceiveMessage( - new AppShimHostMsg_LaunchApp(kTestProfileDir, kTestAppId)); + LaunchApp(true); ASSERT_FALSE(LaunchWasSuccessful()); } TEST_F(AppShimHostTest, TestFailLaunch) { - host()->set_fails_launch(true); - host()->ReceiveMessage( - new AppShimHostMsg_LaunchApp(kTestProfileDir, kTestAppId)); + apps::AppShimHandler::RegisterHandler(kTestAppId, this); + fail_launch_ = true; + LaunchApp(true); ASSERT_FALSE(LaunchWasSuccessful()); + apps::AppShimHandler::RemoveHandler(kTestAppId); } diff --git a/apps/app_shim/app_shim_launch.h b/apps/app_shim/app_shim_launch.h new file mode 100644 index 0000000000..2c71333b2e --- /dev/null +++ b/apps/app_shim/app_shim_launch.h @@ -0,0 +1,20 @@ +// 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. + +#ifndef APPS_APP_SHIM_APP_SHIM_LAUNCH_H_ +#define APPS_APP_SHIM_APP_SHIM_LAUNCH_H_ + +namespace apps { + +enum AppShimLaunchType { + // Process the app shim's LaunchAppmessage and associate the shim with the + // given profile and app id. + APP_SHIM_LAUNCH_REGISTER_ONLY = 0, + // Do the above and launch the app. + APP_SHIM_LAUNCH_NORMAL, +}; + +} // namespace apps + +#endif // APPS_APP_SHIM_APP_SHIM_LAUNCH_H_ diff --git a/apps/app_shim/app_shim_messages.h b/apps/app_shim/app_shim_messages.h index 6a6cc6d07a..1b38c39a96 100644 --- a/apps/app_shim/app_shim_messages.h +++ b/apps/app_shim/app_shim_messages.h @@ -6,22 +6,35 @@ #include <string> +#include "apps/app_shim/app_shim_launch.h" +#include "base/files/file_path.h" #include "ipc/ipc_message_macros.h" +#include "ipc/param_traits_macros.h" #define IPC_MESSAGE_START AppShimMsgStart +IPC_ENUM_TRAITS(apps::AppShimLaunchType) + // Signals that a previous LaunchApp message has been processed, and lets the -// app shim process know whether the app launch was successful. +// app shim process know whether it was registered successfully. IPC_MESSAGE_CONTROL1(AppShimMsg_LaunchApp_Done, bool /* succeeded */) -// Tells the main Chrome process to launch a particular app with the given -// profile name and app id. -IPC_MESSAGE_CONTROL2(AppShimHostMsg_LaunchApp, - std::string /* profile name */, - std::string /* app id */) +// Signals to the main Chrome process that a shim has started indicating the +// profile and app_id that the shim should be associated with and whether to +// launch the app immediately. +IPC_MESSAGE_CONTROL3(AppShimHostMsg_LaunchApp, + base::FilePath /* profile dir */, + std::string /* app id */, + apps::AppShimLaunchType /* launch type */) // Sent when the user has indicated a desire to focus the app, either by // clicking on the app's icon in the dock or by selecting it with Cmd+Tab. In // response, Chrome brings the app's windows to the foreground. IPC_MESSAGE_CONTROL0(AppShimHostMsg_FocusApp) + +// Sent when the shim process receives a request to terminate. Once all of the +// app's windows have closed, and the extension is unloaded, the AppShimHost +// closes the channel. The shim process then completes the terminate request +// and exits. +IPC_MESSAGE_CONTROL0(AppShimHostMsg_QuitApp) diff --git a/apps/app_shim/extension_app_shim_handler_mac.cc b/apps/app_shim/extension_app_shim_handler_mac.cc index 9d31d694c0..9e97735e69 100644 --- a/apps/app_shim/extension_app_shim_handler_mac.cc +++ b/apps/app_shim/extension_app_shim_handler_mac.cc @@ -12,12 +12,18 @@ #include "chrome/browser/extensions/extension_system.h" #include "chrome/browser/extensions/shell_window_registry.h" #include "chrome/browser/ui/extensions/application_launch.h" +#include "chrome/browser/ui/extensions/native_app_window.h" #include "chrome/browser/ui/extensions/shell_window.h" +#include "chrome/browser/ui/web_applications/web_app_ui.h" +#include "chrome/browser/web_applications/web_app_mac.h" #include "ui/base/cocoa/focus_window_set.h" namespace apps { -ExtensionAppShimHandler::ExtensionAppShimHandler() {} +ExtensionAppShimHandler::ExtensionAppShimHandler() { + registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_CREATED, + content::NotificationService::AllBrowserContextsAndSources()); +} ExtensionAppShimHandler::~ExtensionAppShimHandler() { for (HostMap::iterator it = hosts_.begin(); it != hosts_.end(); ) { @@ -27,7 +33,8 @@ ExtensionAppShimHandler::~ExtensionAppShimHandler() { } } -bool ExtensionAppShimHandler::OnShimLaunch(Host* host) { +bool ExtensionAppShimHandler::OnShimLaunch(Host* host, + AppShimLaunchType launch_type) { Profile* profile = host->GetProfile(); DCHECK(profile); @@ -37,13 +44,15 @@ bool ExtensionAppShimHandler::OnShimLaunch(Host* host) { return false; } - if (!LaunchApp(profile, app_id)) + if (!LaunchApp(profile, app_id, launch_type)) return false; // The first host to claim this (profile, app_id) becomes the main host. - // For any others, we launch the app but return false. - if (!hosts_.insert(make_pair(make_pair(profile, app_id), host)).second) + // For any others, we focus the app and return false. + if (!hosts_.insert(make_pair(make_pair(profile, app_id), host)).second) { + OnShimFocus(host); return false; + } if (!registrar_.IsRegistered( this, chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED, @@ -73,15 +82,29 @@ void ExtensionAppShimHandler::OnShimFocus(Host* host) { const extensions::ShellWindowRegistry::ShellWindowList windows = registry->GetShellWindowsForApp(host->GetAppId()); std::set<gfx::NativeWindow> native_windows; - for (extensions::ShellWindowRegistry::const_iterator i = windows.begin(); - i != windows.end(); ++i) { - native_windows.insert((*i)->GetNativeWindow()); + for (extensions::ShellWindowRegistry::const_iterator it = windows.begin(); + it != windows.end(); ++it) { + native_windows.insert((*it)->GetNativeWindow()); } ui::FocusWindowSet(native_windows); } +void ExtensionAppShimHandler::OnShimQuit(Host* host) { + if (!host->GetProfile()) + return; + + extensions::ShellWindowRegistry::ShellWindowList windows = + extensions::ShellWindowRegistry::Get(host->GetProfile())-> + GetShellWindowsForApp(host->GetAppId()); + for (extensions::ShellWindowRegistry::const_iterator it = windows.begin(); + it != windows.end(); ++it) { + (*it)->GetBaseWindow()->Close(); + } +} + bool ExtensionAppShimHandler::LaunchApp(Profile* profile, - const std::string& app_id) { + const std::string& app_id, + AppShimLaunchType launch_type) { extensions::ExtensionSystem* extension_system = extensions::ExtensionSystem::Get(profile); ExtensionServiceInterface* extension_service = @@ -93,6 +116,10 @@ bool ExtensionAppShimHandler::LaunchApp(Profile* profile, << app_id << "'."; return false; } + + if (launch_type == APP_SHIM_LAUNCH_REGISTER_ONLY) + return true; + // TODO(jeremya): Handle the case that launching the app fails. Probably we // need to watch for 'app successfully launched' or at least 'background page // exists/was created' and time out with failure if we don't see that sign of @@ -107,19 +134,34 @@ void ExtensionAppShimHandler::Observe( const content::NotificationSource& source, const content::NotificationDetails& details) { Profile* profile = content::Source<Profile>(source).ptr(); + extensions::ExtensionHost* extension_host = + content::Details<extensions::ExtensionHost>(details).ptr(); switch (type) { - case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: { - extensions::ExtensionHost* extension_host = - content::Details<extensions::ExtensionHost>(details).ptr(); + case chrome::NOTIFICATION_EXTENSION_HOST_CREATED: + StartShim(profile, extension_host->extension()); + break; + case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: CloseShim(profile, extension_host->extension_id()); break; - } default: NOTREACHED(); // Unexpected notification. break; } } +void ExtensionAppShimHandler::StartShim( + Profile* profile, + const extensions::Extension* extension) { + if (!extension->is_platform_app()) + return; + + if (hosts_.count(make_pair(profile, extension->id()))) + return; + + web_app::MaybeLaunchShortcut( + web_app::ShortcutInfoForExtensionAndProfile(extension, profile)); +} + void ExtensionAppShimHandler::CloseShim(Profile* profile, const std::string& app_id) { HostMap::const_iterator it = hosts_.find(make_pair(profile, app_id)); diff --git a/apps/app_shim/extension_app_shim_handler_mac.h b/apps/app_shim/extension_app_shim_handler_mac.h index ea9a8c7eee..f5a7d668eb 100644 --- a/apps/app_shim/extension_app_shim_handler_mac.h +++ b/apps/app_shim/extension_app_shim_handler_mac.h @@ -14,6 +14,10 @@ class Profile; +namespace extensions { +class Extension; +} + namespace apps { // This app shim handler that handles events for app shims that correspond to an @@ -25,9 +29,10 @@ class ExtensionAppShimHandler : public AppShimHandler, virtual ~ExtensionAppShimHandler(); // AppShimHandler overrides: - virtual bool OnShimLaunch(Host* host) OVERRIDE; + virtual bool OnShimLaunch(Host* host, AppShimLaunchType launch_type) OVERRIDE; virtual void OnShimClose(Host* host) OVERRIDE; virtual void OnShimFocus(Host* host) OVERRIDE; + virtual void OnShimQuit(Host* host) OVERRIDE; protected: typedef std::map<std::pair<Profile*, std::string>, AppShimHandler::Host*> @@ -38,7 +43,9 @@ class ExtensionAppShimHandler : public AppShimHandler, content::NotificationRegistrar& registrar() { return registrar_; } private: - virtual bool LaunchApp(Profile* profile, const std::string& app_id); + virtual bool LaunchApp(Profile* profile, + const std::string& app_id, + AppShimLaunchType launch_type); // Listen to the NOTIFICATION_EXTENSION_HOST_DESTROYED message to detect when // an app closes. When that happens, call OnAppClosed on the relevant @@ -48,6 +55,8 @@ class ExtensionAppShimHandler : public AppShimHandler, const content::NotificationSource& source, const content::NotificationDetails& details) OVERRIDE; + void StartShim(Profile* profile, const extensions::Extension* extension); + void CloseShim(Profile* profile, const std::string& app_id); HostMap hosts_; diff --git a/apps/app_shim/extension_app_shim_handler_mac_unittest.cc b/apps/app_shim/extension_app_shim_handler_mac_unittest.cc index dbbbd13c80..651d597a13 100644 --- a/apps/app_shim/extension_app_shim_handler_mac_unittest.cc +++ b/apps/app_shim/extension_app_shim_handler_mac_unittest.cc @@ -31,7 +31,9 @@ class TestingExtensionAppShimHandler : public ExtensionAppShimHandler { content::NotificationRegistrar& GetRegistrar() { return registrar(); } protected: - virtual bool LaunchApp(Profile* profile, const std::string& app_id) OVERRIDE { + virtual bool LaunchApp(Profile* profile, + const std::string& app_id, + AppShimLaunchType launch_type) OVERRIDE { return !fails_launch_; } @@ -96,20 +98,20 @@ class ExtensionAppShimHandlerTest : public testing::Test { TEST_F(ExtensionAppShimHandlerTest, LaunchAndCloseShim) { // If launch fails, the host is not added to the map. handler_->set_fails_launch(true); - EXPECT_EQ(false, handler_->OnShimLaunch(&host_aa_)); + EXPECT_EQ(false, handler_->OnShimLaunch(&host_aa_, APP_SHIM_LAUNCH_NORMAL)); EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA)); // Normal startup. handler_->set_fails_launch(false); - EXPECT_EQ(true, handler_->OnShimLaunch(&host_aa_)); + EXPECT_EQ(true, handler_->OnShimLaunch(&host_aa_, APP_SHIM_LAUNCH_NORMAL)); EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA)); EXPECT_TRUE(handler_->GetRegistrar().IsRegistered( handler_.get(), chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED, content::Source<Profile>(&profile_a_))); - EXPECT_EQ(true, handler_->OnShimLaunch(&host_ab_)); + EXPECT_EQ(true, handler_->OnShimLaunch(&host_ab_, APP_SHIM_LAUNCH_NORMAL)); EXPECT_EQ(&host_ab_, handler_->FindHost(&profile_a_, kTestAppIdB)); - EXPECT_EQ(true, handler_->OnShimLaunch(&host_bb_)); + EXPECT_EQ(true, handler_->OnShimLaunch(&host_bb_, APP_SHIM_LAUNCH_NORMAL)); EXPECT_EQ(&host_bb_, handler_->FindHost(&profile_b_, kTestAppIdB)); EXPECT_TRUE(handler_->GetRegistrar().IsRegistered( handler_.get(), @@ -117,7 +119,8 @@ TEST_F(ExtensionAppShimHandlerTest, LaunchAndCloseShim) { content::Source<Profile>(&profile_b_))); // Starting and closing a second host does nothing. - EXPECT_EQ(false, handler_->OnShimLaunch(&host_aa_duplicate_)); + EXPECT_EQ(false, handler_->OnShimLaunch(&host_aa_duplicate_, + APP_SHIM_LAUNCH_NORMAL)); EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA)); handler_->OnShimClose(&host_aa_duplicate_); EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA)); diff --git a/apps/apps.gypi b/apps/apps.gypi index 92a677e29f..1ad9600bc0 100644 --- a/apps/apps.gypi +++ b/apps/apps.gypi @@ -26,6 +26,10 @@ 'app_launch_for_metro_restart_win.h', 'app_launcher.cc', 'app_launcher.h', + 'app_load_service.cc', + 'app_load_service.h', + 'app_load_service_factory.cc', + 'app_load_service_factory.h', 'app_restore_service.cc', 'app_restore_service.h', 'app_restore_service_factory.cc', @@ -36,8 +40,8 @@ 'app_shim/app_shim_host_mac.h', 'app_shim/app_shim_host_manager_mac.h', 'app_shim/app_shim_host_manager_mac.mm', - 'app_shim/extension_app_shim_handler_mac.h', 'app_shim/extension_app_shim_handler_mac.cc', + 'app_shim/extension_app_shim_handler_mac.h', 'field_trial_names.cc', 'field_trial_names.h', 'pref_names.cc', @@ -54,6 +58,8 @@ 'shortcut_manager.h', 'shortcut_manager_factory.cc', 'shortcut_manager_factory.h', + 'switches.cc', + 'switches.h', ], 'conditions': [ ['enable_extensions==0', diff --git a/apps/load_and_launch_browsertest.cc b/apps/load_and_launch_browsertest.cc new file mode 100644 index 0000000000..63d22661c0 --- /dev/null +++ b/apps/load_and_launch_browsertest.cc @@ -0,0 +1,110 @@ +// 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. + +// Tests for the --load-and-launch-app switch. +// The two cases are when chrome is running and another process uses the switch +// and when chrome is started from scratch. + +#include "apps/switches.h" +#include "base/test/test_timeouts.h" +#include "chrome/browser/extensions/extension_browsertest.h" +#include "chrome/browser/extensions/extension_test_message_listener.h" +#include "chrome/browser/extensions/platform_app_browsertest_util.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/common/chrome_switches.h" +#include "content/public/test/test_launcher.h" + +using extensions::PlatformAppBrowserTest; + +namespace apps { + +// TODO(jackhou): Enable this test once it works on OSX. It currently does not +// work for the same reason --app-id doesn't. See http://crbug.com/148465 +#if defined(OS_MACOSX) +#define MAYBE_LoadAndLaunchAppChromeRunning \ + DISABLED_LoadAndLaunchAppChromeRunning +#else +#define MAYBE_LoadAndLaunchAppChromeRunning LoadAndLaunchAppChromeRunning +#endif + +// Case where Chrome is already running. +IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, + MAYBE_LoadAndLaunchAppChromeRunning) { + ExtensionTestMessageListener launched_listener("Launched", false); + + const CommandLine& cmdline = *CommandLine::ForCurrentProcess(); + CommandLine new_cmdline(cmdline.GetProgram()); + + const char* kSwitchNames[] = { + switches::kUserDataDir, + }; + new_cmdline.CopySwitchesFrom(cmdline, kSwitchNames, arraysize(kSwitchNames)); + + base::FilePath app_path = test_data_dir_ + .AppendASCII("platform_apps") + .AppendASCII("minimal"); + + new_cmdline.AppendSwitchNative(apps::kLoadAndLaunchApp, + app_path.value()); + + new_cmdline.AppendSwitch(content::kLaunchAsBrowser); + base::ProcessHandle process; + base::LaunchProcess(new_cmdline, base::LaunchOptions(), &process); + ASSERT_NE(base::kNullProcessHandle, process); + + ASSERT_TRUE(launched_listener.WaitUntilSatisfied()); + ASSERT_TRUE(base::WaitForSingleProcess( + process, TestTimeouts::action_timeout())); +} + +namespace { + +// TestFixture that appends --load-and-launch-app before calling BrowserMain. +class PlatformAppLoadAndLaunchBrowserTest : public PlatformAppBrowserTest { + protected: + PlatformAppLoadAndLaunchBrowserTest() {} + + virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { + PlatformAppBrowserTest::SetUpCommandLine(command_line); + app_path_ = test_data_dir_ + .AppendASCII("platform_apps") + .AppendASCII("minimal"); + command_line->AppendSwitchNative(apps::kLoadAndLaunchApp, + app_path_.value()); + } + + void LoadAndLaunchApp() { + ExtensionTestMessageListener launched_listener("Launched", false); + ASSERT_TRUE(launched_listener.WaitUntilSatisfied()); + + // Start an actual browser because we can't shut down with just an app + // window. + CreateBrowser(ProfileManager::GetDefaultProfile()); + } + + private: + base::FilePath app_path_; + + DISALLOW_COPY_AND_ASSIGN(PlatformAppLoadAndLaunchBrowserTest); +}; + +} // namespace + + +// TODO(jackhou): Make this test not flaky on Vista. See http://crbug.com/176897 +#if defined(OS_WIN) +#define MAYBE_LoadAndLaunchAppChromeNotRunning \ + DISABLED_LoadAndLaunchAppChromeNotRunning +#else +#define MAYBE_LoadAndLaunchAppChromeNotRunning \ + LoadAndLaunchAppChromeNotRunning +#endif + +// Case where Chrome is not running. +IN_PROC_BROWSER_TEST_F(PlatformAppLoadAndLaunchBrowserTest, + MAYBE_LoadAndLaunchAppChromeNotRunning) { + LoadAndLaunchApp(); +} + +} // namespace apps diff --git a/apps/saved_files_service.cc b/apps/saved_files_service.cc index c509c083ea..aeefa39e44 100644 --- a/apps/saved_files_service.cc +++ b/apps/saved_files_service.cc @@ -240,7 +240,10 @@ void SavedFilesService::EnqueueFileEntry(const std::string& extension_id, std::vector<SavedFileEntry> SavedFilesService::GetAllFileEntries( const std::string& extension_id) { - return GetOrInsert(extension_id)->GetAllFileEntries(); + SavedFiles* saved_files = Get(extension_id); + if (saved_files) + return saved_files->GetAllFileEntries(); + return GetSavedFileEntries(ExtensionPrefs::Get(profile_), extension_id); } bool SavedFilesService::IsRegistered(const std::string& extension_id, @@ -258,19 +261,32 @@ void SavedFilesService::ClearQueueIfNoRetainPermission( const Extension* extension) { if (!extension->GetActivePermissions()->HasAPIPermission( APIPermission::kFileSystemRetainFiles)) { - ClearSavedFileEntries(ExtensionPrefs::Get(profile_), extension->id()); - Clear(extension->id()); + ClearQueue(extension); } } -SavedFilesService::SavedFiles* SavedFilesService::GetOrInsert( - const std::string& extension_id) { - std::map<std::string, SavedFiles*>::iterator it = +void SavedFilesService::ClearQueue(const extensions::Extension* extension) { + ClearSavedFileEntries(ExtensionPrefs::Get(profile_), extension->id()); + Clear(extension->id()); +} + +SavedFilesService::SavedFiles* SavedFilesService::Get( + const std::string& extension_id) const { + std::map<std::string, SavedFiles*>::const_iterator it = extension_id_to_saved_files_.find(extension_id); if (it != extension_id_to_saved_files_.end()) return it->second; - SavedFiles* saved_files = new SavedFiles(profile_, extension_id); + return NULL; +} + +SavedFilesService::SavedFiles* SavedFilesService::GetOrInsert( + const std::string& extension_id) { + SavedFiles* saved_files = Get(extension_id); + if (saved_files) + return saved_files; + + saved_files = new SavedFiles(profile_, extension_id); extension_id_to_saved_files_.insert( std::make_pair(extension_id, saved_files)); return saved_files; diff --git a/apps/saved_files_service.h b/apps/saved_files_service.h index 613764aaa8..dfaae24cb4 100644 --- a/apps/saved_files_service.h +++ b/apps/saved_files_service.h @@ -95,6 +95,9 @@ class SavedFilesService : public BrowserContextKeyedService, // fileSystem.retainFiles permission. void ClearQueueIfNoRetainPermission(const extensions::Extension* extension); + // Clears all retained files. + void ClearQueue(const extensions::Extension* extension); + private: FRIEND_TEST_ALL_PREFIXES(::SavedFilesServiceUnitTest, RetainTwoFilesTest); FRIEND_TEST_ALL_PREFIXES(::SavedFilesServiceUnitTest, EvictionTest); @@ -110,6 +113,9 @@ class SavedFilesService : public BrowserContextKeyedService, const content::NotificationSource& source, const content::NotificationDetails& details) OVERRIDE; + // Returns the SavedFiles for |extension_id| or NULL if one does not exist. + SavedFiles* Get(const std::string& extension_id) const; + // Returns the SavedFiles for |extension_id|, creating it if necessary. SavedFiles* GetOrInsert(const std::string& extension_id); diff --git a/apps/saved_files_service_unittest.cc b/apps/saved_files_service_unittest.cc index 4d31485426..01fc1dd71e 100644 --- a/apps/saved_files_service_unittest.cc +++ b/apps/saved_files_service_unittest.cc @@ -6,7 +6,7 @@ #include "apps/saved_files_service.h" #include "base/files/file_path.h" -#include "base/string_number_conversions.h" +#include "base/strings/string_number_conversions.h" #include "base/test/values_test_util.h" #include "base/values.h" #include "chrome/browser/extensions/extension_prefs.h" diff --git a/apps/shell_window_geometry_cache_unittest.cc b/apps/shell_window_geometry_cache_unittest.cc index 255c78c535..456c165884 100644 --- a/apps/shell_window_geometry_cache_unittest.cc +++ b/apps/shell_window_geometry_cache_unittest.cc @@ -51,7 +51,7 @@ class ShellWindowGeometryCacheTest : public testing::Test { protected: TestingProfile profile_; - MessageLoopForUI ui_message_loop_; + base::MessageLoopForUI ui_message_loop_; content::TestBrowserThread ui_thread_; scoped_ptr<extensions::TestExtensionPrefs> prefs_; scoped_ptr<ShellWindowGeometryCache> cache_; diff --git a/apps/shortcut_manager.cc b/apps/shortcut_manager.cc index 2bdccb5fc2..13aba1826d 100644 --- a/apps/shortcut_manager.cc +++ b/apps/shortcut_manager.cc @@ -5,13 +5,15 @@ #include "apps/shortcut_manager.h" #include "base/bind.h" +#include "base/command_line.h" #include "base/compiler_specific.h" -#include "base/string16.h" -#include "base/utf_string_conversions.h" +#include "base/strings/string16.h" +#include "base/strings/utf_string_conversions.h" #include "chrome/browser/shell_integration.h" #include "chrome/browser/ui/web_applications/web_app_ui.h" #include "chrome/browser/web_applications/web_app.h" #include "chrome/common/chrome_notification_types.h" +#include "chrome/common/chrome_switches.h" #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_source.h" @@ -50,13 +52,19 @@ void ShortcutManager::Observe(int type, const content::NotificationDetails& details) { switch (type) { case chrome::NOTIFICATION_EXTENSION_INSTALLED: { -#if !defined(OS_MACOSX) +#if defined(OS_MACOSX) + if (!CommandLine::ForCurrentProcess()-> + HasSwitch(switches::kEnableAppShims)) + break; +#endif // defined(OS_MACOSX) + const extensions::InstalledExtensionInfo* installed_info = content::Details<const extensions::InstalledExtensionInfo>(details) .ptr(); const Extension* extension = installed_info->extension; if (extension->is_platform_app() && - extension->location() != extensions::Manifest::COMPONENT) { + extension->location() != extensions::Manifest::COMPONENT && + extension->ShouldDisplayInAppLauncher()) { // If the app is being updated, update any existing shortcuts but do not // create new ones. If it is being installed, automatically create a // shortcut in the applications menu (e.g., Start Menu). @@ -73,7 +81,6 @@ void ShortcutManager::Observe(int type, web_app::UpdateShortcutInfoAndIconForApp(*extension, profile_, create_or_update); } -#endif // !defined(OS_MACOSX) break; } case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: { diff --git a/apps/switches.cc b/apps/switches.cc new file mode 100644 index 0000000000..60f94175f6 --- /dev/null +++ b/apps/switches.cc @@ -0,0 +1,12 @@ +// 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 "apps/switches.h" + +namespace apps { + +// Loads an app from the specified directory and launches it. +const char kLoadAndLaunchApp[] = "load-and-launch-app"; + +} // namespace apps diff --git a/apps/switches.h b/apps/switches.h new file mode 100644 index 0000000000..b43f920561 --- /dev/null +++ b/apps/switches.h @@ -0,0 +1,16 @@ +// 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. + +#ifndef APPS_SWITCHES_H_ +#define APPS_SWITCHES_H_ + +namespace apps { + +// All switches in alphabetical order. The switches should be documented +// alongside the definition of their values in the .cc file. +extern const char kLoadAndLaunchApp[]; + +} // namespace apps + +#endif // APPS_SWITCHES_H_ |