summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2013-06-11 10:57:03 +0100
committerTorne (Richard Coles) <torne@google.com>2013-06-11 10:57:03 +0100
commit868fa2fe829687343ffae624259930155e16dbd8 (patch)
tree54d316199dd9739c57c3aacd131853bbd6554a94 /apps
parentbb1bdbd796f966b5bf11f40ecbea12621c7bfac9 (diff)
downloadchromium_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')
-rw-r--r--apps/DEPS3
-rw-r--r--apps/app_host/update.cc4
-rw-r--r--apps/app_launcher.cc47
-rw-r--r--apps/app_launcher.h27
-rw-r--r--apps/app_load_service.cc110
-rw-r--r--apps/app_load_service.h54
-rw-r--r--apps/app_load_service_factory.cc57
-rw-r--r--apps/app_load_service_factory.h40
-rw-r--r--apps/app_restore_service.cc11
-rw-r--r--apps/app_restore_service.h6
-rw-r--r--apps/app_shim/app_shim_handler_mac.h10
-rw-r--r--apps/app_shim/app_shim_host_mac.cc39
-rw-r--r--apps/app_shim/app_shim_host_mac.h18
-rw-r--r--apps/app_shim/app_shim_host_mac_unittest.cc72
-rw-r--r--apps/app_shim/app_shim_launch.h20
-rw-r--r--apps/app_shim/app_shim_messages.h25
-rw-r--r--apps/app_shim/extension_app_shim_handler_mac.cc68
-rw-r--r--apps/app_shim/extension_app_shim_handler_mac.h13
-rw-r--r--apps/app_shim/extension_app_shim_handler_mac_unittest.cc15
-rw-r--r--apps/apps.gypi8
-rw-r--r--apps/load_and_launch_browsertest.cc110
-rw-r--r--apps/saved_files_service.cc30
-rw-r--r--apps/saved_files_service.h6
-rw-r--r--apps/saved_files_service_unittest.cc2
-rw-r--r--apps/shell_window_geometry_cache_unittest.cc2
-rw-r--r--apps/shortcut_manager.cc17
-rw-r--r--apps/switches.cc12
-rw-r--r--apps/switches.h16
28 files changed, 690 insertions, 152 deletions
diff --git a/apps/DEPS b/apps/DEPS
index b7951f84d4..1352f48210 100644
--- a/apps/DEPS
+++ b/apps/DEPS
@@ -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_