summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorjackhou@chromium.org <jackhou@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-10 23:23:50 +0000
committerjackhou@chromium.org <jackhou@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-10 23:23:50 +0000
commit25321031d80042c0b13fbb83ce706b2c45239f2a (patch)
treeecf37270632e1ee069aa2ea723b7ce9639cdbb4b /apps
parentab862306ca2fd7a95d139ae66a2cc1ee06f0211a (diff)
downloadchromium_src-25321031d80042c0b13fbb83ce706b2c45239f2a.zip
chromium_src-25321031d80042c0b13fbb83ce706b2c45239f2a.tar.gz
chromium_src-25321031d80042c0b13fbb83ce706b2c45239f2a.tar.bz2
Enable passing a file path to an app via its shim.
This allows opening a file with a packaged app by dropping the file the app shim's dock icon or app bundle. A base::FilePath param is added to the Launch and Focus IPC messages and respective AppShimHandler methods. The file path ultimately is added to the command line used by OpenApplication. The shim is modified to set a custom NSApplicationDelegate early in order to capture the call to application:openFile:. The file name is saved and sent via LaunchApp in AppShimController::Init. BUG=168080 TEST=Drag a file onto an app shim. The app should start and open the file. Drag a file onto the app shim's dock icon. The app should open the file. Review URL: https://chromiumcodereview.appspot.com/21005003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@222391 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'apps')
-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));