Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "apps/app_shim/extension_app_shim_handler_mac.h" | 5 #include "apps/app_shim/extension_app_shim_handler_mac.h" |
| 6 | 6 |
| 7 #include "apps/app_lifetime_monitor_factory.h" | 7 #include "apps/app_lifetime_monitor_factory.h" |
| 8 #include "apps/app_shim/app_shim_host_manager_mac.h" | 8 #include "apps/app_shim/app_shim_host_manager_mac.h" |
| 9 #include "apps/app_shim/app_shim_messages.h" | 9 #include "apps/app_shim/app_shim_messages.h" |
| 10 #include "apps/launcher.h" | 10 #include "apps/launcher.h" |
| 11 #include "apps/shell_window.h" | 11 #include "apps/shell_window.h" |
| 12 #include "apps/shell_window_registry.h" | 12 #include "apps/shell_window_registry.h" |
| 13 #include "apps/ui/native_app_window.h" | 13 #include "apps/ui/native_app_window.h" |
| 14 #include "base/files/file_path.h" | 14 #include "base/files/file_path.h" |
| 15 #include "base/logging.h" | 15 #include "base/logging.h" |
| 16 #include "chrome/browser/browser_process.h" | 16 #include "chrome/browser/browser_process.h" |
| 17 #include "chrome/browser/chrome_notification_types.h" | 17 #include "chrome/browser/chrome_notification_types.h" |
| 18 #include "chrome/browser/extensions/extension_host.h" | 18 #include "chrome/browser/extensions/extension_host.h" |
| 19 #include "chrome/browser/extensions/extension_service.h" | 19 #include "chrome/browser/extensions/extension_service.h" |
| 20 #include "chrome/browser/extensions/extension_system.h" | 20 #include "chrome/browser/extensions/extension_system.h" |
| 21 #include "chrome/browser/profiles/profile.h" | 21 #include "chrome/browser/profiles/profile.h" |
| 22 #include "chrome/browser/profiles/profile_manager.h" | 22 #include "chrome/browser/profiles/profile_manager.h" |
| 23 #include "chrome/browser/ui/extensions/extension_enable_flow.h" | |
| 24 #include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h" | |
| 23 #include "chrome/browser/ui/web_applications/web_app_ui.h" | 25 #include "chrome/browser/ui/web_applications/web_app_ui.h" |
| 24 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h" | 26 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h" |
| 25 #include "chrome/browser/web_applications/web_app_mac.h" | 27 #include "chrome/browser/web_applications/web_app_mac.h" |
| 26 #include "chrome/common/extensions/extension_constants.h" | 28 #include "chrome/common/extensions/extension_constants.h" |
| 27 #include "content/public/browser/notification_details.h" | 29 #include "content/public/browser/notification_details.h" |
| 28 #include "content/public/browser/notification_service.h" | 30 #include "content/public/browser/notification_service.h" |
| 29 #include "content/public/browser/notification_source.h" | 31 #include "content/public/browser/notification_source.h" |
| 30 #include "ui/base/cocoa/focus_window_set.h" | 32 #include "ui/base/cocoa/focus_window_set.h" |
| 31 | 33 |
| 32 namespace { | 34 namespace { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 66 it != windows.end(); ++it) { | 68 it != windows.end(); ++it) { |
| 67 native_windows.insert((*it)->GetNativeWindow()); | 69 native_windows.insert((*it)->GetNativeWindow()); |
| 68 } | 70 } |
| 69 // Allow workspace switching. For the browser process, we can reasonably rely | 71 // Allow workspace switching. For the browser process, we can reasonably rely |
| 70 // on OS X to switch spaces for us and honor relevant user settings. But shims | 72 // on OS X to switch spaces for us and honor relevant user settings. But shims |
| 71 // don't have windows, so we have to do it ourselves. | 73 // don't have windows, so we have to do it ourselves. |
| 72 ui::FocusWindowSet(native_windows, true); | 74 ui::FocusWindowSet(native_windows, true); |
| 73 return true; | 75 return true; |
| 74 } | 76 } |
| 75 | 77 |
| 78 // Attempts to launch a packaged app, prompting the user to enable it if | |
| 79 // necessary. The prompt is shown in its own window. | |
| 80 // This class manages its own lifetime. | |
| 81 class EnableViaPrompt : public ExtensionEnableFlowDelegate { | |
| 82 public: | |
| 83 EnableViaPrompt(Profile* profile, | |
| 84 const std::string& extension_id, | |
| 85 const base::Callback<void()>& callback) | |
| 86 : profile_(profile), | |
| 87 extension_id_(extension_id), | |
| 88 callback_(callback) { | |
| 89 } | |
| 90 | |
| 91 virtual ~EnableViaPrompt() { | |
| 92 } | |
| 93 | |
| 94 void Run() { | |
| 95 flow_.reset(new ExtensionEnableFlow(profile_, extension_id_, this)); | |
| 96 flow_->StartForCurrentlyNonexistentWindow( | |
| 97 base::Callback<gfx::NativeWindow(void)>()); | |
| 98 } | |
| 99 | |
| 100 private: | |
| 101 // ExtensionEnableFlowDelegate overrides. | |
| 102 virtual void ExtensionEnableFlowFinished() OVERRIDE { | |
| 103 callback_.Run(); | |
| 104 delete this; | |
| 105 } | |
| 106 | |
| 107 virtual void ExtensionEnableFlowAborted(bool user_initiated) OVERRIDE { | |
| 108 callback_.Run(); | |
| 109 delete this; | |
| 110 } | |
| 111 | |
| 112 Profile* profile_; | |
| 113 std::string extension_id_; | |
| 114 base::Callback<void()> callback_; | |
| 115 scoped_ptr<ExtensionEnableFlow> flow_; | |
| 116 | |
| 117 DISALLOW_COPY_AND_ASSIGN(EnableViaPrompt); | |
| 118 }; | |
| 119 | |
| 76 } // namespace | 120 } // namespace |
| 77 | 121 |
| 78 namespace apps { | 122 namespace apps { |
| 79 | 123 |
| 80 bool ExtensionAppShimHandler::Delegate::ProfileExistsForPath( | 124 bool ExtensionAppShimHandler::Delegate::ProfileExistsForPath( |
| 81 const base::FilePath& path) { | 125 const base::FilePath& path) { |
| 82 ProfileManager* profile_manager = g_browser_process->profile_manager(); | 126 ProfileManager* profile_manager = g_browser_process->profile_manager(); |
| 83 // Check for the profile name in the profile info cache to ensure that we | 127 // Check for the profile name in the profile info cache to ensure that we |
| 84 // never access any directory that isn't a known profile. | 128 // never access any directory that isn't a known profile. |
| 85 base::FilePath full_path = profile_manager->user_data_dir().Append(path); | 129 base::FilePath full_path = profile_manager->user_data_dir().Append(path); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 119 Profile* profile, | 163 Profile* profile, |
| 120 const std::string& extension_id) { | 164 const std::string& extension_id) { |
| 121 ExtensionService* extension_service = | 165 ExtensionService* extension_service = |
| 122 extensions::ExtensionSystem::Get(profile)->extension_service(); | 166 extensions::ExtensionSystem::Get(profile)->extension_service(); |
| 123 DCHECK(extension_service); | 167 DCHECK(extension_service); |
| 124 const extensions::Extension* extension = | 168 const extensions::Extension* extension = |
| 125 extension_service->GetExtensionById(extension_id, false); | 169 extension_service->GetExtensionById(extension_id, false); |
| 126 return extension && extension->is_platform_app() ? extension : NULL; | 170 return extension && extension->is_platform_app() ? extension : NULL; |
| 127 } | 171 } |
| 128 | 172 |
| 173 void ExtensionAppShimHandler::Delegate::EnableExtension( | |
| 174 Profile* profile, | |
| 175 const std::string& extension_id, | |
| 176 const base::Callback<void()>& callback) { | |
| 177 (new EnableViaPrompt(profile, extension_id, callback))->Run(); | |
| 178 } | |
| 179 | |
| 129 void ExtensionAppShimHandler::Delegate::LaunchApp( | 180 void ExtensionAppShimHandler::Delegate::LaunchApp( |
| 130 Profile* profile, | 181 Profile* profile, |
| 131 const extensions::Extension* extension, | 182 const extensions::Extension* extension, |
| 132 const std::vector<base::FilePath>& files) { | 183 const std::vector<base::FilePath>& files) { |
| 133 CoreAppLauncherHandler::RecordAppLaunchType( | 184 CoreAppLauncherHandler::RecordAppLaunchType( |
| 134 extension_misc::APP_LAUNCH_CMD_LINE_APP, extension->GetType()); | 185 extension_misc::APP_LAUNCH_CMD_LINE_APP, extension->GetType()); |
| 135 if (files.empty()) { | 186 if (files.empty()) { |
| 136 apps::LaunchPlatformApp(profile, extension); | 187 apps::LaunchPlatformApp(profile, extension); |
| 137 } else { | 188 } else { |
| 138 for (std::vector<base::FilePath>::const_iterator it = files.begin(); | 189 for (std::vector<base::FilePath>::const_iterator it = files.begin(); |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 279 | 330 |
| 280 // Return now. OnAppLaunchComplete will be called when the app is activated. | 331 // Return now. OnAppLaunchComplete will be called when the app is activated. |
| 281 } | 332 } |
| 282 | 333 |
| 283 void ExtensionAppShimHandler::OnProfileLoaded( | 334 void ExtensionAppShimHandler::OnProfileLoaded( |
| 284 Host* host, | 335 Host* host, |
| 285 AppShimLaunchType launch_type, | 336 AppShimLaunchType launch_type, |
| 286 const std::vector<base::FilePath>& files, | 337 const std::vector<base::FilePath>& files, |
| 287 Profile* profile) { | 338 Profile* profile) { |
| 288 const std::string& app_id = host->GetAppId(); | 339 const std::string& app_id = host->GetAppId(); |
| 289 // TODO(jackhou): Add some UI for this case and remove the LOG. | |
| 290 const extensions::Extension* extension = | |
| 291 delegate_->GetAppExtension(profile, app_id); | |
| 292 if (!extension) { | |
| 293 LOG(ERROR) << "Attempted to launch nonexistent app with id '" | |
| 294 << app_id << "'."; | |
| 295 host->OnAppLaunchComplete(APP_SHIM_LAUNCH_APP_NOT_FOUND); | |
| 296 return; | |
| 297 } | |
| 298 | 340 |
| 299 // The first host to claim this (profile, app_id) becomes the main host. | 341 // The first host to claim this (profile, app_id) becomes the main host. |
| 300 // For any others, focus or relaunch the app. | 342 // For any others, focus or relaunch the app. |
| 301 if (!hosts_.insert(make_pair(make_pair(profile, app_id), host)).second) { | 343 if (!hosts_.insert(make_pair(make_pair(profile, app_id), host)).second) { |
| 302 OnShimFocus(host, | 344 OnShimFocus(host, |
| 303 launch_type == APP_SHIM_LAUNCH_NORMAL ? | 345 launch_type == APP_SHIM_LAUNCH_NORMAL ? |
| 304 APP_SHIM_FOCUS_REOPEN : APP_SHIM_FOCUS_NORMAL, | 346 APP_SHIM_FOCUS_REOPEN : APP_SHIM_FOCUS_NORMAL, |
| 305 files); | 347 files); |
| 306 host->OnAppLaunchComplete(APP_SHIM_LAUNCH_DUPLICATE_HOST); | 348 host->OnAppLaunchComplete(APP_SHIM_LAUNCH_DUPLICATE_HOST); |
| 307 return; | 349 return; |
| 308 } | 350 } |
| 309 | 351 |
| 352 if (launch_type != APP_SHIM_LAUNCH_NORMAL) { | |
| 353 host->OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS); | |
| 354 return; | |
| 355 } | |
| 356 | |
| 310 // TODO(jeremya): Handle the case that launching the app fails. Probably we | 357 // TODO(jeremya): Handle the case that launching the app fails. Probably we |
| 311 // need to watch for 'app successfully launched' or at least 'background page | 358 // need to watch for 'app successfully launched' or at least 'background page |
| 312 // exists/was created' and time out with failure if we don't see that sign of | 359 // exists/was created' and time out with failure if we don't see that sign of |
| 313 // life within a certain window. | 360 // life within a certain window. |
| 314 if (launch_type == APP_SHIM_LAUNCH_NORMAL) | 361 const extensions::Extension* extension = |
| 362 delegate_->GetAppExtension(profile, app_id); | |
| 363 if (extension) { | |
| 315 delegate_->LaunchApp(profile, extension, files); | 364 delegate_->LaunchApp(profile, extension, files); |
| 316 else | 365 return; |
| 317 host->OnAppLaunchComplete(APP_SHIM_LAUNCH_SUCCESS); | 366 } |
| 367 | |
| 368 delegate_->EnableExtension( | |
| 369 profile, app_id, | |
| 370 base::Bind(&ExtensionAppShimHandler::OnExtensionEnabled, | |
| 371 weak_factory_.GetWeakPtr(), | |
| 372 host, profile, files)); | |
|
tapted
2013/12/12 02:41:21
profile.. might be OK. But is it safe to reference
jackhou1
2013/12/13 03:47:10
Done.
| |
| 318 } | 373 } |
| 319 | 374 |
| 375 void ExtensionAppShimHandler::OnExtensionEnabled( | |
| 376 Host* host, | |
| 377 Profile* profile, | |
| 378 const std::vector<base::FilePath>& files) { | |
| 379 const extensions::Extension* extension = | |
| 380 delegate_->GetAppExtension(profile, host->GetAppId()); | |
| 381 if (!extension) { | |
| 382 host->OnAppLaunchComplete(APP_SHIM_LAUNCH_APP_NOT_FOUND); | |
| 383 return; | |
| 384 } | |
| 385 | |
| 386 delegate_->LaunchApp(profile, extension, files); | |
| 387 } | |
| 388 | |
| 389 | |
| 320 void ExtensionAppShimHandler::OnShimClose(Host* host) { | 390 void ExtensionAppShimHandler::OnShimClose(Host* host) { |
| 321 // This might be called when shutting down. Don't try to look up the profile | 391 // This might be called when shutting down. Don't try to look up the profile |
| 322 // since profile_manager might not be around. | 392 // since profile_manager might not be around. |
| 323 for (HostMap::iterator it = hosts_.begin(); it != hosts_.end(); ) { | 393 for (HostMap::iterator it = hosts_.begin(); it != hosts_.end(); ) { |
| 324 HostMap::iterator current = it++; | 394 HostMap::iterator current = it++; |
| 325 if (current->second == host) | 395 if (current->second == host) |
| 326 hosts_.erase(current); | 396 hosts_.erase(current); |
| 327 } | 397 } |
| 328 } | 398 } |
| 329 | 399 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 441 if (hosts_.empty()) | 511 if (hosts_.empty()) |
| 442 delegate_->MaybeTerminate(); | 512 delegate_->MaybeTerminate(); |
| 443 } | 513 } |
| 444 | 514 |
| 445 void ExtensionAppShimHandler::OnAppStop(Profile* profile, | 515 void ExtensionAppShimHandler::OnAppStop(Profile* profile, |
| 446 const std::string& app_id) {} | 516 const std::string& app_id) {} |
| 447 | 517 |
| 448 void ExtensionAppShimHandler::OnChromeTerminating() {} | 518 void ExtensionAppShimHandler::OnChromeTerminating() {} |
| 449 | 519 |
| 450 } // namespace apps | 520 } // namespace apps |
| OLD | NEW |