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

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

Issue 790043002: Hosted apps on OS X now act more like a native app. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@creating-app-shims-2
Patch Set: Linting and formatting Created 6 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
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 "chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h" 5 #include "chrome/browser/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/launcher.h" 8 #include "apps/launcher.h"
9 #include "base/files/file_path.h" 9 #include "base/files/file_path.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "chrome/browser/apps/app_shim/app_shim_host_manager_mac.h" 11 #include "chrome/browser/apps/app_shim/app_shim_host_manager_mac.h"
12 #include "chrome/browser/browser_process.h" 12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/chrome_notification_types.h" 13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/extensions/launch_util.h"
14 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/profiles/profile_manager.h" 16 #include "chrome/browser/profiles/profile_manager.h"
17 #include "chrome/browser/ui/browser_list.h"
18 #include "chrome/browser/ui/browser_window.h"
16 #include "chrome/browser/ui/extensions/application_launch.h" 19 #include "chrome/browser/ui/extensions/application_launch.h"
17 #include "chrome/browser/ui/extensions/extension_enable_flow.h" 20 #include "chrome/browser/ui/extensions/extension_enable_flow.h"
18 #include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h" 21 #include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
19 #include "chrome/browser/web_applications/web_app_mac.h" 22 #include "chrome/browser/web_applications/web_app_mac.h"
20 #include "chrome/common/extensions/extension_constants.h" 23 #include "chrome/common/extensions/extension_constants.h"
21 #include "chrome/common/extensions/extension_metrics.h" 24 #include "chrome/common/extensions/extension_metrics.h"
22 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" 25 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
23 #include "chrome/common/mac/app_shim_messages.h" 26 #include "chrome/common/mac/app_shim_messages.h"
24 #include "components/crx_file/id_util.h" 27 #include "components/crx_file/id_util.h"
25 #include "content/public/browser/notification_details.h" 28 #include "content/public/browser/notification_details.h"
26 #include "content/public/browser/notification_service.h" 29 #include "content/public/browser/notification_service.h"
27 #include "content/public/browser/notification_source.h" 30 #include "content/public/browser/notification_source.h"
28 #include "extensions/browser/app_window/app_window.h" 31 #include "extensions/browser/app_window/app_window.h"
29 #include "extensions/browser/app_window/app_window_registry.h" 32 #include "extensions/browser/app_window/app_window_registry.h"
30 #include "extensions/browser/app_window/native_app_window.h" 33 #include "extensions/browser/app_window/native_app_window.h"
31 #include "extensions/browser/extension_host.h" 34 #include "extensions/browser/extension_host.h"
35 #include "extensions/browser/extension_prefs.h"
32 #include "extensions/browser/extension_registry.h" 36 #include "extensions/browser/extension_registry.h"
33 #include "extensions/common/constants.h" 37 #include "extensions/common/constants.h"
34 #include "ui/base/cocoa/focus_window_set.h" 38 #include "ui/base/cocoa/focus_window_set.h"
35 39
36 using extensions::AppWindow; 40 using extensions::AppWindow;
37 using extensions::AppWindowRegistry; 41 using extensions::AppWindowRegistry;
38 using extensions::ExtensionRegistry; 42 using extensions::ExtensionRegistry;
39 43
40 namespace { 44 namespace {
41 45
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 ++it) { 79 ++it) {
76 native_windows.insert((*it)->GetNativeWindow()); 80 native_windows.insert((*it)->GetNativeWindow());
77 } 81 }
78 // Allow workspace switching. For the browser process, we can reasonably rely 82 // Allow workspace switching. For the browser process, we can reasonably rely
79 // on OS X to switch spaces for us and honor relevant user settings. But shims 83 // on OS X to switch spaces for us and honor relevant user settings. But shims
80 // don't have windows, so we have to do it ourselves. 84 // don't have windows, so we have to do it ourselves.
81 ui::FocusWindowSet(native_windows); 85 ui::FocusWindowSet(native_windows);
82 return true; 86 return true;
83 } 87 }
84 88
89 bool FocusHostedAppWindows(std::set<Browser*>& browsers) {
90 if (browsers.empty())
91 return false;
92
93 std::set<gfx::NativeWindow> native_windows;
94 for (const Browser* browser : browsers)
95 native_windows.insert(browser->window()->GetNativeWindow());
96
97 ui::FocusWindowSet(native_windows);
98 return true;
99 }
100
85 // Attempts to launch a packaged app, prompting the user to enable it if 101 // Attempts to launch a packaged app, prompting the user to enable it if
86 // necessary. The prompt is shown in its own window. 102 // necessary. The prompt is shown in its own window.
87 // This class manages its own lifetime. 103 // This class manages its own lifetime.
88 class EnableViaPrompt : public ExtensionEnableFlowDelegate { 104 class EnableViaPrompt : public ExtensionEnableFlowDelegate {
89 public: 105 public:
90 EnableViaPrompt(Profile* profile, 106 EnableViaPrompt(Profile* profile,
91 const std::string& extension_id, 107 const std::string& extension_id,
92 const base::Callback<void()>& callback) 108 const base::Callback<void()>& callback)
93 : profile_(profile), 109 : profile_(profile),
94 extension_id_(extension_id), 110 extension_id_(extension_id),
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 AppWindowList ExtensionAppShimHandler::Delegate::GetWindows( 177 AppWindowList ExtensionAppShimHandler::Delegate::GetWindows(
162 Profile* profile, 178 Profile* profile,
163 const std::string& extension_id) { 179 const std::string& extension_id) {
164 return AppWindowRegistry::Get(profile)->GetAppWindowsForApp(extension_id); 180 return AppWindowRegistry::Get(profile)->GetAppWindowsForApp(extension_id);
165 } 181 }
166 182
167 const extensions::Extension* 183 const extensions::Extension*
168 ExtensionAppShimHandler::Delegate::GetAppExtension( 184 ExtensionAppShimHandler::Delegate::GetAppExtension(
169 Profile* profile, 185 Profile* profile,
170 const std::string& extension_id) { 186 const std::string& extension_id) {
171 ExtensionRegistry* registry = ExtensionRegistry::Get(profile); 187 return ExtensionAppShimHandler::GetAppExtension(profile, extension_id);
172 const extensions::Extension* extension =
173 registry->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
174 return extension &&
175 (extension->is_platform_app() || extension->is_hosted_app())
176 ? extension
177 : NULL;
178 } 188 }
179 189
180 void ExtensionAppShimHandler::Delegate::EnableExtension( 190 void ExtensionAppShimHandler::Delegate::EnableExtension(
181 Profile* profile, 191 Profile* profile,
182 const std::string& extension_id, 192 const std::string& extension_id,
183 const base::Callback<void()>& callback) { 193 const base::Callback<void()>& callback) {
184 (new EnableViaPrompt(profile, extension_id, callback))->Run(); 194 (new EnableViaPrompt(profile, extension_id, callback))->Run();
185 } 195 }
186 196
187 void ExtensionAppShimHandler::Delegate::LaunchApp( 197 void ExtensionAppShimHandler::Delegate::LaunchApp(
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
222 : delegate_(new Delegate), 232 : delegate_(new Delegate),
223 weak_factory_(this) { 233 weak_factory_(this) {
224 // This is instantiated in BrowserProcessImpl::PreMainMessageLoopRun with 234 // This is instantiated in BrowserProcessImpl::PreMainMessageLoopRun with
225 // AppShimHostManager. Since PROFILE_CREATED is not fired until 235 // AppShimHostManager. Since PROFILE_CREATED is not fired until
226 // ProfileManager::GetLastUsedProfile/GetLastOpenedProfiles, this should catch 236 // ProfileManager::GetLastUsedProfile/GetLastOpenedProfiles, this should catch
227 // notifications for all profiles. 237 // notifications for all profiles.
228 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, 238 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED,
229 content::NotificationService::AllBrowserContextsAndSources()); 239 content::NotificationService::AllBrowserContextsAndSources());
230 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, 240 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
231 content::NotificationService::AllBrowserContextsAndSources()); 241 content::NotificationService::AllBrowserContextsAndSources());
242 registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
243 content::NotificationService::AllBrowserContextsAndSources());
244 BrowserList::AddObserver(this);
232 } 245 }
233 246
234 ExtensionAppShimHandler::~ExtensionAppShimHandler() {} 247 ExtensionAppShimHandler::~ExtensionAppShimHandler() {
248 BrowserList::RemoveObserver(this);
249 }
235 250
236 AppShimHandler::Host* ExtensionAppShimHandler::FindHost( 251 AppShimHandler::Host* ExtensionAppShimHandler::FindHost(
237 Profile* profile, 252 Profile* profile,
238 const std::string& app_id) { 253 const std::string& app_id) {
239 HostMap::iterator it = hosts_.find(make_pair(profile, app_id)); 254 HostMap::iterator it = hosts_.find(make_pair(profile, app_id));
240 return it == hosts_.end() ? NULL : it->second; 255 return it == hosts_.end() ? NULL : it->second;
241 } 256 }
242 257
258 void ExtensionAppShimHandler::SetHostedAppHidden(Profile* profile,
259 const std::string& app_id,
260 bool hidden) {
261 const AppBrowserMap::iterator it = app_browser_windows_.find(app_id);
262 if (it == app_browser_windows_.end())
263 return;
264
265 for (const Browser* browser : it->second) {
266 if (web_app::GetExtensionIdFromApplicationName(browser->app_name()) !=
267 app_id) {
268 continue;
269 }
270
271 if (hidden)
272 browser->window()->Hide();
273 else
274 browser->window()->Show();
275 }
276 }
277
278 // static
279 const extensions::Extension* ExtensionAppShimHandler::GetAppExtension(
280 Profile* profile,
281 const std::string& extension_id) {
282 if (!profile)
283 return NULL;
284
285 ExtensionRegistry* registry = ExtensionRegistry::Get(profile);
286 const extensions::Extension* extension =
287 registry->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
288 return extension &&
289 (extension->is_platform_app() || extension->is_hosted_app())
290 ? extension
291 : NULL;
292 }
293
294 // static
295 const extensions::Extension* ExtensionAppShimHandler::GetAppForBrowser(
296 Browser* browser) {
297 if (!browser || !browser->is_app())
298 return NULL;
299
300 return GetAppExtension(
301 browser->profile(),
302 web_app::GetExtensionIdFromApplicationName(browser->app_name()));
303 }
304
243 // static 305 // static
244 void ExtensionAppShimHandler::QuitAppForWindow(AppWindow* app_window) { 306 void ExtensionAppShimHandler::QuitAppForWindow(AppWindow* app_window) {
245 ExtensionAppShimHandler* handler = GetInstance(); 307 ExtensionAppShimHandler* handler = GetInstance();
246 Host* host = handler->FindHost( 308 Host* host = handler->FindHost(
247 Profile::FromBrowserContext(app_window->browser_context()), 309 Profile::FromBrowserContext(app_window->browser_context()),
248 app_window->extension_id()); 310 app_window->extension_id());
249 if (host) { 311 if (host) {
250 handler->OnShimQuit(host); 312 handler->OnShimQuit(host);
251 } else { 313 } else {
252 // App shims might be disabled or the shim is still starting up. 314 // App shims might be disabled or the shim is still starting up.
253 AppWindowRegistry::Get( 315 AppWindowRegistry::Get(
254 Profile::FromBrowserContext(app_window->browser_context())) 316 Profile::FromBrowserContext(app_window->browser_context()))
255 ->CloseAllAppWindowsForApp(app_window->extension_id()); 317 ->CloseAllAppWindowsForApp(app_window->extension_id());
256 } 318 }
257 } 319 }
258 320
321 // static
322 void ExtensionAppShimHandler::QuitHostedAppForWindow(
323 Profile* profile,
324 const std::string& app_id) {
325 ExtensionAppShimHandler* handler = GetInstance();
326 Host* host = handler->FindHost(Profile::FromBrowserContext(profile), app_id);
327 if (host)
328 handler->OnShimQuit(host);
329 else
330 handler->CloseBrowsersForApp(app_id);
331 }
332
259 void ExtensionAppShimHandler::HideAppForWindow(AppWindow* app_window) { 333 void ExtensionAppShimHandler::HideAppForWindow(AppWindow* app_window) {
260 ExtensionAppShimHandler* handler = GetInstance(); 334 ExtensionAppShimHandler* handler = GetInstance();
261 Profile* profile = Profile::FromBrowserContext(app_window->browser_context()); 335 Profile* profile = Profile::FromBrowserContext(app_window->browser_context());
262 Host* host = handler->FindHost(profile, app_window->extension_id()); 336 Host* host = handler->FindHost(profile, app_window->extension_id());
263 if (host) 337 if (host)
264 host->OnAppHide(); 338 host->OnAppHide();
265 else 339 else
266 SetAppHidden(profile, app_window->extension_id(), true); 340 SetAppHidden(profile, app_window->extension_id(), true);
267 } 341 }
268 342
343 void ExtensionAppShimHandler::HideHostedApp(Profile* profile,
344 const std::string& app_id) {
345 ExtensionAppShimHandler* handler = GetInstance();
346 Host* host = handler->FindHost(profile, app_id);
347 if (host)
348 host->OnAppHide();
349 else
350 handler->SetHostedAppHidden(profile, app_id, true);
351 }
352
269 void ExtensionAppShimHandler::FocusAppForWindow(AppWindow* app_window) { 353 void ExtensionAppShimHandler::FocusAppForWindow(AppWindow* app_window) {
270 ExtensionAppShimHandler* handler = GetInstance(); 354 ExtensionAppShimHandler* handler = GetInstance();
271 Profile* profile = Profile::FromBrowserContext(app_window->browser_context()); 355 Profile* profile = Profile::FromBrowserContext(app_window->browser_context());
272 const std::string& app_id = app_window->extension_id(); 356 const std::string& app_id = app_window->extension_id();
273 Host* host = handler->FindHost(profile, app_id); 357 Host* host = handler->FindHost(profile, app_id);
274 if (host) { 358 if (host) {
275 handler->OnShimFocus(host, 359 handler->OnShimFocus(host,
276 APP_SHIM_FOCUS_NORMAL, 360 APP_SHIM_FOCUS_NORMAL,
277 std::vector<base::FilePath>()); 361 std::vector<base::FilePath>());
278 } else { 362 } else {
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 // Return now. OnAppLaunchComplete will be called when the app is activated. 445 // Return now. OnAppLaunchComplete will be called when the app is activated.
362 } 446 }
363 447
364 // static 448 // static
365 ExtensionAppShimHandler* ExtensionAppShimHandler::GetInstance() { 449 ExtensionAppShimHandler* ExtensionAppShimHandler::GetInstance() {
366 return g_browser_process->platform_part() 450 return g_browser_process->platform_part()
367 ->app_shim_host_manager() 451 ->app_shim_host_manager()
368 ->extension_app_shim_handler(); 452 ->extension_app_shim_handler();
369 } 453 }
370 454
455 void ExtensionAppShimHandler::CloseBrowsersForApp(const std::string& app_id) {
456 AppBrowserMap::iterator it = app_browser_windows_.find(app_id);
457 if (it == app_browser_windows_.end())
458 return;
459
460 for (const Browser* browser : it->second)
461 browser->window()->Close();
462 }
463
371 void ExtensionAppShimHandler::OnProfileLoaded( 464 void ExtensionAppShimHandler::OnProfileLoaded(
372 Host* host, 465 Host* host,
373 AppShimLaunchType launch_type, 466 AppShimLaunchType launch_type,
374 const std::vector<base::FilePath>& files, 467 const std::vector<base::FilePath>& files,
375 Profile* profile) { 468 Profile* profile) {
376 const std::string& app_id = host->GetAppId(); 469 const std::string& app_id = host->GetAppId();
377 470
378 // The first host to claim this (profile, app_id) becomes the main host. 471 // The first host to claim this (profile, app_id) becomes the main host.
379 // For any others, focus or relaunch the app. 472 // For any others, focus or relaunch the app.
380 if (!hosts_.insert(make_pair(make_pair(profile, app_id), host)).second) { 473 if (!hosts_.insert(make_pair(make_pair(profile, app_id), host)).second) {
(...skipping 11 matching lines...) Expand all
392 } 485 }
393 486
394 // TODO(jeremya): Handle the case that launching the app fails. Probably we 487 // TODO(jeremya): Handle the case that launching the app fails. Probably we
395 // need to watch for 'app successfully launched' or at least 'background page 488 // need to watch for 'app successfully launched' or at least 'background page
396 // exists/was created' and time out with failure if we don't see that sign of 489 // exists/was created' and time out with failure if we don't see that sign of
397 // life within a certain window. 490 // life within a certain window.
398 const extensions::Extension* extension = 491 const extensions::Extension* extension =
399 delegate_->GetAppExtension(profile, app_id); 492 delegate_->GetAppExtension(profile, app_id);
400 if (extension) { 493 if (extension) {
401 delegate_->LaunchApp(profile, extension, files); 494 delegate_->LaunchApp(profile, extension, files);
402 // If it's a hosted app, just kill it immediately after opening for now. 495 // If it's a hosted app that opens in a tab, let the shim terminate
403 if (extension->is_hosted_app()) 496 // immediately.
497 if (extension->is_hosted_app() &&
498 extensions::GetLaunchType(extensions::ExtensionPrefs::Get(profile),
499 extension) ==
500 extensions::LAUNCH_TYPE_REGULAR) {
404 host->OnAppLaunchComplete(APP_SHIM_LAUNCH_DUPLICATE_HOST); 501 host->OnAppLaunchComplete(APP_SHIM_LAUNCH_DUPLICATE_HOST);
502 }
405 return; 503 return;
406 } 504 }
407 505
408 delegate_->EnableExtension( 506 delegate_->EnableExtension(
409 profile, app_id, 507 profile, app_id,
410 base::Bind(&ExtensionAppShimHandler::OnExtensionEnabled, 508 base::Bind(&ExtensionAppShimHandler::OnExtensionEnabled,
411 weak_factory_.GetWeakPtr(), 509 weak_factory_.GetWeakPtr(),
412 host->GetProfilePath(), app_id, files)); 510 host->GetProfilePath(), app_id, files));
413 } 511 }
414 512
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 } 545 }
448 } 546 }
449 547
450 void ExtensionAppShimHandler::OnShimFocus( 548 void ExtensionAppShimHandler::OnShimFocus(
451 Host* host, 549 Host* host,
452 AppShimFocusType focus_type, 550 AppShimFocusType focus_type,
453 const std::vector<base::FilePath>& files) { 551 const std::vector<base::FilePath>& files) {
454 DCHECK(delegate_->ProfileExistsForPath(host->GetProfilePath())); 552 DCHECK(delegate_->ProfileExistsForPath(host->GetProfilePath()));
455 Profile* profile = delegate_->ProfileForPath(host->GetProfilePath()); 553 Profile* profile = delegate_->ProfileForPath(host->GetProfilePath());
456 554
457 const AppWindowList windows = 555 bool windows_focused;
458 delegate_->GetWindows(profile, host->GetAppId()); 556 const std::string& app_id = host->GetAppId();
459 bool windows_focused = FocusWindows(windows); 557 if (delegate_->GetAppExtension(profile, app_id)->is_hosted_app()) {
558 AppBrowserMap::iterator it = app_browser_windows_.find(app_id);
559 if (it == app_browser_windows_.end())
560 return;
561
562 windows_focused = FocusHostedAppWindows(it->second);
563 } else {
564 const AppWindowList windows =
565 delegate_->GetWindows(profile, host->GetAppId());
566 windows_focused = FocusWindows(windows);
567 }
460 568
461 if (focus_type == APP_SHIM_FOCUS_NORMAL || 569 if (focus_type == APP_SHIM_FOCUS_NORMAL ||
462 (focus_type == APP_SHIM_FOCUS_REOPEN && windows_focused)) { 570 (focus_type == APP_SHIM_FOCUS_REOPEN && windows_focused)) {
463 return; 571 return;
464 } 572 }
465 573
466 const extensions::Extension* extension = 574 const extensions::Extension* extension =
467 delegate_->GetAppExtension(profile, host->GetAppId()); 575 delegate_->GetAppExtension(profile, host->GetAppId());
468 if (extension) { 576 if (extension) {
469 delegate_->LaunchApp(profile, extension, files); 577 delegate_->LaunchApp(profile, extension, files);
470 } else { 578 } else {
471 // Extensions may have been uninstalled or disabled since the shim 579 // Extensions may have been uninstalled or disabled since the shim
472 // started. 580 // started.
473 host->OnAppClosed(); 581 host->OnAppClosed();
474 } 582 }
475 } 583 }
476 584
477 void ExtensionAppShimHandler::OnShimSetHidden(Host* host, bool hidden) { 585 void ExtensionAppShimHandler::OnShimSetHidden(Host* host, bool hidden) {
478 DCHECK(delegate_->ProfileExistsForPath(host->GetProfilePath())); 586 DCHECK(delegate_->ProfileExistsForPath(host->GetProfilePath()));
479 Profile* profile = delegate_->ProfileForPath(host->GetProfilePath()); 587 Profile* profile = delegate_->ProfileForPath(host->GetProfilePath());
480 588
481 SetAppHidden(profile, host->GetAppId(), hidden); 589 const std::string& app_id = host->GetAppId();
590 if (delegate_->GetAppExtension(profile, app_id)->is_hosted_app())
591 SetHostedAppHidden(profile, app_id, hidden);
592 else
593 SetAppHidden(profile, app_id, hidden);
482 } 594 }
483 595
484 void ExtensionAppShimHandler::OnShimQuit(Host* host) { 596 void ExtensionAppShimHandler::OnShimQuit(Host* host) {
485 DCHECK(delegate_->ProfileExistsForPath(host->GetProfilePath())); 597 DCHECK(delegate_->ProfileExistsForPath(host->GetProfilePath()));
486 Profile* profile = delegate_->ProfileForPath(host->GetProfilePath()); 598 Profile* profile = delegate_->ProfileForPath(host->GetProfilePath());
487 599
488 const std::string& app_id = host->GetAppId(); 600 const std::string& app_id = host->GetAppId();
489 const AppWindowList windows = delegate_->GetWindows(profile, app_id); 601 if (delegate_->GetAppExtension(profile, app_id)->is_hosted_app())
490 for (AppWindowRegistry::const_iterator it = windows.begin(); 602 CloseBrowsersForApp(app_id);
491 it != windows.end(); 603 else {
492 ++it) { 604 const AppWindowList windows = delegate_->GetWindows(profile, app_id);
493 (*it)->GetBaseWindow()->Close(); 605 for (AppWindowRegistry::const_iterator it = windows.begin();
606 it != windows.end(); ++it) {
607 (*it)->GetBaseWindow()->Close();
608 }
494 } 609 }
495 // Once the last window closes, flow will end up in OnAppDeactivated via 610 // Once the last window closes, flow will end up in OnAppDeactivated via
496 // AppLifetimeMonitor. 611 // AppLifetimeMonitor.
612 // Otherwise, once the last window closes for a hosted app, OnBrowserRemoved
613 // will call OnAppDeactivated.
497 } 614 }
498 615
499 void ExtensionAppShimHandler::set_delegate(Delegate* delegate) { 616 void ExtensionAppShimHandler::set_delegate(Delegate* delegate) {
500 delegate_.reset(delegate); 617 delegate_.reset(delegate);
501 } 618 }
502 619
503 void ExtensionAppShimHandler::Observe( 620 void ExtensionAppShimHandler::Observe(
504 int type, 621 int type,
505 const content::NotificationSource& source, 622 const content::NotificationSource& source,
506 const content::NotificationDetails& details) { 623 const content::NotificationDetails& details) {
507 Profile* profile = content::Source<Profile>(source).ptr();
508 if (profile->IsOffTheRecord())
509 return;
510
511 switch (type) { 624 switch (type) {
512 case chrome::NOTIFICATION_PROFILE_CREATED: { 625 case chrome::NOTIFICATION_PROFILE_CREATED: {
626 Profile* profile = content::Source<Profile>(source).ptr();
627 if (profile->IsOffTheRecord())
628 return;
629
513 AppLifetimeMonitorFactory::GetForProfile(profile)->AddObserver(this); 630 AppLifetimeMonitorFactory::GetForProfile(profile)->AddObserver(this);
514 break; 631 break;
515 } 632 }
516 case chrome::NOTIFICATION_PROFILE_DESTROYED: { 633 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
634 Profile* profile = content::Source<Profile>(source).ptr();
635 if (profile->IsOffTheRecord())
636 return;
637
517 AppLifetimeMonitorFactory::GetForProfile(profile)->RemoveObserver(this); 638 AppLifetimeMonitorFactory::GetForProfile(profile)->RemoveObserver(this);
518 // Shut down every shim associated with this profile. 639 // Shut down every shim associated with this profile.
519 for (HostMap::iterator it = hosts_.begin(); it != hosts_.end(); ) { 640 for (HostMap::iterator it = hosts_.begin(); it != hosts_.end(); ) {
520 // Increment the iterator first as OnAppClosed may call back to 641 // Increment the iterator first as OnAppClosed may call back to
521 // OnShimClose and invalidate the iterator. 642 // OnShimClose and invalidate the iterator.
522 HostMap::iterator current = it++; 643 HostMap::iterator current = it++;
523 if (profile->IsSameProfile(current->first.first)) { 644 if (profile->IsSameProfile(current->first.first)) {
524 Host* host = current->second; 645 Host* host = current->second;
525 host->OnAppClosed(); 646 host->OnAppClosed();
526 } 647 }
527 } 648 }
528 break; 649 break;
529 } 650 }
651 case chrome::NOTIFICATION_BROWSER_WINDOW_READY: {
652 Browser* browser = content::Source<Browser>(source).ptr();
653 // Don't keep track of browsers that are not associated with an app.
654 const extensions::Extension* extension = GetAppForBrowser(browser);
655 if (!extension)
656 return;
657
658 BrowserSet& browsers = app_browser_windows_[extension->id()];
659 browsers.insert(browser);
660 if (browsers.size() == 1)
661 OnAppActivated(browser->profile(), extension->id());
662
663 break;
664 }
530 default: { 665 default: {
531 NOTREACHED(); // Unexpected notification. 666 NOTREACHED(); // Unexpected notification.
532 break; 667 break;
533 } 668 }
534 } 669 }
535 } 670 }
536 671
537 void ExtensionAppShimHandler::OnAppStart(Profile* profile, 672 void ExtensionAppShimHandler::OnAppStart(Profile* profile,
538 const std::string& app_id) {} 673 const std::string& app_id) {}
539 674
(...skipping 22 matching lines...) Expand all
562 697
563 if (hosts_.empty()) 698 if (hosts_.empty())
564 delegate_->MaybeTerminate(); 699 delegate_->MaybeTerminate();
565 } 700 }
566 701
567 void ExtensionAppShimHandler::OnAppStop(Profile* profile, 702 void ExtensionAppShimHandler::OnAppStop(Profile* profile,
568 const std::string& app_id) {} 703 const std::string& app_id) {}
569 704
570 void ExtensionAppShimHandler::OnChromeTerminating() {} 705 void ExtensionAppShimHandler::OnChromeTerminating() {}
571 706
707 // The BrowserWindow may be NULL when this is called.
708 // Therefore we listen for the notification
709 // chrome::NOTIFICATION_BROWSER_WINDOW_READY and then call OnAppActivated.
710 // If this notification is removed, check that OnBrowserAdded is called after
711 // the BrowserWindow is ready.
712 void ExtensionAppShimHandler::OnBrowserAdded(Browser* browser) {
713 }
714
715 void ExtensionAppShimHandler::OnBrowserRemoved(Browser* browser) {
716 const extensions::Extension* extension = GetAppForBrowser(browser);
717 if (!extension)
718 return;
719
720 AppBrowserMap::iterator it = app_browser_windows_.find(extension->id());
721 if (it != app_browser_windows_.end()) {
722 BrowserSet& browsers = it->second;
723 browsers.erase(browser);
724 if (browsers.empty())
725 OnAppDeactivated(browser->profile(), extension->id());
726 }
727 }
728
572 } // namespace apps 729 } // namespace apps
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698