Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(489)

Side by Side Diff: apps/app_shim/extension_app_shim_handler_mac.cc

Issue 113553002: Use ExtensionEnableFlow for shim initiated launches. (Mac) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Don't pass pointers in callback. Handle deleted app or profile. Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
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
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->GetProfilePath(), app_id, files));
318 } 373 }
319 374
375 void ExtensionAppShimHandler::OnExtensionEnabled(
376 const base::FilePath& profile_path,
377 const std::string& app_id,
378 const std::vector<base::FilePath>& files) {
379 Profile* profile = delegate_->ProfileForPath(profile_path);
380 if (!profile)
381 return;
382
383 const extensions::Extension* extension =
384 delegate_->GetAppExtension(profile, app_id);
385 if (!extension || !delegate_->ProfileExistsForPath(profile_path)) {
386 // If !extension, the extension doesn't exist, or was not re-enabled.
387 // If the profile doesn't exist, it may have been deleted during the enable
388 // prompt. In this case, NOTIFICATION_PROFILE_DESTROYED may not be fired
389 // until later, so respond to the host now.
390 Host* host = FindHost(profile, app_id);
391 if (host)
392 host->OnAppLaunchComplete(APP_SHIM_LAUNCH_APP_NOT_FOUND);
393 return;
394 }
395
396 delegate_->LaunchApp(profile, extension, files);
397 }
398
399
320 void ExtensionAppShimHandler::OnShimClose(Host* host) { 400 void ExtensionAppShimHandler::OnShimClose(Host* host) {
321 // This might be called when shutting down. Don't try to look up the profile 401 // This might be called when shutting down. Don't try to look up the profile
322 // since profile_manager might not be around. 402 // since profile_manager might not be around.
323 for (HostMap::iterator it = hosts_.begin(); it != hosts_.end(); ) { 403 for (HostMap::iterator it = hosts_.begin(); it != hosts_.end(); ) {
324 HostMap::iterator current = it++; 404 HostMap::iterator current = it++;
325 if (current->second == host) 405 if (current->second == host)
326 hosts_.erase(current); 406 hosts_.erase(current);
327 } 407 }
328 } 408 }
329 409
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
393 AppLifetimeMonitorFactory::GetForProfile(profile)->AddObserver(this); 473 AppLifetimeMonitorFactory::GetForProfile(profile)->AddObserver(this);
394 break; 474 break;
395 } 475 }
396 case chrome::NOTIFICATION_PROFILE_DESTROYED: { 476 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
397 AppLifetimeMonitorFactory::GetForProfile(profile)->RemoveObserver(this); 477 AppLifetimeMonitorFactory::GetForProfile(profile)->RemoveObserver(this);
398 // Shut down every shim associated with this profile. 478 // Shut down every shim associated with this profile.
399 for (HostMap::iterator it = hosts_.begin(); it != hosts_.end(); ) { 479 for (HostMap::iterator it = hosts_.begin(); it != hosts_.end(); ) {
400 // Increment the iterator first as OnAppClosed may call back to 480 // Increment the iterator first as OnAppClosed may call back to
401 // OnShimClose and invalidate the iterator. 481 // OnShimClose and invalidate the iterator.
402 HostMap::iterator current = it++; 482 HostMap::iterator current = it++;
403 if (profile->IsSameProfile(current->first.first)) 483 if (profile->IsSameProfile(current->first.first)) {
404 current->second->OnAppClosed(); 484 Host* host = current->second;
485 host->OnAppClosed();
486 }
405 } 487 }
406 break; 488 break;
407 } 489 }
408 default: { 490 default: {
409 NOTREACHED(); // Unexpected notification. 491 NOTREACHED(); // Unexpected notification.
410 break; 492 break;
411 } 493 }
412 } 494 }
413 } 495 }
414 496
(...skipping 26 matching lines...) Expand all
441 if (hosts_.empty()) 523 if (hosts_.empty())
442 delegate_->MaybeTerminate(); 524 delegate_->MaybeTerminate();
443 } 525 }
444 526
445 void ExtensionAppShimHandler::OnAppStop(Profile* profile, 527 void ExtensionAppShimHandler::OnAppStop(Profile* profile,
446 const std::string& app_id) {} 528 const std::string& app_id) {}
447 529
448 void ExtensionAppShimHandler::OnChromeTerminating() {} 530 void ExtensionAppShimHandler::OnChromeTerminating() {}
449 531
450 } // namespace apps 532 } // namespace apps
OLDNEW
« no previous file with comments | « apps/app_shim/extension_app_shim_handler_mac.h ('k') | apps/app_shim/extension_app_shim_handler_mac_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698