Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / ui / ash / launcher / browser_status_monitor.cc
blob31cffa66c0eb4fb5d422bfee11d9cbfbe53e495a
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/display/window_tree_host_manager.h"
8 #include "ash/shelf/shelf_util.h"
9 #include "ash/shell.h"
10 #include "ash/wm/window_util.h"
11 #include "base/stl_util.h"
12 #include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h"
13 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
14 #include "chrome/browser/ui/browser.h"
15 #include "chrome/browser/ui/browser_finder.h"
16 #include "chrome/browser/ui/browser_list.h"
17 #include "chrome/browser/ui/browser_window.h"
18 #include "chrome/browser/ui/settings_window_manager.h"
19 #include "chrome/browser/ui/settings_window_manager_observer.h"
20 #include "chrome/browser/ui/tabs/tab_strip_model.h"
21 #include "chrome/browser/web_applications/web_app.h"
22 #include "content/public/browser/web_contents.h"
23 #include "content/public/browser/web_contents_observer.h"
24 #include "grit/ash_resources.h"
25 #include "grit/generated_resources.h"
26 #include "ui/aura/window.h"
27 #include "ui/aura/window_event_dispatcher.h"
28 #include "ui/base/l10n/l10n_util.h"
29 #include "ui/gfx/screen.h"
30 #include "ui/wm/public/activation_client.h"
32 // This class monitors the WebContent of the all tab and notifies a navigation
33 // to the BrowserStatusMonitor.
34 class BrowserStatusMonitor::LocalWebContentsObserver
35 : public content::WebContentsObserver {
36 public:
37 LocalWebContentsObserver(content::WebContents* contents,
38 BrowserStatusMonitor* monitor)
39 : content::WebContentsObserver(contents),
40 monitor_(monitor) {}
42 ~LocalWebContentsObserver() override {}
44 // content::WebContentsObserver
45 void DidNavigateMainFrame(
46 const content::LoadCommittedDetails& details,
47 const content::FrameNavigateParams& params) override {
48 ChromeLauncherController::AppState state =
49 ChromeLauncherController::APP_STATE_INACTIVE;
50 Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
51 // Don't assume that |browser| still exists.
52 if (browser) {
53 if (browser->window()->IsActive() &&
54 browser->tab_strip_model()->GetActiveWebContents() == web_contents())
55 state = ChromeLauncherController::APP_STATE_WINDOW_ACTIVE;
56 else if (browser->window()->IsActive())
57 state = ChromeLauncherController::APP_STATE_ACTIVE;
59 monitor_->UpdateAppItemState(web_contents(), state);
60 monitor_->UpdateBrowserItemState();
62 // Navigating may change the ShelfID associated with the WebContents.
63 if (browser &&
64 browser->tab_strip_model()->GetActiveWebContents() == web_contents()) {
65 monitor_->SetShelfIDForBrowserWindowContents(browser, web_contents());
69 void WebContentsDestroyed() override {
70 // We can only come here when there was a non standard termination like
71 // an app got un-installed while running, etc.
72 monitor_->WebContentsDestroyed(web_contents());
73 // |this| is gone now.
76 private:
77 BrowserStatusMonitor* monitor_;
79 DISALLOW_COPY_AND_ASSIGN(LocalWebContentsObserver);
82 // Observes any new settings windows and sets their shelf icon (since they
83 // are excluded from BrowserShortcutLauncherItem).
84 class BrowserStatusMonitor::SettingsWindowObserver
85 : public chrome::SettingsWindowManagerObserver {
86 public:
87 SettingsWindowObserver() {}
88 ~SettingsWindowObserver() override {}
90 // SettingsWindowManagerObserver
91 void OnNewSettingsWindow(Browser* settings_browser) override {
92 ash::SetShelfItemDetailsForDialogWindow(
93 settings_browser->window()->GetNativeWindow(),
94 IDR_ASH_SHELF_ICON_SETTINGS,
95 l10n_util::GetStringUTF16(IDS_SETTINGS_TITLE));
98 private:
99 DISALLOW_COPY_AND_ASSIGN(SettingsWindowObserver);
102 BrowserStatusMonitor::BrowserStatusMonitor(
103 ChromeLauncherController* launcher_controller)
104 : launcher_controller_(launcher_controller),
105 observed_activation_clients_(this),
106 observed_root_windows_(this),
107 settings_window_observer_(new SettingsWindowObserver) {
108 DCHECK(launcher_controller_);
109 BrowserList::AddObserver(this);
110 chrome::SettingsWindowManager::GetInstance()->AddObserver(
111 settings_window_observer_.get());
113 // This check needs for win7_aura. Without this, all tests in
114 // ChromeLauncherController will fail in win7_aura.
115 if (ash::Shell::HasInstance()) {
116 // We can't assume all RootWindows have the same ActivationClient.
117 // Add a RootWindow and its ActivationClient to the observed list.
118 aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
119 aura::Window::Windows::const_iterator iter = root_windows.begin();
120 for (; iter != root_windows.end(); ++iter) {
121 // |observed_activation_clients_| can have the same activation client
122 // multiple times - which would be handled by the used
123 // |ScopedObserverWithDuplicatedSources|.
124 observed_activation_clients_.Add(
125 aura::client::GetActivationClient(*iter));
126 observed_root_windows_.Add(static_cast<aura::Window*>(*iter));
128 ash::Shell::GetInstance()->GetScreen()->AddObserver(this);
132 BrowserStatusMonitor::~BrowserStatusMonitor() {
133 // This check needs for win7_aura. Without this, all tests in
134 // ChromeLauncherController will fail in win7_aura.
135 if (ash::Shell::HasInstance())
136 ash::Shell::GetInstance()->GetScreen()->RemoveObserver(this);
138 chrome::SettingsWindowManager::GetInstance()->RemoveObserver(
139 settings_window_observer_.get());
141 BrowserList::RemoveObserver(this);
143 BrowserList* browser_list =
144 BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
145 for (BrowserList::const_iterator i = browser_list->begin();
146 i != browser_list->end(); ++i) {
147 OnBrowserRemoved(*i);
150 STLDeleteContainerPairSecondPointers(webcontents_to_observer_map_.begin(),
151 webcontents_to_observer_map_.end());
154 void BrowserStatusMonitor::UpdateAppItemState(
155 content::WebContents* contents,
156 ChromeLauncherController::AppState app_state) {
157 DCHECK(contents);
158 // It is possible to come here from Browser::SwapTabContent where the contents
159 // cannot be associated with a browser. A removal however should be properly
160 // processed.
161 Browser* browser = chrome::FindBrowserWithWebContents(contents);
162 if (app_state == ChromeLauncherController::APP_STATE_REMOVED ||
163 (browser && launcher_controller_->IsBrowserFromActiveUser(browser)))
164 launcher_controller_->UpdateAppState(contents, app_state);
167 void BrowserStatusMonitor::UpdateBrowserItemState() {
168 launcher_controller_->GetBrowserShortcutLauncherItemController()->
169 UpdateBrowserItemState();
172 void BrowserStatusMonitor::OnWindowActivated(
173 aura::client::ActivationChangeObserver::ActivationReason reason,
174 aura::Window* gained_active,
175 aura::Window* lost_active) {
176 Browser* browser = NULL;
177 content::WebContents* contents_from_gained = NULL;
178 content::WebContents* contents_from_lost = NULL;
179 // Update active webcontents's app item state of |lost_active|, if existed.
180 if (lost_active) {
181 browser = chrome::FindBrowserWithWindow(lost_active);
182 if (browser)
183 contents_from_lost = browser->tab_strip_model()->GetActiveWebContents();
184 if (contents_from_lost) {
185 UpdateAppItemState(
186 contents_from_lost,
187 ChromeLauncherController::APP_STATE_INACTIVE);
191 // Update active webcontents's app item state of |gained_active|, if existed.
192 if (gained_active) {
193 browser = chrome::FindBrowserWithWindow(gained_active);
194 if (browser)
195 contents_from_gained = browser->tab_strip_model()->GetActiveWebContents();
196 if (contents_from_gained) {
197 UpdateAppItemState(
198 contents_from_gained,
199 ChromeLauncherController::APP_STATE_WINDOW_ACTIVE);
203 if (contents_from_lost || contents_from_gained)
204 UpdateBrowserItemState();
207 void BrowserStatusMonitor::OnWindowDestroyed(aura::Window* window) {
208 // Remove RootWindow and its ActivationClient from observed list.
209 observed_root_windows_.Remove(window);
210 observed_activation_clients_.Remove(
211 aura::client::GetActivationClient(window));
214 void BrowserStatusMonitor::OnBrowserAdded(Browser* browser) {
215 if (browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
216 return;
218 if (browser->is_type_popup() && browser->is_app()) {
219 // Note: A V1 application will set the tab strip observer when the app gets
220 // added to the shelf. This makes sure that in the multi user case we will
221 // only set the observer while the app item exists in the shelf.
222 AddV1AppToShelf(browser);
223 } else {
224 browser->tab_strip_model()->AddObserver(this);
228 void BrowserStatusMonitor::OnBrowserRemoved(Browser* browser) {
229 if (browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
230 return;
232 if (browser->is_type_popup() && browser->is_app())
233 RemoveV1AppFromShelf(browser);
234 else
235 browser->tab_strip_model()->RemoveObserver(this);
237 UpdateBrowserItemState();
240 void BrowserStatusMonitor::OnDisplayAdded(const gfx::Display& new_display) {
241 // Add a new RootWindow and its ActivationClient to observed list.
242 aura::Window* root_window = ash::Shell::GetInstance()
243 ->window_tree_host_manager()
244 ->GetRootWindowForDisplayId(new_display.id());
245 // When the primary root window's display get removed, the existing root
246 // window is taken over by the new display and the observer is already set.
247 if (!observed_root_windows_.IsObserving(root_window)) {
248 observed_root_windows_.Add(static_cast<aura::Window*>(root_window));
249 observed_activation_clients_.Add(
250 aura::client::GetActivationClient(root_window));
254 void BrowserStatusMonitor::OnDisplayRemoved(const gfx::Display& old_display) {
255 // When this is called, RootWindow of |old_display| is already removed.
256 // Instead, we can remove RootWindow and its ActivationClient in the
257 // OnWindowRemoved().
258 // Do nothing here.
261 void BrowserStatusMonitor::OnDisplayMetricsChanged(const gfx::Display&,
262 uint32_t) {
263 // Do nothing here.
266 void BrowserStatusMonitor::ActiveTabChanged(content::WebContents* old_contents,
267 content::WebContents* new_contents,
268 int index,
269 int reason) {
270 Browser* browser = NULL;
271 // Use |new_contents|. |old_contents| could be NULL.
272 DCHECK(new_contents);
273 browser = chrome::FindBrowserWithWebContents(new_contents);
275 if (browser && browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
276 return;
278 ChromeLauncherController::AppState state =
279 ChromeLauncherController::APP_STATE_INACTIVE;
281 // Update immediately on a tab change.
282 if (old_contents &&
283 (TabStripModel::kNoTab !=
284 browser->tab_strip_model()->GetIndexOfWebContents(old_contents)))
285 UpdateAppItemState(old_contents, state);
287 if (new_contents) {
288 state = browser->window()->IsActive() ?
289 ChromeLauncherController::APP_STATE_WINDOW_ACTIVE :
290 ChromeLauncherController::APP_STATE_ACTIVE;
291 UpdateAppItemState(new_contents, state);
292 UpdateBrowserItemState();
293 SetShelfIDForBrowserWindowContents(browser, new_contents);
297 void BrowserStatusMonitor::TabReplacedAt(TabStripModel* tab_strip_model,
298 content::WebContents* old_contents,
299 content::WebContents* new_contents,
300 int index) {
301 DCHECK(old_contents && new_contents);
302 Browser* browser = chrome::FindBrowserWithWebContents(new_contents);
304 if (browser && browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
305 return;
307 UpdateAppItemState(old_contents,
308 ChromeLauncherController::APP_STATE_REMOVED);
309 RemoveWebContentsObserver(old_contents);
311 ChromeLauncherController::AppState state =
312 ChromeLauncherController::APP_STATE_ACTIVE;
313 if (browser->window()->IsActive() &&
314 (tab_strip_model->GetActiveWebContents() == new_contents))
315 state = ChromeLauncherController::APP_STATE_WINDOW_ACTIVE;
316 UpdateAppItemState(new_contents, state);
317 UpdateBrowserItemState();
319 if (tab_strip_model->GetActiveWebContents() == new_contents)
320 SetShelfIDForBrowserWindowContents(browser, new_contents);
322 AddWebContentsObserver(new_contents);
325 void BrowserStatusMonitor::TabInsertedAt(content::WebContents* contents,
326 int index,
327 bool foreground) {
328 // An inserted tab is not active - ActiveTabChanged() will be called to
329 // activate. We initialize therefore with |APP_STATE_INACTIVE|.
330 UpdateAppItemState(contents,
331 ChromeLauncherController::APP_STATE_INACTIVE);
332 AddWebContentsObserver(contents);
335 void BrowserStatusMonitor::TabClosingAt(TabStripModel* tab_strip_mode,
336 content::WebContents* contents,
337 int index) {
338 UpdateAppItemState(contents,
339 ChromeLauncherController::APP_STATE_REMOVED);
340 RemoveWebContentsObserver(contents);
343 void BrowserStatusMonitor::WebContentsDestroyed(
344 content::WebContents* contents) {
345 UpdateAppItemState(contents, ChromeLauncherController::APP_STATE_REMOVED);
346 RemoveWebContentsObserver(contents);
349 void BrowserStatusMonitor::AddV1AppToShelf(Browser* browser) {
350 DCHECK(browser->is_type_popup() && browser->is_app());
352 browser->tab_strip_model()->AddObserver(this);
354 std::string app_id =
355 web_app::GetExtensionIdFromApplicationName(browser->app_name());
356 if (!app_id.empty()) {
357 browser_to_app_id_map_[browser] = app_id;
358 launcher_controller_->LockV1AppWithID(app_id);
362 void BrowserStatusMonitor::RemoveV1AppFromShelf(Browser* browser) {
363 DCHECK(browser->is_type_popup() && browser->is_app());
365 browser->tab_strip_model()->RemoveObserver(this);
367 if (browser_to_app_id_map_.find(browser) != browser_to_app_id_map_.end()) {
368 launcher_controller_->UnlockV1AppWithID(browser_to_app_id_map_[browser]);
369 browser_to_app_id_map_.erase(browser);
373 bool BrowserStatusMonitor::IsV1AppInShelf(Browser* browser) {
374 return browser_to_app_id_map_.find(browser) != browser_to_app_id_map_.end();
377 void BrowserStatusMonitor::AddWebContentsObserver(
378 content::WebContents* contents) {
379 if (webcontents_to_observer_map_.find(contents) ==
380 webcontents_to_observer_map_.end()) {
381 webcontents_to_observer_map_[contents] =
382 new LocalWebContentsObserver(contents, this);
386 void BrowserStatusMonitor::RemoveWebContentsObserver(
387 content::WebContents* contents) {
388 DCHECK(webcontents_to_observer_map_.find(contents) !=
389 webcontents_to_observer_map_.end());
390 delete webcontents_to_observer_map_[contents];
391 webcontents_to_observer_map_.erase(contents);
394 ash::ShelfID BrowserStatusMonitor::GetShelfIDForWebContents(
395 content::WebContents* contents) {
396 return launcher_controller_->GetShelfIDForWebContents(contents);
399 void BrowserStatusMonitor::SetShelfIDForBrowserWindowContents(
400 Browser* browser,
401 content::WebContents* web_contents) {
402 launcher_controller_->GetBrowserShortcutLauncherItemController()->
403 SetShelfIDForBrowserWindowContents(browser, web_contents);