summaryrefslogtreecommitdiffstats
path: root/apps/app_shim
diff options
context:
space:
mode:
Diffstat (limited to 'apps/app_shim')
-rw-r--r--apps/app_shim/app_shim_handler_mac.h15
-rw-r--r--apps/app_shim/app_shim_host_mac.cc14
-rw-r--r--apps/app_shim/app_shim_host_mac.h11
-rw-r--r--apps/app_shim/app_shim_host_mac_unittest.cc28
-rw-r--r--apps/app_shim/app_shim_launch.h2
-rw-r--r--apps/app_shim/app_shim_messages.h12
-rw-r--r--apps/app_shim/app_shim_quit_interactive_uitest_mac.mm5
-rw-r--r--apps/app_shim/chrome_main_app_mode_mac.mm188
-rw-r--r--apps/app_shim/extension_app_shim_handler_mac.cc64
-rw-r--r--apps/app_shim/extension_app_shim_handler_mac.h13
-rw-r--r--apps/app_shim/extension_app_shim_handler_mac_unittest.cc92
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));