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
3// found in the LICENSE file.
4
5#include "chrome/browser/apps/app_shim/app_shim_handler_mac.h"
6
7#include <map>
8
9#include "base/bind.h"
10#include "base/logging.h"
11#include "base/memory/singleton.h"
12#include "base/message_loop/message_loop.h"
13#include "chrome/browser/apps/app_window_registry_util.h"
14#include "chrome/browser/chrome_notification_types.h"
15#include "chrome/browser/lifetime/application_lifetime.h"
16#include "chrome/browser/ui/app_list/app_list_service.h"
17#include "content/public/browser/notification_observer.h"
18#include "content/public/browser/notification_registrar.h"
19#include "content/public/browser/notification_service.h"
20
21namespace apps {
22
23namespace {
24
25void TerminateIfNoAppWindows() {
26  bool app_windows_left =
27      AppWindowRegistryUtil::IsAppWindowRegisteredInAnyProfile(0);
28  if (!app_windows_left &&
29      !AppListService::Get(chrome::HOST_DESKTOP_TYPE_NATIVE)
30           ->IsAppListVisible()) {
31    chrome::AttemptExit();
32  }
33}
34
35class AppShimHandlerRegistry : public content::NotificationObserver {
36 public:
37  static AppShimHandlerRegistry* GetInstance() {
38    return Singleton<AppShimHandlerRegistry,
39                     LeakySingletonTraits<AppShimHandlerRegistry> >::get();
40  }
41
42  AppShimHandler* GetForAppMode(const std::string& app_mode_id) const {
43    HandlerMap::const_iterator it = handlers_.find(app_mode_id);
44    if (it != handlers_.end())
45      return it->second;
46
47    return default_handler_;
48  }
49
50  bool SetForAppMode(const std::string& app_mode_id, AppShimHandler* handler) {
51    bool inserted_or_removed = handler ?
52        handlers_.insert(HandlerMap::value_type(app_mode_id, handler)).second :
53        handlers_.erase(app_mode_id) == 1;
54    DCHECK(inserted_or_removed);
55    return inserted_or_removed;
56  }
57
58  void SetDefaultHandler(AppShimHandler* handler) {
59    DCHECK_NE(default_handler_ == NULL, handler == NULL);
60    default_handler_ = handler;
61  }
62
63  void MaybeTerminate() {
64    if (!browser_session_running_) {
65      // Post this to give AppWindows a chance to remove themselves from the
66      // registry.
67      base::MessageLoop::current()->PostTask(
68          FROM_HERE, base::Bind(&TerminateIfNoAppWindows));
69    }
70  }
71
72  bool ShouldRestoreSession() {
73    return !browser_session_running_;
74  }
75
76 private:
77  friend struct DefaultSingletonTraits<AppShimHandlerRegistry>;
78  typedef std::map<std::string, AppShimHandler*> HandlerMap;
79
80  AppShimHandlerRegistry()
81      : default_handler_(NULL),
82        browser_session_running_(false) {
83    registrar_.Add(
84        this, chrome::NOTIFICATION_BROWSER_OPENED,
85        content::NotificationService::AllBrowserContextsAndSources());
86    registrar_.Add(
87        this, chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
88        content::NotificationService::AllBrowserContextsAndSources());
89    registrar_.Add(
90        this, chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED,
91        content::NotificationService::AllBrowserContextsAndSources());
92  }
93
94  virtual ~AppShimHandlerRegistry() {}
95
96  // content::NotificationObserver override:
97  virtual void Observe(
98      int type,
99      const content::NotificationSource& source,
100      const content::NotificationDetails& details) OVERRIDE {
101    switch (type) {
102      case chrome::NOTIFICATION_BROWSER_OPENED:
103      case chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED:
104        browser_session_running_ = true;
105        break;
106      case chrome::NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST:
107        browser_session_running_ = false;
108        break;
109      default:
110        NOTREACHED();
111    }
112  }
113
114  HandlerMap handlers_;
115  AppShimHandler* default_handler_;
116  content::NotificationRegistrar registrar_;
117  bool browser_session_running_;
118
119  DISALLOW_COPY_AND_ASSIGN(AppShimHandlerRegistry);
120};
121
122}  // namespace
123
124// static
125void AppShimHandler::RegisterHandler(const std::string& app_mode_id,
126                                     AppShimHandler* handler) {
127  DCHECK(handler);
128  AppShimHandlerRegistry::GetInstance()->SetForAppMode(app_mode_id, handler);
129}
130
131// static
132void AppShimHandler::RemoveHandler(const std::string& app_mode_id) {
133  AppShimHandlerRegistry::GetInstance()->SetForAppMode(app_mode_id, NULL);
134}
135
136// static
137AppShimHandler* AppShimHandler::GetForAppMode(const std::string& app_mode_id) {
138  return AppShimHandlerRegistry::GetInstance()->GetForAppMode(app_mode_id);
139}
140
141// static
142void AppShimHandler::SetDefaultHandler(AppShimHandler* handler) {
143  AppShimHandlerRegistry::GetInstance()->SetDefaultHandler(handler);
144}
145
146// static
147void AppShimHandler::MaybeTerminate() {
148  AppShimHandlerRegistry::GetInstance()->MaybeTerminate();
149}
150
151// static
152bool AppShimHandler::ShouldRestoreSession() {
153  return AppShimHandlerRegistry::GetInstance()->ShouldRestoreSession();
154}
155
156}  // namespace apps
157