diff options
Diffstat (limited to 'apps/app_shim')
-rw-r--r-- | apps/app_shim/app_shim_handler_mac.h | 15 | ||||
-rw-r--r-- | apps/app_shim/app_shim_host_mac.cc | 14 | ||||
-rw-r--r-- | apps/app_shim/app_shim_host_mac.h | 11 | ||||
-rw-r--r-- | apps/app_shim/app_shim_host_mac_unittest.cc | 28 | ||||
-rw-r--r-- | apps/app_shim/app_shim_launch.h | 2 | ||||
-rw-r--r-- | apps/app_shim/app_shim_messages.h | 12 | ||||
-rw-r--r-- | apps/app_shim/app_shim_quit_interactive_uitest_mac.mm | 5 | ||||
-rw-r--r-- | apps/app_shim/chrome_main_app_mode_mac.mm | 188 | ||||
-rw-r--r-- | apps/app_shim/extension_app_shim_handler_mac.cc | 64 | ||||
-rw-r--r-- | apps/app_shim/extension_app_shim_handler_mac.h | 13 | ||||
-rw-r--r-- | apps/app_shim/extension_app_shim_handler_mac_unittest.cc | 92 |
11 files changed, 306 insertions, 138 deletions
diff --git a/apps/app_shim/app_shim_handler_mac.h b/apps/app_shim/app_shim_handler_mac.h index e442e64..66dbea9 100644 --- a/apps/app_shim/app_shim_handler_mac.h +++ b/apps/app_shim/app_shim_handler_mac.h @@ -6,6 +6,7 @@ #define APPS_APP_SHIM_APP_SHIM_HANDLER_MAC_H_ #include <string> +#include <vector> #include "apps/app_shim/app_shim_launch.h" #include "base/files/file_path.h" @@ -55,14 +56,22 @@ class AppShimHandler { // Invoked by the shim host when the shim process is launched. The handler // must call OnAppLaunchComplete to inform the shim of the result. - // |launch_now| indicates whether to launch the associated app. - virtual void OnShimLaunch(Host* host, AppShimLaunchType launch_type) = 0; + // |launch_type| indicates the type of launch. + // |files|, if non-empty, holds an array of files paths given as arguments, or + // dragged onto the app bundle or dock icon. + virtual void OnShimLaunch(Host* host, + AppShimLaunchType launch_type, + const std::vector<base::FilePath>& files) = 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, AppShimFocusType focus_type) = 0; + // |files|, if non-empty, holds an array of files dragged onto the app bundle + // or dock icon. + virtual void OnShimFocus(Host* host, + AppShimFocusType focus_type, + const std::vector<base::FilePath>& files) = 0; // Invoked by the shim host when the shim process is hidden or shown. virtual void OnShimSetHidden(Host* host, bool hidden) = 0; diff --git a/apps/app_shim/app_shim_host_mac.cc b/apps/app_shim/app_shim_host_mac.cc index 6762873..437fb6b 100644 --- a/apps/app_shim/app_shim_host_mac.cc +++ b/apps/app_shim/app_shim_host_mac.cc @@ -63,9 +63,10 @@ bool AppShimHost::Send(IPC::Message* message) { return channel_->Send(message); } -void AppShimHost::OnLaunchApp(base::FilePath profile_dir, - std::string app_id, - apps::AppShimLaunchType launch_type) { +void AppShimHost::OnLaunchApp(const base::FilePath& profile_dir, + const std::string& app_id, + apps::AppShimLaunchType launch_type, + const std::vector<base::FilePath>& files) { DCHECK(CalledOnValidThread()); DCHECK(profile_path_.empty()); // Only one app launch message per channel. @@ -77,16 +78,17 @@ void AppShimHost::OnLaunchApp(base::FilePath profile_dir, apps::AppShimHandler* handler = apps::AppShimHandler::GetForAppMode(app_id_); if (handler) - handler->OnShimLaunch(this, launch_type); + handler->OnShimLaunch(this, launch_type, files); // |handler| can only be NULL after AppShimHostManager is destroyed. Since // this only happens at shutdown, do nothing here. } -void AppShimHost::OnFocus(apps::AppShimFocusType focus_type) { +void AppShimHost::OnFocus(apps::AppShimFocusType focus_type, + const std::vector<base::FilePath>& files) { DCHECK(CalledOnValidThread()); apps::AppShimHandler* handler = apps::AppShimHandler::GetForAppMode(app_id_); if (handler) - handler->OnShimFocus(this, focus_type); + handler->OnShimFocus(this, focus_type, files); } void AppShimHost::OnSetHidden(bool hidden) { diff --git a/apps/app_shim/app_shim_host_mac.h b/apps/app_shim/app_shim_host_mac.h index e7eabf7..b2b0882 100644 --- a/apps/app_shim/app_shim_host_mac.h +++ b/apps/app_shim/app_shim_host_mac.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_WEB_APPLICATIONS_APP_SHIM_HOST_MAC_H_ #include <string> +#include <vector> #include "apps/app_shim/app_shim_handler_mac.h" #include "base/files/file_path.h" @@ -50,12 +51,14 @@ class AppShimHost : public IPC::Listener, // 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); + void OnLaunchApp(const base::FilePath& profile_dir, + const std::string& app_id, + apps::AppShimLaunchType launch_type, + const std::vector<base::FilePath>& files); // Called when the app shim process notifies that the app was focused. - void OnFocus(apps::AppShimFocusType focus_type); + void OnFocus(apps::AppShimFocusType focus_type, + const std::vector<base::FilePath>& files); void OnSetHidden(bool hidden); diff --git a/apps/app_shim/app_shim_host_mac_unittest.cc b/apps/app_shim/app_shim_host_mac_unittest.cc index 0345b55..b4b56fb6 100644 --- a/apps/app_shim/app_shim_host_mac_unittest.cc +++ b/apps/app_shim/app_shim_host_mac_unittest.cc @@ -4,6 +4,8 @@ #include "apps/app_shim/app_shim_host_mac.h" +#include <vector> + #include "apps/app_shim/app_shim_messages.h" #include "base/basictypes.h" #include "base/memory/scoped_vector.h" @@ -58,11 +60,12 @@ class AppShimHostTest : public testing::Test, TestingAppShimHost* host() { return host_.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))); + void LaunchApp(apps::AppShimLaunchType launch_type) { + EXPECT_TRUE(host()->ReceiveMessage( + new AppShimHostMsg_LaunchApp(base::FilePath(kTestProfileDir), + kTestAppId, + launch_type, + std::vector<base::FilePath>()))); } apps::AppShimLaunchResult GetLaunchResult() { @@ -80,7 +83,8 @@ class AppShimHostTest : public testing::Test, protected: virtual void OnShimLaunch(Host* host, - apps::AppShimLaunchType launch_type) OVERRIDE { + apps::AppShimLaunchType launch_type, + const std::vector<base::FilePath>& file) OVERRIDE { ++launch_count_; if (launch_type == apps::APP_SHIM_LAUNCH_NORMAL) ++launch_now_count_; @@ -90,7 +94,8 @@ class AppShimHostTest : public testing::Test, virtual void OnShimClose(Host* host) OVERRIDE { ++close_count_; } virtual void OnShimFocus(Host* host, - apps::AppShimFocusType focus_type) OVERRIDE { + apps::AppShimFocusType focus_type, + const std::vector<base::FilePath>& file) OVERRIDE { ++focus_count_; } @@ -121,7 +126,7 @@ class AppShimHostTest : public testing::Test, TEST_F(AppShimHostTest, TestLaunchAppWithHandler) { apps::AppShimHandler::RegisterHandler(kTestAppId, this); - LaunchApp(true); + LaunchApp(apps::APP_SHIM_LAUNCH_NORMAL); EXPECT_EQ(kTestAppId, implicit_cast<apps::AppShimHandler::Host*>(host())->GetAppId()); EXPECT_EQ(apps::APP_SHIM_LAUNCH_SUCCESS, GetLaunchResult()); @@ -136,7 +141,8 @@ TEST_F(AppShimHostTest, TestLaunchAppWithHandler) { EXPECT_EQ(apps::APP_SHIM_LAUNCH_SUCCESS, GetLaunchResult()); EXPECT_TRUE(host()->ReceiveMessage( - new AppShimHostMsg_FocusApp(apps::APP_SHIM_FOCUS_NORMAL))); + new AppShimHostMsg_FocusApp(apps::APP_SHIM_FOCUS_NORMAL, + std::vector<base::FilePath>()))); EXPECT_EQ(1, focus_count_); EXPECT_TRUE(host()->ReceiveMessage(new AppShimHostMsg_QuitApp())); @@ -149,7 +155,7 @@ TEST_F(AppShimHostTest, TestLaunchAppWithHandler) { TEST_F(AppShimHostTest, TestNoLaunchNow) { apps::AppShimHandler::RegisterHandler(kTestAppId, this); - LaunchApp(false); + LaunchApp(apps::APP_SHIM_LAUNCH_REGISTER_ONLY); EXPECT_EQ(kTestAppId, implicit_cast<apps::AppShimHandler::Host*>(host())->GetAppId()); EXPECT_EQ(apps::APP_SHIM_LAUNCH_SUCCESS, GetLaunchResult()); @@ -163,7 +169,7 @@ TEST_F(AppShimHostTest, TestNoLaunchNow) { TEST_F(AppShimHostTest, TestFailLaunch) { apps::AppShimHandler::RegisterHandler(kTestAppId, this); launch_result_ = apps::APP_SHIM_LAUNCH_APP_NOT_FOUND; - LaunchApp(true); + LaunchApp(apps::APP_SHIM_LAUNCH_NORMAL); EXPECT_EQ(apps::APP_SHIM_LAUNCH_APP_NOT_FOUND, GetLaunchResult()); apps::AppShimHandler::RemoveHandler(kTestAppId); } diff --git a/apps/app_shim/app_shim_launch.h b/apps/app_shim/app_shim_launch.h index 7f0c126..26b6416 100644 --- a/apps/app_shim/app_shim_launch.h +++ b/apps/app_shim/app_shim_launch.h @@ -35,6 +35,8 @@ enum AppShimFocusType { APP_SHIM_FOCUS_NORMAL = 0, // Focus the app or launch it if it has no windows open. APP_SHIM_FOCUS_REOPEN, + // Open the given file in the app. + APP_SHIM_FOCUS_OPEN_FILES, // Counter and end marker. APP_SHIM_FOCUS_NUM_TYPES }; diff --git a/apps/app_shim/app_shim_messages.h b/apps/app_shim/app_shim_messages.h index 26a0263..75be2d0 100644 --- a/apps/app_shim/app_shim_messages.h +++ b/apps/app_shim/app_shim_messages.h @@ -5,10 +5,12 @@ // Multiply-included message file, hence no include guard. #include <string> +#include <vector> #include "apps/app_shim/app_shim_launch.h" #include "base/files/file_path.h" #include "ipc/ipc_message_macros.h" +#include "ipc/ipc_message_utils.h" #include "ipc/param_traits_macros.h" #define IPC_MESSAGE_START AppShimMsgStart @@ -34,17 +36,19 @@ IPC_MESSAGE_CONTROL0(AppShimMsg_RequestUserAttention) // 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, +IPC_MESSAGE_CONTROL4(AppShimHostMsg_LaunchApp, base::FilePath /* profile dir */, std::string /* app id */, - apps::AppShimLaunchType /* launch type */) + apps::AppShimLaunchType /* launch type */, + std::vector<base::FilePath> /* files */) // 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, or relaunches // if the focus type indicates a reopen and there are no open windows. -IPC_MESSAGE_CONTROL1(AppShimHostMsg_FocusApp, - apps::AppShimFocusType /* focus type */) +IPC_MESSAGE_CONTROL2(AppShimHostMsg_FocusApp, + apps::AppShimFocusType /* focus type */, + std::vector<base::FilePath> /* files */) // Sent when the app shim is hidden or unhidden. IPC_MESSAGE_CONTROL1(AppShimHostMsg_SetAppHidden, diff --git a/apps/app_shim/app_shim_quit_interactive_uitest_mac.mm b/apps/app_shim/app_shim_quit_interactive_uitest_mac.mm index 2651f61..d8d5fe7 100644 --- a/apps/app_shim/app_shim_quit_interactive_uitest_mac.mm +++ b/apps/app_shim/app_shim_quit_interactive_uitest_mac.mm @@ -5,6 +5,7 @@ // Tests behavior when quitting apps with app shims. #import <Cocoa/Cocoa.h> +#include <vector> #include "apps/app_shim/app_shim_host_manager_mac.h" #include "apps/app_shim/extension_app_shim_handler_mac.h" @@ -75,7 +76,9 @@ class AppShimQuitTest : public PlatformAppBrowserTest { host_.reset(new FakeHost(profile()->GetPath().BaseName(), extension_id_, handler_)); - handler_->OnShimLaunch(host_.get(), APP_SHIM_LAUNCH_REGISTER_ONLY); + handler_->OnShimLaunch(host_.get(), + APP_SHIM_LAUNCH_REGISTER_ONLY, + std::vector<base::FilePath>()); EXPECT_EQ(host_.get(), handler_->FindHost(profile(), extension_id_)); // Focus the app window. diff --git a/apps/app_shim/chrome_main_app_mode_mac.mm b/apps/app_shim/chrome_main_app_mode_mac.mm index 09d7ab7..6dca6b7 100644 --- a/apps/app_shim/chrome_main_app_mode_mac.mm +++ b/apps/app_shim/chrome_main_app_mode_mac.mm @@ -8,12 +8,15 @@ // those app bundles. #import <Cocoa/Cocoa.h> +#include <vector> #include "apps/app_shim/app_shim_messages.h" #include "base/at_exit.h" #include "base/command_line.h" +#include "base/files/file_path.h" #include "base/logging.h" #include "base/mac/bundle_locations.h" +#include "base/mac/foundation_util.h" #include "base/mac/launch_services_util.h" #include "base/mac/mac_logging.h" #include "base/mac/mac_util.h" @@ -54,18 +57,31 @@ base::Thread* g_io_thread = NULL; class AppShimController; +// An application delegate to catch user interactions and send the appropriate +// IPC messages to Chrome. @interface AppShimDelegate : NSObject<NSApplicationDelegate> { @private - AppShimController* appShimController_; // Weak. Owns us. + AppShimController* appShimController_; // Weak, initially NULL. BOOL terminateNow_; BOOL terminateRequested_; + std::vector<base::FilePath> filesToOpenAtStartup_; } -- (id)initWithController:(AppShimController*)controller; -- (BOOL)applicationOpenUntitledFile:(NSApplication *)app; -- (void)applicationWillBecomeActive:(NSNotification*)notification; -- (void)applicationWillHide:(NSNotification*)notification; -- (void)applicationWillUnhide:(NSNotification*)notification; +// The controller is initially NULL. Setting it indicates to the delegate that +// the controller has finished initialization. +- (void)setController:(AppShimController*)controller; + +// Gets files that were queued because the controller was not ready. +// Returns whether any FilePaths were added to |out|. +- (BOOL)getFilesToOpenAtStartup:(std::vector<base::FilePath>*)out; + +// If the controller is ready, this sends a FocusApp with the files to open. +// Otherwise, this adds the files to |filesToOpenAtStartup_|. +// Takes an array of NSString*. +- (void)openFiles:(NSArray*)filename; + +// Terminate immediately. This is necessary as we override terminate: to send +// a QuitApp message. - (void)terminateNow; @end @@ -75,6 +91,11 @@ class AppShimController; class AppShimController : public IPC::Listener { public: AppShimController(); + virtual ~AppShimController(); + + // Called when the main Chrome process responds to the Apple Event ping that + // was sent, or when the ping fails (if |success| is false). + void OnPingChromeReply(bool success); // Connects to Chrome and sends a LaunchApp message. void Init(); @@ -86,9 +107,11 @@ class AppShimController : public IPC::Listener { void SendQuitApp(); - // Called when the app is activated, either by the user clicking on it in the - // dock or by Cmd+Tabbing to it. - void ActivateApp(bool is_reopen); + // Called when the app is activated, e.g. by clicking on it in the dock, by + // dropping a file on the dock icon, or by Cmd+Tabbing to it. + // Returns whether the message was sent. + bool SendFocusApp(apps::AppShimFocusType focus_type, + const std::vector<base::FilePath>& files); private: // IPC::Listener implemetation. @@ -109,14 +132,34 @@ class AppShimController : public IPC::Listener { void Close(); IPC::ChannelProxy* channel_; - base::scoped_nsobject<AppShimDelegate> nsapp_delegate_; + base::scoped_nsobject<AppShimDelegate> delegate_; bool launch_app_done_; DISALLOW_COPY_AND_ASSIGN(AppShimController); }; -AppShimController::AppShimController() : channel_(NULL), - launch_app_done_(false) {} +AppShimController::AppShimController() + : channel_(NULL), + delegate_([[AppShimDelegate alloc] init]), + launch_app_done_(false) { + // Since AppShimController is created before the main message loop starts, + // NSApp will not be set, so use sharedApplication. + [[NSApplication sharedApplication] setDelegate:delegate_]; +} + +AppShimController::~AppShimController() { + // Un-set the delegate since NSApplication does not retain it. + [NSApp setDelegate:nil]; +} + +void AppShimController::OnPingChromeReply(bool success) { + if (!success) { + [NSApp terminate:nil]; + return; + } + + Init(); +} void AppShimController::Init() { DCHECK(g_io_thread); @@ -142,14 +185,16 @@ void AppShimController::Init() { bool launched_by_chrome = CommandLine::ForCurrentProcess()->HasSwitch( app_mode::kLaunchedByChromeProcessId); - channel_->Send(new AppShimHostMsg_LaunchApp( - g_info->profile_dir, g_info->app_mode_id, - launched_by_chrome ? - apps::APP_SHIM_LAUNCH_REGISTER_ONLY : apps::APP_SHIM_LAUNCH_NORMAL)); + apps::AppShimLaunchType launch_type = launched_by_chrome ? + apps::APP_SHIM_LAUNCH_REGISTER_ONLY : apps::APP_SHIM_LAUNCH_NORMAL; + + [delegate_ setController:this]; - nsapp_delegate_.reset([[AppShimDelegate alloc] initWithController:this]); - DCHECK(![NSApp delegate]); - [NSApp setDelegate:nsapp_delegate_]; + std::vector<base::FilePath> files; + [delegate_ getFilesToOpenAtStartup:&files]; + + channel_->Send(new AppShimHostMsg_LaunchApp( + g_info->profile_dir, g_info->app_mode_id, launch_type, files)); } void AppShimController::SetUpMenu() { @@ -212,6 +257,10 @@ void AppShimController::OnLaunchAppDone(apps::AppShimLaunchResult result) { return; } + std::vector<base::FilePath> files; + if ([delegate_ getFilesToOpenAtStartup:&files]) + SendFocusApp(apps::APP_SHIM_FOCUS_OPEN_FILES, files); + launch_app_done_ = true; } @@ -224,14 +273,17 @@ void AppShimController::OnRequestUserAttention() { } void AppShimController::Close() { - [nsapp_delegate_ terminateNow]; + [delegate_ terminateNow]; } -void AppShimController::ActivateApp(bool is_reopen) { +bool AppShimController::SendFocusApp(apps::AppShimFocusType focus_type, + const std::vector<base::FilePath>& files) { if (launch_app_done_) { - channel_->Send(new AppShimHostMsg_FocusApp( - is_reopen ? apps::APP_SHIM_FOCUS_REOPEN : apps::APP_SHIM_FOCUS_NORMAL)); + channel_->Send(new AppShimHostMsg_FocusApp(focus_type, files)); + return true; } + + return false; } void AppShimController::SendSetAppHidden(bool hidden) { @@ -240,25 +292,70 @@ void AppShimController::SendSetAppHidden(bool hidden) { @implementation AppShimDelegate -- (id)initWithController:(AppShimController*)controller { - if ((self = [super init])) { - appShimController_ = controller; +- (BOOL)getFilesToOpenAtStartup:(std::vector<base::FilePath>*)out { + if (filesToOpenAtStartup_.empty()) + return NO; + + out->insert(out->end(), + filesToOpenAtStartup_.begin(), + filesToOpenAtStartup_.end()); + filesToOpenAtStartup_.clear(); + return YES; +} + +- (void)setController:(AppShimController*)controller { + appShimController_ = controller; +} + +- (void)openFiles:(NSArray*)filenames { + std::vector<base::FilePath> filePaths; + for (NSString* filename in filenames) + filePaths.push_back(base::mac::NSStringToFilePath(filename)); + + // If the AppShimController is ready, try to send a FocusApp. If that fails, + // (e.g. if launching has not finished), enqueue the files. + if (appShimController_ && + appShimController_->SendFocusApp(apps::APP_SHIM_FOCUS_OPEN_FILES, + filePaths)) { + return; } - return self; + + filesToOpenAtStartup_.insert(filesToOpenAtStartup_.end(), + filePaths.begin(), + filePaths.end()); } -- (BOOL)applicationOpenUntitledFile:(NSApplication *)app { - appShimController_->ActivateApp(true); +- (BOOL)application:(NSApplication*)app + openFile:(NSString*)filename { + [self openFiles:@[filename]]; return YES; } +- (void)application:(NSApplication*)app + openFiles:(NSArray*)filenames { + [self openFiles:filenames]; + [app replyToOpenOrPrint:NSApplicationDelegateReplySuccess]; +} + +- (BOOL)applicationOpenUntitledFile:(NSApplication*)app { + if (appShimController_) { + return appShimController_->SendFocusApp(apps::APP_SHIM_FOCUS_REOPEN, + std::vector<base::FilePath>()); + } + + return NO; +} + - (void)applicationWillBecomeActive:(NSNotification*)notification { - appShimController_->ActivateApp(false); + if (appShimController_) { + appShimController_->SendFocusApp(apps::APP_SHIM_FOCUS_NORMAL, + std::vector<base::FilePath>()); + } } - (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*)sender { - if (terminateNow_) + if (terminateNow_ || !appShimController_) return NSTerminateNow; appShimController_->SendQuitApp(); @@ -268,11 +365,13 @@ void AppShimController::SendSetAppHidden(bool hidden) { } - (void)applicationWillHide:(NSNotification*)notification { - appShimController_->SendSetAppHidden(true); + if (appShimController_) + appShimController_->SendSetAppHidden(true); } - (void)applicationWillUnhide:(NSNotification*)notification { - appShimController_->SendSetAppHidden(false); + if (appShimController_) + appShimController_->SendSetAppHidden(false); } - (void)terminateNow { @@ -390,21 +489,6 @@ void AppShimController::SendSetAppHidden(bool hidden) { //----------------------------------------------------------------------------- -namespace { - -// Called when the main Chrome process responds to the Apple Event ping that -// was sent, or when the ping fails (if |success| is false). -void OnPingChromeReply(bool success) { - if (!success) { - [NSApp terminate:nil]; - return; - } - AppShimController* controller = new AppShimController; - controller->Init(); -} - -} // namespace - extern "C" { // |ChromeAppModeStart()| is the point of entry into the framework from the app @@ -501,10 +585,16 @@ int ChromeAppModeStart(const app_mode::ChromeAppModeInfo* info) { return 1; } + AppShimController controller; + base::Callback<void(bool)> on_ping_chrome_reply = + base::Bind(&AppShimController::OnPingChromeReply, + base::Unretained(&controller)); + // This code abuses the fact that Apple Events sent before the process is // fully initialized don't receive a reply until its run loop starts. Once // the reply is received, Chrome will have opened its IPC port, guaranteed. - [ReplyEventHandler pingProcess:psn andCall:base::Bind(&OnPingChromeReply)]; + [ReplyEventHandler pingProcess:psn + andCall:on_ping_chrome_reply]; base::MessageLoopForUI main_message_loop; main_message_loop.set_thread_name("MainThread"); diff --git a/apps/app_shim/extension_app_shim_handler_mac.cc b/apps/app_shim/extension_app_shim_handler_mac.cc index 86929fd..3f8d4e4 100644 --- a/apps/app_shim/extension_app_shim_handler_mac.cc +++ b/apps/app_shim/extension_app_shim_handler_mac.cc @@ -7,6 +7,7 @@ #include "apps/app_lifetime_monitor_factory.h" #include "apps/app_shim/app_shim_host_manager_mac.h" #include "apps/app_shim/app_shim_messages.h" +#include "apps/launcher.h" #include "apps/native_app_window.h" #include "apps/shell_window.h" #include "apps/shell_window_registry.h" @@ -20,7 +21,6 @@ #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" -#include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/web_applications/web_app_ui.h" #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h" #include "chrome/browser/web_applications/web_app_mac.h" @@ -120,11 +120,14 @@ ExtensionAppShimHandler::Delegate::GetAppExtension( void ExtensionAppShimHandler::Delegate::LaunchApp( Profile* profile, - const extensions::Extension* extension) { + const extensions::Extension* extension, + const std::vector<base::FilePath>& files) { CoreAppLauncherHandler::RecordAppLaunchType( extension_misc::APP_LAUNCH_CMD_LINE_APP, extension->GetType()); - chrome::OpenApplication( - chrome::AppLaunchParams(profile, extension, NEW_FOREGROUND_TAB)); + for (std::vector<base::FilePath>::const_iterator it = files.begin(); + it != files.end(); ++it) { + apps::LaunchPlatformAppWithPath(profile, extension, *it); + } } void ExtensionAppShimHandler::Delegate::LaunchShim( @@ -215,8 +218,10 @@ bool ExtensionAppShimHandler::RequestUserAttentionForWindow( } } -void ExtensionAppShimHandler::OnShimLaunch(Host* host, - AppShimLaunchType launch_type) { +void ExtensionAppShimHandler::OnShimLaunch( + Host* host, + AppShimLaunchType launch_type, + const std::vector<base::FilePath>& files) { const std::string& app_id = host->GetAppId(); DCHECK(extensions::Extension::IdIsValid(app_id)); @@ -235,7 +240,7 @@ void ExtensionAppShimHandler::OnShimLaunch(Host* host, Profile* profile = delegate_->ProfileForPath(profile_path); if (profile) { - OnProfileLoaded(host, launch_type, profile); + OnProfileLoaded(host, launch_type, files, profile); return; } @@ -247,14 +252,16 @@ void ExtensionAppShimHandler::OnShimLaunch(Host* host, profile_path, base::Bind(&ExtensionAppShimHandler::OnProfileLoaded, weak_factory_.GetWeakPtr(), - host, launch_type)); + host, launch_type, files)); // Return now. OnAppLaunchComplete will be called when the app is activated. } -void ExtensionAppShimHandler::OnProfileLoaded(Host* host, - AppShimLaunchType launch_type, - Profile* profile) { +void ExtensionAppShimHandler::OnProfileLoaded( + Host* host, + AppShimLaunchType launch_type, + const std::vector<base::FilePath>& files, + Profile* profile) { const std::string& app_id = host->GetAppId(); // TODO(jackhou): Add some UI for this case and remove the LOG. const extensions::Extension* extension = @@ -271,7 +278,8 @@ void ExtensionAppShimHandler::OnProfileLoaded(Host* host, if (!hosts_.insert(make_pair(make_pair(profile, app_id), host)).second) { OnShimFocus(host, launch_type == APP_SHIM_LAUNCH_NORMAL ? - APP_SHIM_FOCUS_REOPEN : APP_SHIM_FOCUS_NORMAL); + APP_SHIM_FOCUS_REOPEN : APP_SHIM_FOCUS_NORMAL, + files); host->OnAppLaunchComplete(APP_SHIM_LAUNCH_DUPLICATE_HOST); return; } @@ -281,7 +289,7 @@ void ExtensionAppShimHandler::OnProfileLoaded(Host* host, // exists/was created' and time out with failure if we don't see that sign of // life within a certain window. if (launch_type == APP_SHIM_LAUNCH_NORMAL) - delegate_->LaunchApp(profile, extension); + delegate_->LaunchApp(profile, extension, files); else host->OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS); } @@ -296,8 +304,10 @@ void ExtensionAppShimHandler::OnShimClose(Host* host) { } } -void ExtensionAppShimHandler::OnShimFocus(Host* host, - AppShimFocusType focus_type) { +void ExtensionAppShimHandler::OnShimFocus( + Host* host, + AppShimFocusType focus_type, + const std::vector<base::FilePath>& files) { DCHECK(delegate_->ProfileExistsForPath(host->GetProfilePath())); Profile* profile = delegate_->ProfileForPath(host->GetProfilePath()); @@ -314,19 +324,21 @@ void ExtensionAppShimHandler::OnShimFocus(Host* host, // relevant user settings. But shims don't have windows, so we // have to do it ourselves. ui::FocusWindowSet(native_windows, true); + } + + if (focus_type == APP_SHIM_FOCUS_NORMAL || + (focus_type == APP_SHIM_FOCUS_REOPEN && !native_windows.empty())) { return; } - if (focus_type == APP_SHIM_FOCUS_REOPEN) { - const extensions::Extension* extension = - delegate_->GetAppExtension(profile, host->GetAppId()); - if (extension) { - delegate_->LaunchApp(profile, extension); - } else { - // Extensions may have been uninstalled or disabled since the shim - // started. - host->OnAppClosed(); - } + const extensions::Extension* extension = + delegate_->GetAppExtension(profile, host->GetAppId()); + if (extension) { + delegate_->LaunchApp(profile, extension, files); + } else { + // Extensions may have been uninstalled or disabled since the shim + // started. + host->OnAppClosed(); } } @@ -409,7 +421,7 @@ void ExtensionAppShimHandler::OnAppActivated(Profile* profile, Host* host = FindHost(profile, app_id); if (host) { host->OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS); - OnShimFocus(host, APP_SHIM_FOCUS_NORMAL); + OnShimFocus(host, APP_SHIM_FOCUS_NORMAL, std::vector<base::FilePath>()); return; } diff --git a/apps/app_shim/extension_app_shim_handler_mac.h b/apps/app_shim/extension_app_shim_handler_mac.h index 07f0527..c4c0b1e 100644 --- a/apps/app_shim/extension_app_shim_handler_mac.h +++ b/apps/app_shim/extension_app_shim_handler_mac.h @@ -7,6 +7,7 @@ #include <map> #include <string> +#include <vector> #include "apps/app_lifetime_monitor.h" #include "apps/app_shim/app_shim_handler_mac.h" @@ -55,7 +56,8 @@ class ExtensionAppShimHandler : public AppShimHandler, virtual const extensions::Extension* GetAppExtension( Profile* profile, const std::string& extension_id); virtual void LaunchApp(Profile* profile, - const extensions::Extension* extension); + const extensions::Extension* extension, + const std::vector<base::FilePath>& files); virtual void LaunchShim(Profile* profile, const extensions::Extension* extension); @@ -76,9 +78,13 @@ class ExtensionAppShimHandler : public AppShimHandler, static bool RequestUserAttentionForWindow(ShellWindow* shell_window); // AppShimHandler overrides: - virtual void OnShimLaunch(Host* host, AppShimLaunchType launch_type) OVERRIDE; + virtual void OnShimLaunch(Host* host, + AppShimLaunchType launch_type, + const std::vector<base::FilePath>& files) OVERRIDE; virtual void OnShimClose(Host* host) OVERRIDE; - virtual void OnShimFocus(Host* host, AppShimFocusType focus_type) OVERRIDE; + virtual void OnShimFocus(Host* host, + AppShimFocusType focus_type, + const std::vector<base::FilePath>& files) OVERRIDE; virtual void OnShimSetHidden(Host* host, bool hidden) OVERRIDE; virtual void OnShimQuit(Host* host) OVERRIDE; @@ -110,6 +116,7 @@ class ExtensionAppShimHandler : public AppShimHandler, // where the profile was not yet loaded. void OnProfileLoaded(Host* host, AppShimLaunchType launch_type, + const std::vector<base::FilePath>& files, Profile* profile); scoped_ptr<Delegate> delegate_; 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 0b46f10..d0ac3b0 100644 --- a/apps/app_shim/extension_app_shim_handler_mac_unittest.cc +++ b/apps/app_shim/extension_app_shim_handler_mac_unittest.cc @@ -4,6 +4,8 @@ #include "apps/app_shim/extension_app_shim_handler_mac.h" +#include <vector> + #include "apps/app_shim/app_shim_host_mac.h" #include "base/memory/scoped_ptr.h" #include "chrome/browser/chrome_notification_types.h" @@ -35,7 +37,10 @@ class MockDelegate : public ExtensionAppShimHandler::Delegate { MOCK_METHOD2(GetWindows, ShellWindowList(Profile*, const std::string&)); MOCK_METHOD2(GetAppExtension, const Extension*(Profile*, const std::string&)); - MOCK_METHOD2(LaunchApp, void(Profile*, const Extension*)); + MOCK_METHOD3(LaunchApp, + void(Profile*, + const Extension*, + const std::vector<base::FilePath>&)); MOCK_METHOD2(LaunchShim, void(Profile*, const Extension*)); MOCK_METHOD0(MaybeTerminate, void()); @@ -65,10 +70,15 @@ class TestingExtensionAppShimHandler : public ExtensionAppShimHandler { } virtual ~TestingExtensionAppShimHandler() {} - MOCK_METHOD2(OnShimFocus, void(Host*, AppShimFocusType)); + MOCK_METHOD3(OnShimFocus, + void(Host* host, + AppShimFocusType, + const std::vector<base::FilePath>& files)); - void RealOnShimFocus(Host* host, AppShimFocusType focus_type) { - ExtensionAppShimHandler::OnShimFocus(host, focus_type); + void RealOnShimFocus(Host* host, + AppShimFocusType focus_type, + const std::vector<base::FilePath>& files) { + ExtensionAppShimHandler::OnShimFocus(host, focus_type, files); } AppShimHandler::Host* FindHost(Profile* profile, @@ -166,10 +176,22 @@ class ExtensionAppShimHandlerTest : public testing::Test { .WillRepeatedly(Return(extension_a_.get())); EXPECT_CALL(*delegate_, GetAppExtension(_, kTestAppIdB)) .WillRepeatedly(Return(extension_b_.get())); - EXPECT_CALL(*delegate_, LaunchApp(_,_)) + EXPECT_CALL(*delegate_, LaunchApp(_, _, _)) .WillRepeatedly(Return()); } + void NormalLaunch(AppShimHandler::Host* host) { + handler_->OnShimLaunch(host, + APP_SHIM_LAUNCH_NORMAL, + std::vector<base::FilePath>()); + } + + void RegisterOnlyLaunch(AppShimHandler::Host* host) { + handler_->OnShimLaunch(host, + APP_SHIM_LAUNCH_REGISTER_ONLY, + std::vector<base::FilePath>()); + } + MockDelegate* delegate_; scoped_ptr<TestingExtensionAppShimHandler> handler_; base::FilePath profile_path_a_; @@ -193,41 +215,45 @@ TEST_F(ExtensionAppShimHandlerTest, LaunchFailure) { .WillOnce(Return(false)) .WillRepeatedly(Return(true)); EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_PROFILE_NOT_FOUND)); - handler_->OnShimLaunch(&host_aa_, APP_SHIM_LAUNCH_NORMAL); + NormalLaunch(&host_aa_); // App not found. EXPECT_CALL(*delegate_, GetAppExtension(&profile_a_, kTestAppIdA)) .WillOnce(Return(static_cast<const Extension*>(NULL))) .WillRepeatedly(Return(extension_a_.get())); EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_APP_NOT_FOUND)); - handler_->OnShimLaunch(&host_aa_, APP_SHIM_LAUNCH_NORMAL); + NormalLaunch(&host_aa_); } TEST_F(ExtensionAppShimHandlerTest, LaunchAndCloseShim) { - const AppShimLaunchType normal_launch = APP_SHIM_LAUNCH_NORMAL; - // Normal startup. - handler_->OnShimLaunch(&host_aa_, normal_launch); + NormalLaunch(&host_aa_); EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA)); - handler_->OnShimLaunch(&host_ab_, normal_launch); + NormalLaunch(&host_ab_); EXPECT_EQ(&host_ab_, handler_->FindHost(&profile_a_, kTestAppIdB)); - handler_->OnShimLaunch(&host_bb_, normal_launch); + std::vector<base::FilePath> some_file(1, base::FilePath("some_file")); + EXPECT_CALL(*delegate_, + LaunchApp(&profile_b_, extension_b_.get(), some_file)); + handler_->OnShimLaunch(&host_bb_, APP_SHIM_LAUNCH_NORMAL, some_file); EXPECT_EQ(&host_bb_, handler_->FindHost(&profile_b_, kTestAppIdB)); // Activation when there is a registered shim finishes launch with success and // focuses the app. EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS)); - EXPECT_CALL(*handler_, OnShimFocus(&host_aa_, APP_SHIM_FOCUS_NORMAL)); + EXPECT_CALL(*handler_, OnShimFocus(&host_aa_, APP_SHIM_FOCUS_NORMAL, _)); handler_->OnAppActivated(&profile_a_, kTestAppIdA); // Starting and closing a second host just focuses the app. EXPECT_CALL(*handler_, OnShimFocus(&host_aa_duplicate_, - APP_SHIM_FOCUS_REOPEN)); + APP_SHIM_FOCUS_REOPEN, + some_file)); EXPECT_CALL(host_aa_duplicate_, OnAppLaunchComplete(APP_SHIM_LAUNCH_DUPLICATE_HOST)); - handler_->OnShimLaunch(&host_aa_duplicate_, normal_launch); + handler_->OnShimLaunch(&host_aa_duplicate_, + APP_SHIM_LAUNCH_NORMAL, + some_file); EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA)); handler_->OnShimClose(&host_aa_duplicate_); EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA)); @@ -248,10 +274,11 @@ TEST_F(ExtensionAppShimHandlerTest, AppLifetime) { // Normal shim launch adds an entry in the map. // App should not be launched here, but return success to the shim. - EXPECT_CALL(*delegate_, LaunchApp(&profile_a_, extension_a_.get())) + EXPECT_CALL(*delegate_, + LaunchApp(&profile_a_, extension_a_.get(), _)) .Times(0); EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS)); - handler_->OnShimLaunch(&host_aa_, APP_SHIM_LAUNCH_REGISTER_ONLY); + RegisterOnlyLaunch(&host_aa_); EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA)); // Return no shell windows for OnShimFocus and OnShimQuit. @@ -260,19 +287,24 @@ TEST_F(ExtensionAppShimHandlerTest, AppLifetime) { .WillRepeatedly(Return(shell_window_list)); // Non-reopen focus does nothing. - EXPECT_CALL(*handler_, OnShimFocus(&host_aa_, APP_SHIM_FOCUS_NORMAL)) + EXPECT_CALL(*handler_, OnShimFocus(&host_aa_, APP_SHIM_FOCUS_NORMAL, _)) .WillOnce(Invoke(handler_.get(), &TestingExtensionAppShimHandler::RealOnShimFocus)); - EXPECT_CALL(*delegate_, LaunchApp(&profile_a_, extension_a_.get())) + EXPECT_CALL(*delegate_, + LaunchApp(&profile_a_, extension_a_.get(), _)) .Times(0); - handler_->OnShimFocus(&host_aa_, APP_SHIM_FOCUS_NORMAL); + handler_->OnShimFocus(&host_aa_, + APP_SHIM_FOCUS_NORMAL, + std::vector<base::FilePath>()); // Reopen focus launches the app. - EXPECT_CALL(*handler_, OnShimFocus(&host_aa_, APP_SHIM_FOCUS_REOPEN)) + EXPECT_CALL(*handler_, OnShimFocus(&host_aa_, APP_SHIM_FOCUS_REOPEN, _)) .WillOnce(Invoke(handler_.get(), &TestingExtensionAppShimHandler::RealOnShimFocus)); - EXPECT_CALL(*delegate_, LaunchApp(&profile_a_, extension_a_.get())); - handler_->OnShimFocus(&host_aa_, APP_SHIM_FOCUS_REOPEN); + std::vector<base::FilePath> some_file(1, base::FilePath("some_file")); + EXPECT_CALL(*delegate_, + LaunchApp(&profile_a_, extension_a_.get(), some_file)); + handler_->OnShimFocus(&host_aa_, APP_SHIM_FOCUS_REOPEN, some_file); // Quit just closes all the windows. This tests that it doesn't terminate, // but we expect closing all windows triggers a OnAppDeactivated from @@ -288,15 +320,13 @@ TEST_F(ExtensionAppShimHandlerTest, AppLifetime) { } TEST_F(ExtensionAppShimHandlerTest, MaybeTerminate) { - const AppShimLaunchType register_only = APP_SHIM_LAUNCH_REGISTER_ONLY; - // Launch shims, adding entries in the map. EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS)); - handler_->OnShimLaunch(&host_aa_, register_only); + RegisterOnlyLaunch(&host_aa_); EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA)); EXPECT_CALL(host_ab_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS)); - handler_->OnShimLaunch(&host_ab_, register_only); + RegisterOnlyLaunch(&host_ab_); EXPECT_EQ(&host_ab_, handler_->FindHost(&profile_a_, kTestAppIdB)); // Return empty window list. @@ -315,7 +345,7 @@ TEST_F(ExtensionAppShimHandlerTest, MaybeTerminate) { // Launch a shim again. EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS)); - handler_->OnShimLaunch(&host_aa_, register_only); + RegisterOnlyLaunch(&host_aa_); EXPECT_EQ(&host_aa_, handler_->FindHost(&profile_a_, kTestAppIdA)); // Quitting after a browser window has opened should not terminate. @@ -329,10 +359,10 @@ TEST_F(ExtensionAppShimHandlerTest, MaybeTerminate) { TEST_F(ExtensionAppShimHandlerTest, RegisterOnly) { // For an APP_SHIM_LAUNCH_REGISTER_ONLY, don't launch the app. - EXPECT_CALL(*delegate_, LaunchApp(_, _)) + EXPECT_CALL(*delegate_, LaunchApp(_, _, _)) .Times(0); EXPECT_CALL(host_aa_, OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS)); - handler_->OnShimLaunch(&host_aa_, APP_SHIM_LAUNCH_REGISTER_ONLY); + RegisterOnlyLaunch(&host_aa_); EXPECT_TRUE(handler_->FindHost(&profile_a_, kTestAppIdA)); // Close the shim, removing the entry in the map. @@ -349,7 +379,7 @@ TEST_F(ExtensionAppShimHandlerTest, LoadProfile) { .WillRepeatedly(Return(&profile_a_)); EXPECT_CALL(*delegate_, LoadProfileAsync(profile_path_a_, _)) .WillOnce(Invoke(delegate_, &MockDelegate::CaptureLoadProfileCallback)); - handler_->OnShimLaunch(&host_aa_, APP_SHIM_LAUNCH_NORMAL); + NormalLaunch(&host_aa_); EXPECT_FALSE(handler_->FindHost(&profile_a_, kTestAppIdA)); delegate_->RunLoadProfileCallback(profile_path_a_, &profile_a_); EXPECT_TRUE(handler_->FindHost(&profile_a_, kTestAppIdA)); |