diff options
author | tapted@chromium.org <tapted@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-14 12:50:27 +0000 |
---|---|---|
committer | tapted@chromium.org <tapted@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-14 12:50:27 +0000 |
commit | 1f75b3fb8d6edb5e440233280a8235d394040715 (patch) | |
tree | 1d8c53ded781030671b5f646d7e69771646e7402 /apps | |
parent | e4004a6417bf29eb19a70e424373b87ebb39a9ee (diff) | |
download | chromium_src-1f75b3fb8d6edb5e440233280a8235d394040715.zip chromium_src-1f75b3fb8d6edb5e440233280a8235d394040715.tar.gz chromium_src-1f75b3fb8d6edb5e440233280a8235d394040715.tar.bz2 |
Update the OSX app shim to support the app launcher.
Adds AppShimHandler: a registrar, and interface for services that can
handle interactions with OSX shim processes, and makes AppListServiceMac
implement that interface.
BUG=138633
TEST=Added:
- browser_tests: AppListServiceMacBrowserTest.ShowAppListUsingShim
- unit_tests: AppShimHostTest.TestLaunchAppWithHandler
Review URL: https://chromiumcodereview.appspot.com/14696009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@199968 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'apps')
-rw-r--r-- | apps/app_shim/app_shim_handler_mac.cc | 70 | ||||
-rw-r--r-- | apps/app_shim/app_shim_handler_mac.h | 54 | ||||
-rw-r--r-- | apps/app_shim/app_shim_host_mac.cc | 41 | ||||
-rw-r--r-- | apps/app_shim/app_shim_host_mac.h | 12 | ||||
-rw-r--r-- | apps/app_shim/app_shim_host_mac_unittest.cc | 71 | ||||
-rw-r--r-- | apps/apps.gypi | 2 |
6 files changed, 225 insertions, 25 deletions
diff --git a/apps/app_shim/app_shim_handler_mac.cc b/apps/app_shim/app_shim_handler_mac.cc new file mode 100644 index 0000000..18cca92 --- /dev/null +++ b/apps/app_shim/app_shim_handler_mac.cc @@ -0,0 +1,70 @@ +// 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_shim/app_shim_handler_mac.h" + +#include <map> + +#include "base/logging.h" +#include "base/memory/singleton.h" + +namespace apps { + +namespace { + +class AppShimHandlerRegistry { + public: + static AppShimHandlerRegistry* GetInstance() { + return Singleton<AppShimHandlerRegistry, + LeakySingletonTraits<AppShimHandlerRegistry> >::get(); + } + + AppShimHandler* GetForAppMode(const std::string& app_mode_id) const { + HandlerMap::const_iterator it = handlers_.find(app_mode_id); + if (it != handlers_.end()) + return it->second; + + return NULL; + } + + bool SetForAppMode(const std::string& app_mode_id, AppShimHandler* handler) { + bool inserted_or_removed = handler ? + handlers_.insert(HandlerMap::value_type(app_mode_id, handler)).second : + handlers_.erase(app_mode_id) == 1; + DCHECK(inserted_or_removed); + return inserted_or_removed; + } + + private: + friend struct DefaultSingletonTraits<AppShimHandlerRegistry>; + typedef std::map<std::string, AppShimHandler*> HandlerMap; + + AppShimHandlerRegistry() {} + ~AppShimHandlerRegistry() {} + + HandlerMap handlers_; + + DISALLOW_COPY_AND_ASSIGN(AppShimHandlerRegistry); +}; + +} // namespace + +// static +void AppShimHandler::RegisterHandler(const std::string& app_mode_id, + AppShimHandler* handler) { + DCHECK(handler); + AppShimHandlerRegistry::GetInstance()->SetForAppMode(app_mode_id, handler); +} + +// static +void AppShimHandler::RemoveHandler(const std::string& app_mode_id) { + AppShimHandlerRegistry::GetInstance()->SetForAppMode(app_mode_id, NULL); +} + +// static +AppShimHandler* AppShimHandler::GetForAppMode(const std::string& app_mode_id) { + return AppShimHandlerRegistry::GetInstance()->GetForAppMode(app_mode_id); +} + +} // namespace apps diff --git a/apps/app_shim/app_shim_handler_mac.h b/apps/app_shim/app_shim_handler_mac.h new file mode 100644 index 0000000..6a694c0 --- /dev/null +++ b/apps/app_shim/app_shim_handler_mac.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_SHIM_APP_SHIM_HANDLER_MAC_H_ +#define APPS_APP_SHIM_APP_SHIM_HANDLER_MAC_H_ + +#include <string> + +namespace apps { + +// Registrar, and interface for services that can handle interactions with OSX +// shim processes. +class AppShimHandler { + public: + class Host { + public: + // Invoked when the app is closed in the browser process. + virtual void OnAppClosed() = 0; + + protected: + virtual ~Host() {} + }; + + // Register a handler for an |app_mode_id|. + static void RegisterHandler(const std::string& app_mode_id, + AppShimHandler* handler); + + // Remove a handler for an |app_mode_id|. + static void RemoveHandler(const std::string& app_mode_id); + + // Returns the handler registered for the given |app_mode_id|, or NULL if none + // is registered. + static AppShimHandler* GetForAppMode(const std::string& app_mode_id); + + // 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; + + // Invoked by the shim host when the connection to the shim process is closed. + virtual void OnShimClose(Host* host) = 0; + + // Invoked by the shim host when the shim process receives a focus event. + virtual void OnShimFocus(Host* host) = 0; + + protected: + AppShimHandler() {} + virtual ~AppShimHandler() {} +}; + +} // namespace apps + +#endif // APPS_APP_SHIM_APP_SHIM_HANDLER_MAC_H_ diff --git a/apps/app_shim/app_shim_host_mac.cc b/apps/app_shim/app_shim_host_mac.cc index b2d577f..bfe28f9 100644 --- a/apps/app_shim/app_shim_host_mac.cc +++ b/apps/app_shim/app_shim_host_mac.cc @@ -4,6 +4,7 @@ #include "apps/app_shim/app_shim_host_mac.h" +#include "apps/app_shim/app_shim_handler_mac.h" #include "apps/app_shim/app_shim_messages.h" #include "base/bind.h" #include "base/files/file_path.h" @@ -26,6 +27,9 @@ AppShimHost::AppShimHost() AppShimHost::~AppShimHost() { DCHECK(CalledOnValidThread()); + apps::AppShimHandler* handler = apps::AppShimHandler::GetForAppMode(app_id_); + if (handler) + handler->OnShimClose(this); } void AppShimHost::ServeChannel(const IPC::ChannelHandle& handle) { @@ -47,6 +51,10 @@ bool AppShimHost::OnMessageReceived(const IPC::Message& message) { return handled; } +void AppShimHost::OnChannelError() { + Close(); +} + bool AppShimHost::Send(IPC::Message* message) { DCHECK(channel_.get()); return channel_->Send(message); @@ -54,12 +62,21 @@ bool AppShimHost::Send(IPC::Message* message) { void AppShimHost::OnLaunchApp(std::string profile_dir, std::string app_id) { DCHECK(CalledOnValidThread()); - bool success = LaunchAppImpl(profile_dir, app_id); + app_id_ = app_id; + apps::AppShimHandler* handler = apps::AppShimHandler::GetForAppMode(app_id_); + bool success = + handler ? handler->OnShimLaunch(this) : LaunchAppImpl(profile_dir); Send(new AppShimMsg_LaunchApp_Done(success)); } void AppShimHost::OnFocus() { DCHECK(CalledOnValidThread()); + apps::AppShimHandler* handler = apps::AppShimHandler::GetForAppMode(app_id_); + if (handler) { + handler->OnShimFocus(this); + return; + } + if (!profile_) return; extensions::ShellWindowRegistry* registry = @@ -75,14 +92,13 @@ void AppShimHost::OnFocus() { ui::FocusWindowSet(native_windows); } -bool AppShimHost::LaunchAppImpl(const std::string& profile_dir, - const std::string& app_id) { +bool AppShimHost::LaunchAppImpl(const std::string& profile_dir) { DCHECK(CalledOnValidThread()); if (profile_) { // Only one app launch message per channel. return false; } - if (!extensions::Extension::IdIsValid(app_id)) { + if (!extensions::Extension::IdIsValid(app_id_)) { LOG(ERROR) << "Bad app ID from app shim launch message."; return false; } @@ -90,12 +106,10 @@ bool AppShimHost::LaunchAppImpl(const std::string& profile_dir, if (!profile) return false; - if (!LaunchApp(profile, app_id)) + if (!LaunchApp(profile)) return false; profile_ = profile; - app_id_ = app_id; - registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED, content::Source<Profile>(profile_)); return true; @@ -112,7 +126,8 @@ Profile* AppShimHost::FetchProfileForDirectory(const std::string& profile_dir) { // 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."; + LOG(ERROR) << "Requested directory is not a known profile '" + << profile_dir << "'."; return NULL; } Profile* profile = profileManager->GetProfile(path); @@ -123,17 +138,17 @@ Profile* AppShimHost::FetchProfileForDirectory(const std::string& profile_dir) { return profile; } -bool AppShimHost::LaunchApp(Profile* profile, const std::string& app_id) { +bool AppShimHost::LaunchApp(Profile* profile) { extensions::ExtensionSystem* extension_system = extensions::ExtensionSystem::Get(profile); ExtensionServiceInterface* extension_service = extension_system->extension_service(); const extensions::Extension* extension = extension_service->GetExtensionById( - app_id, false); + app_id_, false); if (!extension) { LOG(ERROR) << "Attempted to launch nonexistent app with id '" - << app_id << "'."; + << app_id_ << "'."; return false; } // TODO(jeremya): Handle the case that launching the app fails. Probably we @@ -167,6 +182,10 @@ void AppShimHost::Observe(int type, } } +void AppShimHost::OnAppClosed() { + Close(); +} + void AppShimHost::Close() { DCHECK(CalledOnValidThread()); delete this; diff --git a/apps/app_shim/app_shim_host_mac.h b/apps/app_shim/app_shim_host_mac.h index fbfd0fa..438832c 100644 --- a/apps/app_shim/app_shim_host_mac.h +++ b/apps/app_shim/app_shim_host_mac.h @@ -7,6 +7,7 @@ #include <string> +#include "apps/app_shim/app_shim_handler_mac.h" #include "base/memory/scoped_ptr.h" #include "base/threading/non_thread_safe.h" #include "content/public/browser/notification_observer.h" @@ -28,6 +29,7 @@ class Message; // connected to the app shim is closed. class AppShimHost : public IPC::Listener, public IPC::Sender, + public apps::AppShimHandler::Host, public content::NotificationObserver, public base::NonThreadSafe { public: @@ -39,16 +41,17 @@ class AppShimHost : public IPC::Listener, // listening for messages on it. void ServeChannel(const IPC::ChannelHandle& handle); + protected: const std::string& app_id() const { return app_id_; } const Profile* profile() const { return profile_; } - protected: // Used internally; virtual so they can be mocked for testing. virtual Profile* FetchProfileForDirectory(const std::string& profile_dir); - virtual bool LaunchApp(Profile* profile, const std::string& app_id); + virtual bool LaunchApp(Profile* profile); // IPC::Listener implementation. virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + virtual void OnChannelError() OVERRIDE; // IPC::Sender implementation. virtual bool Send(IPC::Message* message) OVERRIDE; @@ -65,7 +68,7 @@ class AppShimHost : public IPC::Listener, // Cmd+Tabbed to it.) void OnFocus(); - bool LaunchAppImpl(const std::string& profile_dir, const std::string& app_id); + bool LaunchAppImpl(const std::string& profile_dir); // The AppShimHost listens to the NOTIFICATION_EXTENSION_HOST_DESTROYED // message to detect when the app closes. When that happens, the AppShimHost @@ -74,6 +77,9 @@ class AppShimHost : public IPC::Listener, const content::NotificationSource& source, const content::NotificationDetails& details) OVERRIDE; + // apps::AppShimHandler::Host override: + virtual void OnAppClosed() OVERRIDE; + // Closes the channel and destroys the AppShimHost. void Close(); diff --git a/apps/app_shim/app_shim_host_mac_unittest.cc b/apps/app_shim/app_shim_host_mac_unittest.cc index 802c8e9..476b2ce 100644 --- a/apps/app_shim/app_shim_host_mac_unittest.cc +++ b/apps/app_shim/app_shim_host_mac_unittest.cc @@ -10,6 +10,8 @@ #include "ipc/ipc_message.h" #include "testing/gtest/include/gtest/gtest.h" +namespace { + class TestingAppShimHost : public AppShimHost { public: explicit TestingAppShimHost(Profile* profile); @@ -29,13 +31,21 @@ class TestingAppShimHost : public AppShimHost { fails_launch_ = fails_launch; } + const std::string& GetAppId() const { + return app_id(); + } + + const Profile* GetProfile() const { + return profile(); + } + protected: virtual Profile* FetchProfileForDirectory(const std::string& profile_dir) OVERRIDE; - virtual bool LaunchApp(Profile* profile, const std::string& app_id) OVERRIDE; - + virtual bool LaunchApp(Profile* profile) OVERRIDE; virtual bool Send(IPC::Message* message) OVERRIDE; + private: Profile* test_profile_; bool fails_profile_; bool fails_launch_; @@ -67,13 +77,15 @@ Profile* TestingAppShimHost::FetchProfileForDirectory( return fails_profile_ ? NULL : test_profile_; } -bool TestingAppShimHost::LaunchApp( - Profile* profile, const std::string& app_id) { +bool TestingAppShimHost::LaunchApp(Profile* profile) { return !fails_launch_; } -class AppShimHostTest : public testing::Test { +class AppShimHostTest : public testing::Test, + public apps::AppShimHandler { public: + AppShimHostTest() : launch_count_(0), close_count_(0), focus_count_(0) {} + TestingAppShimHost* host() { return host_.get(); } TestingProfile* profile() { return profile_.get(); } @@ -86,6 +98,23 @@ class AppShimHostTest : public testing::Test { return param.a; } + void SimulateDisconnect() { + implicit_cast<IPC::Listener*>(host_.release())->OnChannelError(); + } + + protected: + virtual bool OnShimLaunch(Host* host) OVERRIDE { + ++launch_count_; + return true; + } + + virtual void OnShimClose(Host* host) OVERRIDE { ++close_count_; } + virtual void OnShimFocus(Host* host) OVERRIDE { ++focus_count_; } + + int launch_count_; + int close_count_; + int focus_count_; + private: virtual void SetUp() OVERRIDE { profile_.reset(new TestingProfile); @@ -94,24 +123,45 @@ class AppShimHostTest : public testing::Test { scoped_ptr<TestingAppShimHost> host_; scoped_ptr<TestingProfile> profile_; + + DISALLOW_COPY_AND_ASSIGN(AppShimHostTest); }; -static const std::string kTestAppId = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; -static const std::string kTestProfileDir = "Default"; +const char kTestAppId[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; +const char kTestProfileDir[] = "Default"; + +} // namespace TEST_F(AppShimHostTest, TestLaunchApp) { host()->ReceiveMessage( new AppShimHostMsg_LaunchApp(kTestProfileDir, kTestAppId)); - ASSERT_EQ(kTestAppId, host()->app_id()); - ASSERT_EQ(profile(), host()->profile()); + ASSERT_EQ(kTestAppId, host()->GetAppId()); + ASSERT_EQ(profile(), host()->GetProfile()); ASSERT_TRUE(LaunchWasSuccessful()); } +TEST_F(AppShimHostTest, TestLaunchAppWithHandler) { + apps::AppShimHandler::RegisterHandler(kTestAppId, this); + EXPECT_TRUE(host()->ReceiveMessage( + new AppShimHostMsg_LaunchApp(kTestProfileDir, kTestAppId))); + EXPECT_EQ(kTestAppId, host()->GetAppId()); + EXPECT_TRUE(LaunchWasSuccessful()); + EXPECT_EQ(1, launch_count_); + EXPECT_EQ(0, focus_count_); + EXPECT_EQ(0, close_count_); + + EXPECT_TRUE(host()->ReceiveMessage(new AppShimHostMsg_FocusApp())); + EXPECT_EQ(1, focus_count_); + + SimulateDisconnect(); + EXPECT_EQ(1, close_count_); + apps::AppShimHandler::RemoveHandler(kTestAppId); +} + TEST_F(AppShimHostTest, TestFailProfile) { host()->set_fails_profile(true); host()->ReceiveMessage( new AppShimHostMsg_LaunchApp(kTestProfileDir, kTestAppId)); - ASSERT_TRUE(host()->app_id().empty()); ASSERT_FALSE(LaunchWasSuccessful()); } @@ -119,6 +169,5 @@ TEST_F(AppShimHostTest, TestFailLaunch) { host()->set_fails_launch(true); host()->ReceiveMessage( new AppShimHostMsg_LaunchApp(kTestProfileDir, kTestAppId)); - ASSERT_TRUE(host()->app_id().empty()); ASSERT_FALSE(LaunchWasSuccessful()); } diff --git a/apps/apps.gypi b/apps/apps.gypi index 5553a51..4867f73 100644 --- a/apps/apps.gypi +++ b/apps/apps.gypi @@ -30,6 +30,8 @@ 'app_restore_service.h', 'app_restore_service_factory.cc', 'app_restore_service_factory.h', + 'app_shim/app_shim_handler_mac.cc', + 'app_shim/app_shim_handler_mac.h', 'app_shim/app_shim_host_mac.cc', 'app_shim/app_shim_host_mac.h', 'app_shim/app_shim_host_manager_mac.h', |