190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "apps/app_shim/extension_app_shim_handler_mac.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "apps/app_lifetime_monitor_factory.h"
8a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "apps/app_shim/app_shim_host_manager_mac.h"
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "apps/app_shim/app_shim_messages.h"
102385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch#include "apps/native_app_window.h"
11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "apps/shell_window.h"
124311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch#include "apps/shell_window_registry.h"
1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/files/file_path.h"
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/logging.h"
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/browser_process.h"
167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/extensions/extension_host.h"
1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/extensions/extension_system.h"
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/lifetime/application_lifetime.h"
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/profiles/profile.h"
22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/profiles/profile_manager.h"
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "chrome/browser/ui/extensions/application_launch.h"
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/ui/web_applications/web_app_ui.h"
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/web_applications/web_app_mac.h"
267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/public/browser/notification_details.h"
277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/public/browser/notification_service.h"
287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/public/browser/notification_source.h"
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/base/cocoa/focus_window_set.h"
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochnamespace {
327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ProfileLoadedCallback(base::Callback<void(Profile*)> callback,
347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                           Profile* profile,
357dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                           Profile::CreateStatus status) {
367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (status == Profile::CREATE_STATUS_INITIALIZED) {
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    callback.Run(profile);
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // This should never get an error since it only loads existing profiles.
427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_EQ(Profile::CREATE_STATUS_CREATED, status);
437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
45a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void TerminateIfNoShellWindows() {
46a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  bool shell_windows_left =
474311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch      apps::ShellWindowRegistry::IsShellWindowRegisteredInAnyProfile(0);
48a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!shell_windows_left)
49a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    chrome::AttemptExit();
50a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
51a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}  // namespace
537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace apps {
5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
564311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdochtypedef ShellWindowRegistry::ShellWindowList ShellWindowList;
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ExtensionAppShimHandler::Delegate::ProfileExistsForPath(
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const base::FilePath& path) {
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ProfileManager* profile_manager = g_browser_process->profile_manager();
61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Check for the profile name in the profile info cache to ensure that we
62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // never access any directory that isn't a known profile.
63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::FilePath full_path = profile_manager->user_data_dir().Append(path);
64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return cache.GetIndexOfProfileWithPath(full_path) != std::string::npos;
66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochProfile* ExtensionAppShimHandler::Delegate::ProfileForPath(
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const base::FilePath& path) {
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ProfileManager* profile_manager = g_browser_process->profile_manager();
71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::FilePath full_path = profile_manager->user_data_dir().Append(path);
727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  Profile* profile = profile_manager->GetProfileByPath(full_path);
737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Use IsValidProfile to check if the profile has been created.
757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return profile && profile_manager->IsValidProfile(profile) ? profile : NULL;
767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ExtensionAppShimHandler::Delegate::LoadProfileAsync(
797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const base::FilePath& path,
807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::Callback<void(Profile*)> callback) {
817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ProfileManager* profile_manager = g_browser_process->profile_manager();
827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::FilePath full_path = profile_manager->user_data_dir().Append(path);
837dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  profile_manager->CreateProfileAsync(
847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      full_path,
857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::Bind(&ProfileLoadedCallback, callback),
862385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      string16(), string16(), std::string());
87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochShellWindowList ExtensionAppShimHandler::Delegate::GetWindows(
90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    Profile* profile,
91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& extension_id) {
924311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  return ShellWindowRegistry::Get(profile)->GetShellWindowsForApp(extension_id);
93eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
94eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst extensions::Extension*
96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochExtensionAppShimHandler::Delegate::GetAppExtension(
97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    Profile* profile,
98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& extension_id) {
99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ExtensionService* extension_service =
100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      extensions::ExtensionSystem::Get(profile)->extension_service();
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(extension_service);
102eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const extensions::Extension* extension =
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      extension_service->GetExtensionById(extension_id, false);
104eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return extension && extension->is_platform_app() ? extension : NULL;
105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::Delegate::LaunchApp(
108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    Profile* profile,
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const extensions::Extension* extension) {
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  chrome::OpenApplication(
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      chrome::AppLaunchParams(profile, extension, NEW_FOREGROUND_TAB));
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
114eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::Delegate::LaunchShim(
115eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    Profile* profile,
116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const extensions::Extension* extension) {
117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  web_app::MaybeLaunchShortcut(
118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      web_app::ShortcutInfoForExtensionAndProfile(extension, profile));
119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
120eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::Delegate::MaybeTerminate() {
122a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // Post this to give ShellWindows a chance to remove themselves from the
123a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  // registry.
124a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  base::MessageLoop::current()->PostTask(
125a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      FROM_HERE,
126a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      base::Bind(&TerminateIfNoShellWindows));
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochExtensionAppShimHandler::ExtensionAppShimHandler()
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    : delegate_(new Delegate),
1317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      browser_opened_ever_(false),
1327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      weak_factory_(this) {
133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // This is instantiated in BrowserProcessImpl::PreMainMessageLoopRun with
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // AppShimHostManager. Since PROFILE_CREATED is not fired until
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // ProfileManager::GetLastUsedProfile/GetLastOpenedProfiles, this should catch
136eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // notifications for all profiles.
137eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 content::NotificationService::AllBrowserContextsAndSources());
139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 content::NotificationService::AllBrowserContextsAndSources());
141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 content::NotificationService::AllBrowserContextsAndSources());
1433240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
1443240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                 content::NotificationService::AllBrowserContextsAndSources());
145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 content::NotificationService::AllBrowserContextsAndSources());
147eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
148eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
149eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochExtensionAppShimHandler::~ExtensionAppShimHandler() {}
150eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
151a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)AppShimHandler::Host* ExtensionAppShimHandler::FindHost(
152a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    Profile* profile,
153a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const std::string& app_id) {
154a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  HostMap::iterator it = hosts_.find(make_pair(profile, app_id));
155a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return it == hosts_.end() ? NULL : it->second;
156a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
157a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
158a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// static
159a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void ExtensionAppShimHandler::QuitAppForWindow(ShellWindow* shell_window) {
160a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  ExtensionAppShimHandler* handler =
161a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      g_browser_process->platform_part()->app_shim_host_manager()->
162a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          extension_app_shim_handler();
163a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  Host* host = handler->FindHost(shell_window->profile(),
164a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                                 shell_window->extension_id());
165a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (host) {
166a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    handler->OnShimQuit(host);
167a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  } else {
168a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // App shims might be disabled or the shim is still starting up.
1694311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch    ShellWindowRegistry::Get(shell_window->profile())->
170a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        CloseAllShellWindowsForApp(shell_window->extension_id());
171a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
172a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
173a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
1747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ExtensionAppShimHandler::OnShimLaunch(Host* host,
175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                           AppShimLaunchType launch_type) {
1767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const std::string& app_id = host->GetAppId();
1777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK(extensions::Extension::IdIsValid(app_id));
1787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
179eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const base::FilePath& profile_path = host->GetProfilePath();
180eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(!profile_path.empty());
181eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!delegate_->ProfileExistsForPath(profile_path)) {
183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // User may have deleted the profile this shim was originally created for.
184eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // TODO(jackhou): Add some UI for this case and remove the LOG.
185eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(ERROR) << "Requested directory is not a known profile '"
186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch               << profile_path.value() << "'.";
1877dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    host->OnAppLaunchComplete(APP_SHIM_LAUNCH_PROFILE_NOT_FOUND);
1887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
191eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Profile* profile = delegate_->ProfileForPath(profile_path);
19290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (profile) {
1947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    OnProfileLoaded(host, launch_type, profile);
1957dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
19690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
19790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // If the profile is not loaded, this must have been a launch by the shim.
1997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Load the profile asynchronously, the host will be registered in
2007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // OnProfileLoaded.
2017dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_EQ(APP_SHIM_LAUNCH_NORMAL, launch_type);
2027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  delegate_->LoadProfileAsync(
2037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      profile_path,
2047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::Bind(&ExtensionAppShimHandler::OnProfileLoaded,
2057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                 weak_factory_.GetWeakPtr(),
2067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                 host, launch_type));
2077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Return now. OnAppLaunchComplete will be called when the app is activated.
2097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
2107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ExtensionAppShimHandler::OnProfileLoaded(Host* host,
2127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                              AppShimLaunchType launch_type,
2137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                              Profile* profile) {
2147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const std::string& app_id = host->GetAppId();
215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // TODO(jackhou): Add some UI for this case and remove the LOG.
216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const extensions::Extension* extension =
217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      delegate_->GetAppExtension(profile, app_id);
218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!extension) {
219eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(ERROR) << "Attempted to launch nonexistent app with id '"
220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch               << app_id << "'.";
2217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    host->OnAppLaunchComplete(APP_SHIM_LAUNCH_APP_NOT_FOUND);
2227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
22490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // The first host to claim this (profile, app_id) becomes the main host.
2267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // For any others, focus or relaunch the app.
2277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!hosts_.insert(make_pair(make_pair(profile, app_id), host)).second) {
2287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    OnShimFocus(host,
2297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                launch_type == APP_SHIM_LAUNCH_NORMAL ?
2307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    APP_SHIM_FOCUS_REOPEN : APP_SHIM_FOCUS_NORMAL);
2317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    host->OnAppLaunchComplete(APP_SHIM_LAUNCH_DUPLICATE_HOST);
2327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
233868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
23490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
235eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // TODO(jeremya): Handle the case that launching the app fails. Probably we
236eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // need to watch for 'app successfully launched' or at least 'background page
237eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // exists/was created' and time out with failure if we don't see that sign of
238eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // life within a certain window.
239eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (launch_type == APP_SHIM_LAUNCH_NORMAL)
240eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    delegate_->LaunchApp(profile, extension);
2417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  else
2427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    host->OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS);
24390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
24490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
24590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ExtensionAppShimHandler::OnShimClose(Host* host) {
2467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // This might be called when shutting down. Don't try to look up the profile
2477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // since profile_manager might not be around.
2487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  for (HostMap::iterator it = hosts_.begin(); it != hosts_.end(); ) {
2497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    HostMap::iterator current = it++;
2507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (current->second == host)
2517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      hosts_.erase(current);
2527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
25390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
25490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
255eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::OnShimFocus(Host* host,
256eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                          AppShimFocusType focus_type) {
257eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(delegate_->ProfileExistsForPath(host->GetProfilePath()));
258eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Profile* profile = delegate_->ProfileForPath(host->GetProfilePath());
25990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
260eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const ShellWindowList windows =
261eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      delegate_->GetWindows(profile, host->GetAppId());
26290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::set<gfx::NativeWindow> native_windows;
263eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (ShellWindowList::const_iterator it = windows.begin();
264868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       it != windows.end(); ++it) {
265868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    native_windows.insert((*it)->GetNativeWindow());
26690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
267eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!native_windows.empty()) {
268eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ui::FocusWindowSet(native_windows);
269eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
270eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
271eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
272eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (focus_type == APP_SHIM_FOCUS_REOPEN) {
273eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const extensions::Extension* extension =
274eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        delegate_->GetAppExtension(profile, host->GetAppId());
275eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (extension) {
276eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      delegate_->LaunchApp(profile, extension);
277eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    } else {
278eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // Extensions may have been uninstalled or disabled since the shim
279eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // started.
280eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      host->OnAppClosed();
281eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
282eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
283eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
284eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
285eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::OnShimSetHidden(Host* host, bool hidden) {
286eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(delegate_->ProfileExistsForPath(host->GetProfilePath()));
287eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Profile* profile = delegate_->ProfileForPath(host->GetProfilePath());
288eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
289eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const ShellWindowList windows =
290eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      delegate_->GetWindows(profile, host->GetAppId());
291eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  for (ShellWindowList::const_reverse_iterator it = windows.rbegin();
292eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       it != windows.rend(); ++it) {
293eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    if (hidden)
294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      (*it)->GetBaseWindow()->Hide();
295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    else
296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      (*it)->GetBaseWindow()->ShowInactive();
297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
29890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
29990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
300868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ExtensionAppShimHandler::OnShimQuit(Host* host) {
301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(delegate_->ProfileExistsForPath(host->GetProfilePath()));
302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Profile* profile = delegate_->ProfileForPath(host->GetProfilePath());
303868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
304a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  const std::string& app_id = host->GetAppId();
305eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const ShellWindowList windows =
306a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      delegate_->GetWindows(profile, app_id);
3074311e82a78ceafbe0585f51d4c8a86df9f21aa0dBen Murdoch  for (ShellWindowRegistry::const_iterator it = windows.begin();
308868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)       it != windows.end(); ++it) {
309868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    (*it)->GetBaseWindow()->Close();
310868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
311868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
312a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  DCHECK_NE(0u, hosts_.count(make_pair(profile, app_id)));
313a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  host->OnAppClosed();
314868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
315eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!browser_opened_ever_ && hosts_.empty())
316eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    delegate_->MaybeTerminate();
317eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
319eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::set_delegate(Delegate* delegate) {
320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  delegate_.reset(delegate);
32190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
32290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
32390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ExtensionAppShimHandler::Observe(
32490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    int type,
32590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const content::NotificationSource& source,
32690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const content::NotificationDetails& details) {
327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (type == chrome::NOTIFICATION_BROWSER_OPENED) {
328eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    registrar_.Remove(
329eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        this, chrome::NOTIFICATION_BROWSER_OPENED,
330eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        content::NotificationService::AllBrowserContextsAndSources());
331eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    browser_opened_ever_ = true;
332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
333eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
334eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
33590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  Profile* profile = content::Source<Profile>(source).ptr();
336eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (profile->IsOffTheRecord())
337eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
338eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
33990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  switch (type) {
340eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case chrome::NOTIFICATION_PROFILE_CREATED: {
341eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      AppLifetimeMonitorFactory::GetForProfile(profile)->AddObserver(this);
342eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
343eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
344eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case chrome::NOTIFICATION_PROFILE_DESTROYED: {
345eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      AppLifetimeMonitorFactory::GetForProfile(profile)->RemoveObserver(this);
346eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // Shut down every shim associated with this profile.
347eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      for (HostMap::iterator it = hosts_.begin(); it != hosts_.end(); ) {
348eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        // Increment the iterator first as OnAppClosed may call back to
349eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        // OnShimClose and invalidate the iterator.
350eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        HostMap::iterator current = it++;
351eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        if (profile->IsSameProfile(current->first.first))
352eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch          current->second->OnAppClosed();
353eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
354868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
355eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
3563240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED:
357eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: {
3583240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      std::string app_id;
3593240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      if (type == chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED) {
3603240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        app_id = content::Details<extensions::ExtensionHost>(details).ptr()
3613240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch            ->extension_id();
3623240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      } else {
3633240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch        app_id = content::Details<extensions::Extension>(details).ptr()->id();
3643240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch      }
365a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      Host* host = FindHost(profile, app_id);
366a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      if (host)
367a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        host->OnAppClosed();
36890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
369eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
370eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    default: {
37190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      NOTREACHED();  // Unexpected notification.
37290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
373eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
37490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
37590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
37690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
377eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::OnAppStart(Profile* profile,
378eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                         const std::string& app_id) {}
379eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
380eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::OnAppActivated(Profile* profile,
381eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                             const std::string& app_id) {
382eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const extensions::Extension* extension =
383eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      delegate_->GetAppExtension(profile, app_id);
384eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!extension)
385868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
386868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
387a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  Host* host = FindHost(profile, app_id);
388a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (host) {
389a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    host->OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS);
390a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    OnShimFocus(host, APP_SHIM_FOCUS_NORMAL);
391868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
3927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
393868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
394eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  delegate_->LaunchShim(profile, extension);
395868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
396868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
397eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::OnAppDeactivated(Profile* profile,
398eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                               const std::string& app_id) {}
399eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
400eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::OnAppStop(Profile* profile,
401eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                        const std::string& app_id) {}
402eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
403eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::OnChromeTerminating() {}
40490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
40590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace apps
406