Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / ui / ash / launcher / browser_status_monitor.cc
blob0b1c506fb0082df81c356817c18cb9a9f415c043
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.
5 #include "chrome/browser/ui/ash/launcher/browser_status_monitor.h"
7 #include "ash/shelf/shelf_util.h"
8 #include "ash/shell.h"
9 #include "ash/wm/window_util.h"
10 #include "base/stl_util.h"
11 #include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h"
12 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/browser_finder.h"
15 #include "chrome/browser/ui/browser_list.h"
16 #include "chrome/browser/ui/browser_window.h"
17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
18 #include "chrome/browser/web_applications/web_app.h"
19 #include "content/public/browser/web_contents.h"
20 #include "ui/aura/client/activation_client.h"
21 #include "ui/aura/root_window.h"
22 #include "ui/aura/window.h"
23 #include "ui/gfx/screen.h"
25 BrowserStatusMonitor::LocalWebContentsObserver::LocalWebContentsObserver(
26 content::WebContents* contents,
27 BrowserStatusMonitor* monitor)
28 : content::WebContentsObserver(contents),
29 monitor_(monitor) {
32 BrowserStatusMonitor::LocalWebContentsObserver::~LocalWebContentsObserver() {
35 void BrowserStatusMonitor::LocalWebContentsObserver::DidNavigateMainFrame(
36 const content::LoadCommittedDetails& details,
37 const content::FrameNavigateParams& params) {
38 Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
39 ChromeLauncherController::AppState state =
40 ChromeLauncherController::APP_STATE_INACTIVE;
41 if (browser->window()->IsActive() &&
42 browser->tab_strip_model()->GetActiveWebContents() == web_contents())
43 state = ChromeLauncherController::APP_STATE_WINDOW_ACTIVE;
44 else if (browser->window()->IsActive())
45 state = ChromeLauncherController::APP_STATE_ACTIVE;
47 monitor_->UpdateAppItemState(web_contents(), state);
48 monitor_->UpdateBrowserItemState();
50 // Navigating may change the LauncherID associated with the WebContents.
51 if (browser->tab_strip_model()->GetActiveWebContents() == web_contents()) {
52 ash::SetLauncherIDForWindow(
53 monitor_->GetLauncherIDForWebContents(web_contents()),
54 browser->window()->GetNativeWindow());
58 BrowserStatusMonitor::BrowserStatusMonitor(
59 ChromeLauncherController* launcher_controller)
60 : launcher_controller_(launcher_controller),
61 observed_activation_clients_(this),
62 observed_root_windows_(this) {
63 DCHECK(launcher_controller_);
64 BrowserList::AddObserver(this);
66 // This check needs for win7_aura. Without this, all tests in
67 // ChromeLauncherController will fail in win7_aura.
68 if (ash::Shell::HasInstance()) {
69 // We can't assume all RootWindows have the same ActivationClient.
70 // Add a RootWindow and its ActivationClient to the observed list.
71 aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
72 aura::Window::Windows::const_iterator iter = root_windows.begin();
73 for (; iter != root_windows.end(); ++iter) {
74 // |observed_activation_clients_| can have the same activation client
75 // multiple times - which would be handled by the used
76 // |ScopedObserverWithDuplicatedSources|.
77 observed_activation_clients_.Add(
78 aura::client::GetActivationClient(*iter));
79 observed_root_windows_.Add(static_cast<aura::Window*>(*iter));
81 ash::Shell::GetInstance()->GetScreen()->AddObserver(this);
85 BrowserStatusMonitor::~BrowserStatusMonitor() {
86 // This check needs for win7_aura. Without this, all tests in
87 // ChromeLauncherController will fail in win7_aura.
88 if (ash::Shell::HasInstance())
89 ash::Shell::GetInstance()->GetScreen()->RemoveObserver(this);
91 BrowserList::RemoveObserver(this);
93 BrowserList* browser_list =
94 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
95 for (BrowserList::const_iterator i = browser_list->begin();
96 i != browser_list->end(); ++i) {
97 OnBrowserRemoved(*i);
100 STLDeleteContainerPairSecondPointers(webcontents_to_observer_map_.begin(),
101 webcontents_to_observer_map_.end());
104 void BrowserStatusMonitor::UpdateAppItemState(
105 content::WebContents* contents,
106 ChromeLauncherController::AppState app_state) {
107 DCHECK(contents);
108 // It is possible to come here from Browser::SwapTabContent where the contents
109 // cannot be associated with a browser.
110 Browser* browser = chrome::FindBrowserWithWebContents(contents);
111 if (browser && launcher_controller_->IsBrowserFromActiveUser(browser))
112 launcher_controller_->UpdateAppState(contents, app_state);
115 void BrowserStatusMonitor::UpdateBrowserItemState() {
116 launcher_controller_->GetBrowserShortcutLauncherItemController()->
117 UpdateBrowserItemState();
120 void BrowserStatusMonitor::OnWindowActivated(aura::Window* gained_active,
121 aura::Window* lost_active) {
122 Browser* browser = NULL;
123 content::WebContents* contents_from_gained = NULL;
124 content::WebContents* contents_from_lost = NULL;
125 // Update active webcontents's app item state of |lost_active|, if existed.
126 if (lost_active) {
127 browser = chrome::FindBrowserWithWindow(lost_active);
128 if (browser)
129 contents_from_lost = browser->tab_strip_model()->GetActiveWebContents();
130 if (contents_from_lost) {
131 UpdateAppItemState(
132 contents_from_lost,
133 ChromeLauncherController::APP_STATE_INACTIVE);
137 // Update active webcontents's app item state of |gained_active|, if existed.
138 if (gained_active) {
139 browser = chrome::FindBrowserWithWindow(gained_active);
140 if (browser)
141 contents_from_gained = browser->tab_strip_model()->GetActiveWebContents();
142 if (contents_from_gained) {
143 UpdateAppItemState(
144 contents_from_gained,
145 ChromeLauncherController::APP_STATE_WINDOW_ACTIVE);
149 if (contents_from_lost || contents_from_gained)
150 UpdateBrowserItemState();
153 void BrowserStatusMonitor::OnWindowDestroyed(aura::Window* window) {
154 // Remove RootWindow and its ActivationClient from observed list.
155 observed_root_windows_.Remove(window);
156 observed_activation_clients_.Remove(
157 aura::client::GetActivationClient(window));
160 void BrowserStatusMonitor::OnBrowserAdded(Browser* browser) {
161 if (browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
162 return;
164 if (browser->is_type_popup() && browser->is_app()) {
165 // Note: A V1 application will set the tab strip observer when the app gets
166 // added to the shelf. This makes sure that in the multi user case we will
167 // only set the observer while the app item exists in the shelf.
168 AddV1AppToShelf(browser);
169 } else {
170 browser->tab_strip_model()->AddObserver(this);
174 void BrowserStatusMonitor::OnBrowserRemoved(Browser* browser) {
175 if (browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
176 return;
178 if (browser->is_type_popup() && browser->is_app())
179 RemoveV1AppFromShelf(browser);
180 else
181 browser->tab_strip_model()->RemoveObserver(this);
183 UpdateBrowserItemState();
186 void BrowserStatusMonitor::OnDisplayBoundsChanged(
187 const gfx::Display& display) {
188 // Do nothing here.
191 void BrowserStatusMonitor::OnDisplayAdded(const gfx::Display& new_display) {
192 // Add a new RootWindow and its ActivationClient to observed list.
193 aura::Window* root_window = ash::Shell::GetInstance()->
194 display_controller()->GetRootWindowForDisplayId(new_display.id());
195 // When the primary root window's display get removed, the existing root
196 // window is taken over by the new display and the observer is already set.
197 if (!observed_root_windows_.IsObserving(root_window)) {
198 observed_root_windows_.Add(static_cast<aura::Window*>(root_window));
199 observed_activation_clients_.Add(
200 aura::client::GetActivationClient(root_window));
204 void BrowserStatusMonitor::OnDisplayRemoved(const gfx::Display& old_display) {
205 // When this is called, RootWindow of |old_display| is already removed.
206 // Instead, we can remove RootWindow and its ActivationClient in the
207 // OnWindowRemoved().
208 // Do nothing here.
211 void BrowserStatusMonitor::ActiveTabChanged(content::WebContents* old_contents,
212 content::WebContents* new_contents,
213 int index,
214 int reason) {
215 Browser* browser = NULL;
216 // Use |new_contents|. |old_contents| could be NULL.
217 DCHECK(new_contents);
218 browser = chrome::FindBrowserWithWebContents(new_contents);
220 if (browser && browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
221 return;
223 ChromeLauncherController::AppState state =
224 ChromeLauncherController::APP_STATE_INACTIVE;
226 // Update immediately on a tab change.
227 if (old_contents &&
228 (TabStripModel::kNoTab !=
229 browser->tab_strip_model()->GetIndexOfWebContents(old_contents)))
230 UpdateAppItemState(old_contents, state);
232 if (new_contents) {
233 state = browser->window()->IsActive() ?
234 ChromeLauncherController::APP_STATE_WINDOW_ACTIVE :
235 ChromeLauncherController::APP_STATE_ACTIVE;
236 UpdateAppItemState(new_contents, state);
237 UpdateBrowserItemState();
238 ash::SetLauncherIDForWindow(
239 GetLauncherIDForWebContents(new_contents),
240 browser->window()->GetNativeWindow());
244 void BrowserStatusMonitor::TabReplacedAt(TabStripModel* tab_strip_model,
245 content::WebContents* old_contents,
246 content::WebContents* new_contents,
247 int index) {
248 DCHECK(old_contents && new_contents);
249 Browser* browser = chrome::FindBrowserWithWebContents(new_contents);
251 if (browser && browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
252 return;
254 UpdateAppItemState(old_contents,
255 ChromeLauncherController::APP_STATE_REMOVED);
256 RemoveWebContentsObserver(old_contents);
258 ChromeLauncherController::AppState state =
259 ChromeLauncherController::APP_STATE_ACTIVE;
260 if (browser->window()->IsActive() &&
261 (tab_strip_model->GetActiveWebContents() == new_contents))
262 state = ChromeLauncherController::APP_STATE_WINDOW_ACTIVE;
263 UpdateAppItemState(new_contents, state);
264 UpdateBrowserItemState();
266 if (tab_strip_model->GetActiveWebContents() == new_contents) {
267 ash::SetLauncherIDForWindow(
268 GetLauncherIDForWebContents(new_contents),
269 browser->window()->GetNativeWindow());
272 AddWebContentsObserver(new_contents);
275 void BrowserStatusMonitor::TabInsertedAt(content::WebContents* contents,
276 int index,
277 bool foreground) {
278 // An inserted tab is not active - ActiveTabChanged() will be called to
279 // activate. We initialize therefore with |APP_STATE_INACTIVE|.
280 UpdateAppItemState(contents,
281 ChromeLauncherController::APP_STATE_INACTIVE);
282 AddWebContentsObserver(contents);
285 void BrowserStatusMonitor::TabClosingAt(TabStripModel* tab_strip_mode,
286 content::WebContents* contents,
287 int index) {
288 UpdateAppItemState(contents,
289 ChromeLauncherController::APP_STATE_REMOVED);
290 RemoveWebContentsObserver(contents);
293 void BrowserStatusMonitor::AddV1AppToShelf(Browser* browser) {
294 DCHECK(browser->is_type_popup() && browser->is_app());
296 browser->tab_strip_model()->AddObserver(this);
298 std::string app_id =
299 web_app::GetExtensionIdFromApplicationName(browser->app_name());
300 if (!app_id.empty()) {
301 browser_to_app_id_map_[browser] = app_id;
302 launcher_controller_->LockV1AppWithID(app_id);
306 void BrowserStatusMonitor::RemoveV1AppFromShelf(Browser* browser) {
307 DCHECK(browser->is_type_popup() && browser->is_app());
309 browser->tab_strip_model()->RemoveObserver(this);
311 if (browser_to_app_id_map_.find(browser) != browser_to_app_id_map_.end()) {
312 launcher_controller_->UnlockV1AppWithID(browser_to_app_id_map_[browser]);
313 browser_to_app_id_map_.erase(browser);
317 bool BrowserStatusMonitor::IsV1AppInShelf(Browser* browser) {
318 return browser_to_app_id_map_.find(browser) != browser_to_app_id_map_.end();
321 void BrowserStatusMonitor::AddWebContentsObserver(
322 content::WebContents* contents) {
323 if (webcontents_to_observer_map_.find(contents) ==
324 webcontents_to_observer_map_.end()) {
325 webcontents_to_observer_map_[contents] =
326 new LocalWebContentsObserver(contents, this);
330 void BrowserStatusMonitor::RemoveWebContentsObserver(
331 content::WebContents* contents) {
332 DCHECK(webcontents_to_observer_map_.find(contents) !=
333 webcontents_to_observer_map_.end());
334 delete webcontents_to_observer_map_[contents];
335 webcontents_to_observer_map_.erase(contents);
338 ash::LauncherID BrowserStatusMonitor::GetLauncherIDForWebContents(
339 content::WebContents* contents) {
340 return launcher_controller_->GetLauncherIDForWebContents(contents);