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)
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h"
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "apps/app_lifetime_monitor_factory.h"
858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "apps/launcher.h"
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/files/file_path.h"
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/logging.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/apps/app_shim/app_shim_host_manager_mac.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/browser_process.h"
137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/profiles/profile.h"
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/profiles/profile_manager.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/ui/extensions/extension_enable_flow.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/browser/web_applications/web_app_mac.h"
203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)#include "chrome/common/extensions/extension_constants.h"
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/common/mac/app_shim_messages.h"
2203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "components/crx_file/id_util.h"
237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/public/browser/notification_details.h"
247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/public/browser/notification_service.h"
257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "content/public/browser/notification_source.h"
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/app_window/app_window.h"
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/browser/app_window/app_window_registry.h"
2803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "extensions/browser/app_window/native_app_window.h"
2923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "extensions/browser/extension_host.h"
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "extensions/browser/extension_registry.h"
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "ui/base/cocoa/focus_window_set.h"
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciusing extensions::AppWindow;
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciusing extensions::AppWindowRegistry;
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using extensions::ExtensionRegistry;
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochnamespace {
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccitypedef AppWindowRegistry::AppWindowList AppWindowList;
40424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ProfileLoadedCallback(base::Callback<void(Profile*)> callback,
427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                           Profile* profile,
437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                           Profile::CreateStatus status) {
447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (status == Profile::CREATE_STATUS_INITIALIZED) {
457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    callback.Run(profile);
467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // This should never get an error since it only loads existing profiles.
507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_EQ(Profile::CREATE_STATUS_CREATED, status);
517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
53424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void SetAppHidden(Profile* profile, const std::string& app_id, bool hidden) {
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  AppWindowList windows =
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      AppWindowRegistry::Get(profile)->GetAppWindowsForApp(app_id);
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (AppWindowList::const_reverse_iterator it = windows.rbegin();
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != windows.rend();
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++it) {
59424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (hidden)
60424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      (*it)->GetBaseWindow()->HideWithApp();
61424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    else
62424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      (*it)->GetBaseWindow()->ShowWithApp();
63424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
64424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
65424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool FocusWindows(const AppWindowList& windows) {
67d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (windows.empty())
68d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    return false;
69d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
70d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::set<gfx::NativeWindow> native_windows;
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (AppWindowList::const_iterator it = windows.begin(); it != windows.end();
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++it) {
73d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    native_windows.insert((*it)->GetNativeWindow());
74d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
75d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Allow workspace switching. For the browser process, we can reasonably rely
76d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // on OS X to switch spaces for us and honor relevant user settings. But shims
77d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // don't have windows, so we have to do it ourselves.
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ui::FocusWindowSet(native_windows);
79d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  return true;
80d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
81d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Attempts to launch a packaged app, prompting the user to enable it if
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// necessary. The prompt is shown in its own window.
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// This class manages its own lifetime.
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class EnableViaPrompt : public ExtensionEnableFlowDelegate {
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EnableViaPrompt(Profile* profile,
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  const std::string& extension_id,
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                  const base::Callback<void()>& callback)
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      : profile_(profile),
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        extension_id_(extension_id),
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        callback_(callback) {
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~EnableViaPrompt() {
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void Run() {
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    flow_.reset(new ExtensionEnableFlow(profile_, extension_id_, this));
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    flow_->StartForCurrentlyNonexistentWindow(
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::Callback<gfx::NativeWindow(void)>());
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // ExtensionEnableFlowDelegate overrides.
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void ExtensionEnableFlowFinished() OVERRIDE {
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback_.Run();
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    delete this;
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void ExtensionEnableFlowAborted(bool user_initiated) OVERRIDE {
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    callback_.Run();
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    delete this;
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Profile* profile_;
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string extension_id_;
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::Callback<void()> callback_;
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<ExtensionEnableFlow> flow_;
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(EnableViaPrompt);
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}  // namespace
1257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace apps {
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
128eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool ExtensionAppShimHandler::Delegate::ProfileExistsForPath(
129eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const base::FilePath& path) {
130eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ProfileManager* profile_manager = g_browser_process->profile_manager();
131eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Check for the profile name in the profile info cache to ensure that we
132eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // never access any directory that isn't a known profile.
133eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::FilePath full_path = profile_manager->user_data_dir().Append(path);
134eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
135eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return cache.GetIndexOfProfileWithPath(full_path) != std::string::npos;
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochProfile* ExtensionAppShimHandler::Delegate::ProfileForPath(
139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const base::FilePath& path) {
140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  ProfileManager* profile_manager = g_browser_process->profile_manager();
141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::FilePath full_path = profile_manager->user_data_dir().Append(path);
1427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  Profile* profile = profile_manager->GetProfileByPath(full_path);
1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Use IsValidProfile to check if the profile has been created.
1457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return profile && profile_manager->IsValidProfile(profile) ? profile : NULL;
1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
1477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochvoid ExtensionAppShimHandler::Delegate::LoadProfileAsync(
1497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    const base::FilePath& path,
1507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::Callback<void(Profile*)> callback) {
1517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  ProfileManager* profile_manager = g_browser_process->profile_manager();
1527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::FilePath full_path = profile_manager->user_data_dir().Append(path);
1537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  profile_manager->CreateProfileAsync(
1547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      full_path,
1557dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::Bind(&ProfileLoadedCallback, callback),
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::string16(), base::string16(), std::string());
157eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
158eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)AppWindowList ExtensionAppShimHandler::Delegate::GetWindows(
160eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    Profile* profile,
161eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& extension_id) {
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return AppWindowRegistry::Get(profile)->GetAppWindowsForApp(extension_id);
163eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
164eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
165eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochconst extensions::Extension*
166eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochExtensionAppShimHandler::Delegate::GetAppExtension(
167eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    Profile* profile,
168eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::string& extension_id) {
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
170eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const extensions::Extension* extension =
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      registry->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return extension && extension->is_platform_app() ? extension : NULL;
173eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
174eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ExtensionAppShimHandler::Delegate::EnableExtension(
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Profile* profile,
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& extension_id,
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::Callback<void()>& callback) {
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  (new EnableViaPrompt(profile, extension_id, callback))->Run();
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
182eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::Delegate::LaunchApp(
183eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    Profile* profile,
18458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const extensions::Extension* extension,
18558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::vector<base::FilePath>& files) {
1863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CoreAppLauncherHandler::RecordAppLaunchType(
1873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      extension_misc::APP_LAUNCH_CMD_LINE_APP, extension->GetType());
18868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (files.empty()) {
18968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    apps::LaunchPlatformApp(profile, extension);
19068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  } else {
19168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    for (std::vector<base::FilePath>::const_iterator it = files.begin();
19268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)         it != files.end(); ++it) {
19368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      apps::LaunchPlatformAppWithPath(profile, extension, *it);
19468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    }
19558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
196eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
197eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
198eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::Delegate::LaunchShim(
199eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    Profile* profile,
200eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const extensions::Extension* extension) {
201eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  web_app::MaybeLaunchShortcut(
202eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      web_app::ShortcutInfoForExtensionAndProfile(extension, profile));
203eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
204eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
205eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::Delegate::MaybeTerminate() {
2064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AppShimHandler::MaybeTerminate();
20790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
20890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
209eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochExtensionAppShimHandler::ExtensionAppShimHandler()
210eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    : delegate_(new Delegate),
2117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      weak_factory_(this) {
212eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // This is instantiated in BrowserProcessImpl::PreMainMessageLoopRun with
213eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // AppShimHostManager. Since PROFILE_CREATED is not fired until
214eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // ProfileManager::GetLastUsedProfile/GetLastOpenedProfiles, this should catch
215eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // notifications for all profiles.
216eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
217eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 content::NotificationService::AllBrowserContextsAndSources());
218eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
219eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                 content::NotificationService::AllBrowserContextsAndSources());
220eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
221eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
222eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochExtensionAppShimHandler::~ExtensionAppShimHandler() {}
223eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
224a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)AppShimHandler::Host* ExtensionAppShimHandler::FindHost(
225a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    Profile* profile,
226a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    const std::string& app_id) {
227a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  HostMap::iterator it = hosts_.find(make_pair(profile, app_id));
228a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  return it == hosts_.end() ? NULL : it->second;
229a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
230a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
231a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// static
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ExtensionAppShimHandler::QuitAppForWindow(AppWindow* app_window) {
2335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ExtensionAppShimHandler* handler = GetInstance();
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Host* host = handler->FindHost(
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      Profile::FromBrowserContext(app_window->browser_context()),
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      app_window->extension_id());
237a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (host) {
238a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    handler->OnShimQuit(host);
239a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  } else {
240a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    // App shims might be disabled or the shim is still starting up.
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    AppWindowRegistry::Get(
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        Profile::FromBrowserContext(app_window->browser_context()))
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ->CloseAllAppWindowsForApp(app_window->extension_id());
244a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
245a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
246a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ExtensionAppShimHandler::HideAppForWindow(AppWindow* app_window) {
2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ExtensionAppShimHandler* handler = GetInstance();
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(app_window->browser_context());
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Host* host = handler->FindHost(profile, app_window->extension_id());
25158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (host)
25258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    host->OnAppHide();
25358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  else
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetAppHidden(profile, app_window->extension_id(), true);
25558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
25658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ExtensionAppShimHandler::FocusAppForWindow(AppWindow* app_window) {
2585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ExtensionAppShimHandler* handler = GetInstance();
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(app_window->browser_context());
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string& app_id = app_window->extension_id();
261d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  Host* host = handler->FindHost(profile, app_id);
262d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (host) {
263d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    handler->OnShimFocus(host,
264d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                         APP_SHIM_FOCUS_NORMAL,
265d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                         std::vector<base::FilePath>());
266d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  } else {
2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    FocusWindows(AppWindowRegistry::Get(profile)->GetAppWindowsForApp(app_id));
268d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
269d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
270d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
271424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// static
27203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)bool ExtensionAppShimHandler::ActivateAndRequestUserAttentionForWindow(
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    AppWindow* app_window) {
2745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ExtensionAppShimHandler* handler = GetInstance();
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(app_window->browser_context());
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Host* host = handler->FindHost(profile, app_window->extension_id());
277424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (host) {
278424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Bring the window to the front without showing it.
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    AppWindowRegistry::Get(profile)->AppWindowActivated(app_window);
28003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    host->OnAppRequestUserAttention(APP_SHIM_ATTENTION_INFORMATIONAL);
281424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return true;
282424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  } else {
283424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Just show the app.
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    SetAppHidden(profile, app_window->extension_id(), false);
285424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return false;
286424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
287424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
288424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// static
29003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)void ExtensionAppShimHandler::RequestUserAttentionForWindow(
29103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    AppWindow* app_window,
29203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    AppShimAttentionType attention_type) {
29303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  ExtensionAppShimHandler* handler = GetInstance();
29403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  Profile* profile = Profile::FromBrowserContext(app_window->browser_context());
29503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  Host* host = handler->FindHost(profile, app_window->extension_id());
29603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (host)
29703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    host->OnAppRequestUserAttention(attention_type);
29803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)}
29903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
30003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)// static
3015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ExtensionAppShimHandler::OnChromeWillHide() {
3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Send OnAppHide to all the shims so that they go into the hidden state.
3035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // This is necessary so that when the shim is next focused, it will know to
3045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // unhide.
3055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ExtensionAppShimHandler* handler = GetInstance();
3065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  for (HostMap::iterator it = handler->hosts_.begin();
3075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       it != handler->hosts_.end();
3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)       ++it) {
3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    it->second->OnAppHide();
3105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
31358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void ExtensionAppShimHandler::OnShimLaunch(
31458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Host* host,
31558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AppShimLaunchType launch_type,
31658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::vector<base::FilePath>& files) {
3177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const std::string& app_id = host->GetAppId();
31803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  DCHECK(crx_file::id_util::IdIsValid(app_id));
3197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
320eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const base::FilePath& profile_path = host->GetProfilePath();
321eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(!profile_path.empty());
322eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
323eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!delegate_->ProfileExistsForPath(profile_path)) {
324eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // User may have deleted the profile this shim was originally created for.
325eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // TODO(jackhou): Add some UI for this case and remove the LOG.
326eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    LOG(ERROR) << "Requested directory is not a known profile '"
327eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch               << profile_path.value() << "'.";
3287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    host->OnAppLaunchComplete(APP_SHIM_LAUNCH_PROFILE_NOT_FOUND);
3297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
330eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
331eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
332eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Profile* profile = delegate_->ProfileForPath(profile_path);
33390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (profile) {
33558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    OnProfileLoaded(host, launch_type, files, profile);
3367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
33890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // If the profile is not loaded, this must have been a launch by the shim.
3407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Load the profile asynchronously, the host will be registered in
3417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // OnProfileLoaded.
3427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  DCHECK_EQ(APP_SHIM_LAUNCH_NORMAL, launch_type);
3437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  delegate_->LoadProfileAsync(
3447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      profile_path,
3457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      base::Bind(&ExtensionAppShimHandler::OnProfileLoaded,
3467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                 weak_factory_.GetWeakPtr(),
34758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                 host, launch_type, files));
3487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // Return now. OnAppLaunchComplete will be called when the app is activated.
3507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
3517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// static
3535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)ExtensionAppShimHandler* ExtensionAppShimHandler::GetInstance() {
3545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return g_browser_process->platform_part()
3555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      ->app_shim_host_manager()
3565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      ->extension_app_shim_handler();
3575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
35958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void ExtensionAppShimHandler::OnProfileLoaded(
36058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Host* host,
36158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AppShimLaunchType launch_type,
36258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::vector<base::FilePath>& files,
36358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Profile* profile) {
3647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  const std::string& app_id = host->GetAppId();
36590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // The first host to claim this (profile, app_id) becomes the main host.
3677dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // For any others, focus or relaunch the app.
3687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!hosts_.insert(make_pair(make_pair(profile, app_id), host)).second) {
3697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    OnShimFocus(host,
3707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                launch_type == APP_SHIM_LAUNCH_NORMAL ?
37158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    APP_SHIM_FOCUS_REOPEN : APP_SHIM_FOCUS_NORMAL,
37258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                files);
3737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    host->OnAppLaunchComplete(APP_SHIM_LAUNCH_DUPLICATE_HOST);
3747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return;
375868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
37690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (launch_type != APP_SHIM_LAUNCH_NORMAL) {
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    host->OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS);
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
382eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // TODO(jeremya): Handle the case that launching the app fails. Probably we
383eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // need to watch for 'app successfully launched' or at least 'background page
384eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // exists/was created' and time out with failure if we don't see that sign of
385eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // life within a certain window.
3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const extensions::Extension* extension =
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      delegate_->GetAppExtension(profile, app_id);
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (extension) {
38958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    delegate_->LaunchApp(profile, extension, files);
3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  delegate_->EnableExtension(
3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      profile, app_id,
3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::Bind(&ExtensionAppShimHandler::OnExtensionEnabled,
3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 weak_factory_.GetWeakPtr(),
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                 host->GetProfilePath(), app_id, files));
39890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
39990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ExtensionAppShimHandler::OnExtensionEnabled(
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const base::FilePath& profile_path,
4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::string& app_id,
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const std::vector<base::FilePath>& files) {
4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Profile* profile = delegate_->ProfileForPath(profile_path);
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!profile)
4065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const extensions::Extension* extension =
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      delegate_->GetAppExtension(profile, app_id);
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!extension || !delegate_->ProfileExistsForPath(profile_path)) {
4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // If !extension, the extension doesn't exist, or was not re-enabled.
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // If the profile doesn't exist, it may have been deleted during the enable
4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // prompt. In this case, NOTIFICATION_PROFILE_DESTROYED may not be fired
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // until later, so respond to the host now.
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Host* host = FindHost(profile, app_id);
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (host)
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      host->OnAppLaunchComplete(APP_SHIM_LAUNCH_APP_NOT_FOUND);
4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  delegate_->LaunchApp(profile, extension, files);
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
42590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ExtensionAppShimHandler::OnShimClose(Host* host) {
4267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // This might be called when shutting down. Don't try to look up the profile
4277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  // since profile_manager might not be around.
4287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  for (HostMap::iterator it = hosts_.begin(); it != hosts_.end(); ) {
4297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    HostMap::iterator current = it++;
4307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (current->second == host)
4317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      hosts_.erase(current);
4327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
43390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
43490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
43558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void ExtensionAppShimHandler::OnShimFocus(
43658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Host* host,
43758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    AppShimFocusType focus_type,
43858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    const std::vector<base::FilePath>& files) {
439eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(delegate_->ProfileExistsForPath(host->GetProfilePath()));
440eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Profile* profile = delegate_->ProfileForPath(host->GetProfilePath());
44190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const AppWindowList windows =
443eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      delegate_->GetWindows(profile, host->GetAppId());
444d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  bool windows_focused = FocusWindows(windows);
44558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
44658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (focus_type == APP_SHIM_FOCUS_NORMAL ||
447d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      (focus_type == APP_SHIM_FOCUS_REOPEN && windows_focused)) {
448eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
449eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
450eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
45158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  const extensions::Extension* extension =
45258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      delegate_->GetAppExtension(profile, host->GetAppId());
45358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (extension) {
45458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    delegate_->LaunchApp(profile, extension, files);
45558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  } else {
45658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // Extensions may have been uninstalled or disabled since the shim
45758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    // started.
45858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    host->OnAppClosed();
459eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
460eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
461eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
462eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::OnShimSetHidden(Host* host, bool hidden) {
463eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(delegate_->ProfileExistsForPath(host->GetProfilePath()));
464eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Profile* profile = delegate_->ProfileForPath(host->GetProfilePath());
465eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
466424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  SetAppHidden(profile, host->GetAppId(), hidden);
46790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
46890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
469868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ExtensionAppShimHandler::OnShimQuit(Host* host) {
470eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(delegate_->ProfileExistsForPath(host->GetProfilePath()));
471eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  Profile* profile = delegate_->ProfileForPath(host->GetProfilePath());
472868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
473a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  const std::string& app_id = host->GetAppId();
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const AppWindowList windows = delegate_->GetWindows(profile, app_id);
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (AppWindowRegistry::const_iterator it = windows.begin();
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       it != windows.end();
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++it) {
478868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    (*it)->GetBaseWindow()->Close();
479868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
480424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Once the last window closes, flow will end up in OnAppDeactivated via
481424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // AppLifetimeMonitor.
482eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
483868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
484eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::set_delegate(Delegate* delegate) {
485eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  delegate_.reset(delegate);
48690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
48790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
48890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void ExtensionAppShimHandler::Observe(
48990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    int type,
49090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const content::NotificationSource& source,
49190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    const content::NotificationDetails& details) {
49290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  Profile* profile = content::Source<Profile>(source).ptr();
493eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (profile->IsOffTheRecord())
494eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return;
495eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
49690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  switch (type) {
497eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case chrome::NOTIFICATION_PROFILE_CREATED: {
498eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      AppLifetimeMonitorFactory::GetForProfile(profile)->AddObserver(this);
499eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      break;
500eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
501eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    case chrome::NOTIFICATION_PROFILE_DESTROYED: {
502eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      AppLifetimeMonitorFactory::GetForProfile(profile)->RemoveObserver(this);
503eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      // Shut down every shim associated with this profile.
504eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      for (HostMap::iterator it = hosts_.begin(); it != hosts_.end(); ) {
505eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        // Increment the iterator first as OnAppClosed may call back to
506eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        // OnShimClose and invalidate the iterator.
507eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        HostMap::iterator current = it++;
5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        if (profile->IsSameProfile(current->first.first)) {
5095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          Host* host = current->second;
5105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          host->OnAppClosed();
5115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        }
512eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      }
513868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
514eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
515eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    default: {
51690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      NOTREACHED();  // Unexpected notification.
51790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      break;
518eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
51990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
52090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
52190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
522eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::OnAppStart(Profile* profile,
523eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                         const std::string& app_id) {}
524eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
525eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::OnAppActivated(Profile* profile,
526eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                             const std::string& app_id) {
527eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  const extensions::Extension* extension =
528eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      delegate_->GetAppExtension(profile, app_id);
529eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (!extension)
530868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
531868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
532a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  Host* host = FindHost(profile, app_id);
533a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (host) {
534a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    host->OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS);
53558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    OnShimFocus(host, APP_SHIM_FOCUS_NORMAL, std::vector<base::FilePath>());
536868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
5377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  }
538868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
539eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  delegate_->LaunchShim(profile, extension);
540868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
541868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
542eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::OnAppDeactivated(Profile* profile,
543424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                               const std::string& app_id) {
544424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  Host* host = FindHost(profile, app_id);
545424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (host)
546424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    host->OnAppClosed();
547424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
5484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (hosts_.empty())
549424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    delegate_->MaybeTerminate();
550424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
551eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
552eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::OnAppStop(Profile* profile,
553eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                        const std::string& app_id) {}
554eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
555eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid ExtensionAppShimHandler::OnChromeTerminating() {}
55690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
55790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace apps
558