Add ability to gather metrics to BubbleManager.
[chromium-blink-merge.git] / chrome / browser / ui / browser_list.cc
blob3057802817646bce2d538c1688e48128842cf3da
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/ui/browser_list.h"
7 #include <algorithm>
9 #include "base/auto_reset.h"
10 #include "base/logging.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/browser_shutdown.h"
13 #include "chrome/browser/chrome_notification_types.h"
14 #include "chrome/browser/lifetime/application_lifetime.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_finder.h"
18 #include "chrome/browser/ui/browser_iterator.h"
19 #include "chrome/browser/ui/browser_list_observer.h"
20 #include "chrome/browser/ui/browser_window.h"
21 #include "chrome/browser/ui/host_desktop.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/browser/user_metrics.h"
25 using base::UserMetricsAction;
26 using content::WebContents;
28 // static
29 base::LazyInstance<base::ObserverList<chrome::BrowserListObserver>>::Leaky
30 BrowserList::observers_ = LAZY_INSTANCE_INITIALIZER;
32 // static
33 BrowserList* BrowserList::native_instance_ = NULL;
34 BrowserList* BrowserList::ash_instance_ = NULL;
36 ////////////////////////////////////////////////////////////////////////////////
37 // BrowserList, public:
39 Browser* BrowserList::GetLastActive() const {
40 if (!last_active_browsers_.empty())
41 return *(last_active_browsers_.rbegin());
42 return NULL;
45 // static
46 BrowserList* BrowserList::GetInstance(chrome::HostDesktopType type) {
47 BrowserList** list = NULL;
48 if (type == chrome::HOST_DESKTOP_TYPE_NATIVE)
49 list = &native_instance_;
50 else if (type == chrome::HOST_DESKTOP_TYPE_ASH)
51 list = &ash_instance_;
52 else
53 NOTREACHED();
54 if (!*list)
55 *list = new BrowserList;
56 return *list;
59 // static
60 void BrowserList::AddBrowser(Browser* browser) {
61 DCHECK(browser);
62 // Push |browser| on the appropriate list instance.
63 BrowserList* browser_list = GetInstance(browser->host_desktop_type());
64 browser_list->browsers_.push_back(browser);
66 g_browser_process->AddRefModule();
68 content::NotificationService::current()->Notify(
69 chrome::NOTIFICATION_BROWSER_OPENED,
70 content::Source<Browser>(browser),
71 content::NotificationService::NoDetails());
73 FOR_EACH_OBSERVER(chrome::BrowserListObserver, observers_.Get(),
74 OnBrowserAdded(browser));
77 // static
78 void BrowserList::RemoveBrowser(Browser* browser) {
79 // Remove |browser| from the appropriate list instance.
80 BrowserList* browser_list = GetInstance(browser->host_desktop_type());
81 RemoveBrowserFrom(browser, &browser_list->last_active_browsers_);
83 content::NotificationService::current()->Notify(
84 chrome::NOTIFICATION_BROWSER_CLOSED,
85 content::Source<Browser>(browser),
86 content::NotificationService::NoDetails());
88 RemoveBrowserFrom(browser, &browser_list->browsers_);
90 FOR_EACH_OBSERVER(chrome::BrowserListObserver, observers_.Get(),
91 OnBrowserRemoved(browser));
93 g_browser_process->ReleaseModule();
95 // If we're exiting, send out the APP_TERMINATING notification to allow other
96 // modules to shut themselves down.
97 if (chrome::GetTotalBrowserCount() == 0 &&
98 (browser_shutdown::IsTryingToQuit() ||
99 g_browser_process->IsShuttingDown())) {
100 // Last browser has just closed, and this is a user-initiated quit or there
101 // is no module keeping the app alive, so send out our notification. No need
102 // to call ProfileManager::ShutdownSessionServices() as part of the
103 // shutdown, because Browser::WindowClosing() already makes sure that the
104 // SessionService is created and notified.
105 chrome::NotifyAppTerminating();
106 chrome::OnAppExiting();
110 // static
111 void BrowserList::AddObserver(chrome::BrowserListObserver* observer) {
112 observers_.Get().AddObserver(observer);
115 // static
116 void BrowserList::RemoveObserver(chrome::BrowserListObserver* observer) {
117 observers_.Get().RemoveObserver(observer);
120 // static
121 void BrowserList::CloseAllBrowsersWithProfile(Profile* profile) {
122 BrowserVector browsers_to_close;
123 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
124 if (it->profile()->GetOriginalProfile() == profile->GetOriginalProfile())
125 browsers_to_close.push_back(*it);
128 for (BrowserVector::const_iterator it = browsers_to_close.begin();
129 it != browsers_to_close.end(); ++it) {
130 (*it)->window()->Close();
134 // static
135 void BrowserList::CloseAllBrowsersWithProfile(Profile* profile,
136 const base::Callback<void(const base::FilePath&)>& on_close_success) {
137 BrowserVector browsers_to_close;
138 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
139 if (it->profile()->GetOriginalProfile() == profile->GetOriginalProfile())
140 browsers_to_close.push_back(*it);
143 TryToCloseBrowserList(browsers_to_close,
144 on_close_success,
145 profile->GetPath());
148 // static
149 void BrowserList::TryToCloseBrowserList(const BrowserVector& browsers_to_close,
150 const base::Callback<void(const base::FilePath&)>& on_close_success,
151 const base::FilePath& profile_path) {
152 for (BrowserVector::const_iterator it = browsers_to_close.begin();
153 it != browsers_to_close.end(); ++it) {
154 if ((*it)->CallBeforeUnloadHandlers(
155 base::Bind(&BrowserList::PostBeforeUnloadHandlers,
156 browsers_to_close,
157 on_close_success,
158 profile_path))) {
159 return;
163 on_close_success.Run(profile_path);
165 for (Browser* b : browsers_to_close) {
166 // BeforeUnload handlers may close browser windows, so we need to explicitly
167 // check whether they still exist.
168 if (b->window())
169 b->window()->Close();
173 // static
174 void BrowserList::PostBeforeUnloadHandlers(
175 const BrowserVector& browsers_to_close,
176 const base::Callback<void(const base::FilePath&)>& on_close_success,
177 const base::FilePath& profile_path,
178 bool tab_close_confirmed) {
179 // We need this bool to avoid infinite recursion when resetting the
180 // BeforeUnload handlers, since doing that will trigger calls back to this
181 // method for each affected window.
182 static bool resetting_handlers = false;
184 if (tab_close_confirmed) {
185 TryToCloseBrowserList(browsers_to_close, on_close_success, profile_path);
186 } else if (!resetting_handlers) {
187 base::AutoReset<bool> resetting_handlers_scoper(&resetting_handlers, true);
188 for (BrowserVector::const_iterator it = browsers_to_close.begin();
189 it != browsers_to_close.end(); ++it) {
190 (*it)->ResetBeforeUnloadHandlers();
195 // static
196 void BrowserList::SetLastActive(Browser* browser) {
197 content::RecordAction(UserMetricsAction("ActiveBrowserChanged"));
198 BrowserList* browser_list = GetInstance(browser->host_desktop_type());
200 RemoveBrowserFrom(browser, &browser_list->last_active_browsers_);
201 browser_list->last_active_browsers_.push_back(browser);
203 FOR_EACH_OBSERVER(chrome::BrowserListObserver, observers_.Get(),
204 OnBrowserSetLastActive(browser));
207 // static
208 bool BrowserList::IsOffTheRecordSessionActive() {
209 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
210 if (it->profile()->IsOffTheRecord())
211 return true;
213 return false;
216 // static
217 bool BrowserList::IsOffTheRecordSessionActiveForProfile(Profile* profile) {
218 for (chrome::BrowserIterator it; !it.done(); it.Next()) {
219 if (it->profile()->IsSameProfile(profile) &&
220 it->profile()->IsOffTheRecord()) {
221 return true;
224 return false;
227 ////////////////////////////////////////////////////////////////////////////////
228 // BrowserList, private:
230 BrowserList::BrowserList() {
233 BrowserList::~BrowserList() {
236 // static
237 void BrowserList::RemoveBrowserFrom(Browser* browser,
238 BrowserVector* browser_list) {
239 BrowserVector::iterator remove_browser =
240 std::find(browser_list->begin(), browser_list->end(), browser);
241 if (remove_browser != browser_list->end())
242 browser_list->erase(remove_browser);