1424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)// found in the LICENSE file.
4424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
5424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/browser_status_monitor.h"
6424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ash/shelf/shelf_util.h"
8424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ash/shell.h"
9424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ash/wm/window_util.h"
104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/stl_util.h"
1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.h"
12424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
13424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
14424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "chrome/browser/ui/browser_finder.h"
15424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "chrome/browser/ui/browser_list.h"
16424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "chrome/browser/ui/browser_window.h"
17424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
18424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "chrome/browser/web_applications/web_app.h"
19424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "content/public/browser/web_contents.h"
20424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ui/aura/client/activation_client.h"
21424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ui/aura/root_window.h"
22424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ui/aura/window.h"
23424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "ui/gfx/screen.h"
24424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)BrowserStatusMonitor::LocalWebContentsObserver::LocalWebContentsObserver(
264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    content::WebContents* contents,
274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    BrowserStatusMonitor* monitor)
284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    : content::WebContentsObserver(contents),
294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      monitor_(monitor) {
304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)BrowserStatusMonitor::LocalWebContentsObserver::~LocalWebContentsObserver() {
334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void BrowserStatusMonitor::LocalWebContentsObserver::DidNavigateMainFrame(
364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const content::LoadCommittedDetails& details,
374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const content::FrameNavigateParams& params) {
384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ChromeLauncherController::AppState state =
404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ChromeLauncherController::APP_STATE_INACTIVE;
414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (browser->window()->IsActive() &&
424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      browser->tab_strip_model()->GetActiveWebContents() == web_contents())
434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    state = ChromeLauncherController::APP_STATE_WINDOW_ACTIVE;
444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  else if (browser->window()->IsActive())
454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    state = ChromeLauncherController::APP_STATE_ACTIVE;
464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  monitor_->UpdateAppItemState(web_contents(), state);
484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  monitor_->UpdateBrowserItemState();
49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  // Navigating may change the LauncherID associated with the WebContents.
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (browser->tab_strip_model()->GetActiveWebContents() == web_contents()) {
52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ash::SetLauncherIDForWindow(
53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        monitor_->GetLauncherIDForWebContents(web_contents()),
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        browser->window()->GetNativeWindow());
55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
58424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)BrowserStatusMonitor::BrowserStatusMonitor(
59424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    ChromeLauncherController* launcher_controller)
60424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    : launcher_controller_(launcher_controller),
61424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      observed_activation_clients_(this),
62424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      observed_root_windows_(this) {
63424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  DCHECK(launcher_controller_);
6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  BrowserList::AddObserver(this);
65424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
66424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // This check needs for win7_aura. Without this, all tests in
67424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // ChromeLauncherController will fail in win7_aura.
68424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (ash::Shell::HasInstance()) {
69424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // We can't assume all RootWindows have the same ActivationClient.
70424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // Add a RootWindow and its ActivationClient to the observed list.
71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    aura::Window::Windows::const_iterator iter = root_windows.begin();
73424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    for (; iter != root_windows.end(); ++iter) {
74424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // |observed_activation_clients_| can have the same activation client
75424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // multiple times - which would be handled by the used
76424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // |ScopedObserverWithDuplicatedSources|.
77424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      observed_activation_clients_.Add(
78424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)          aura::client::GetActivationClient(*iter));
79424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      observed_root_windows_.Add(static_cast<aura::Window*>(*iter));
80424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
81424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    ash::Shell::GetInstance()->GetScreen()->AddObserver(this);
82424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
83424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
84424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
85424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)BrowserStatusMonitor::~BrowserStatusMonitor() {
86424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // This check needs for win7_aura. Without this, all tests in
87424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // ChromeLauncherController will fail in win7_aura.
88424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (ash::Shell::HasInstance())
89424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    ash::Shell::GetInstance()->GetScreen()->RemoveObserver(this);
90424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
9158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  BrowserList::RemoveObserver(this);
9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
93424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  BrowserList* browser_list =
94424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_ASH);
9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  for (BrowserList::const_iterator i = browser_list->begin();
9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)       i != browser_list->end(); ++i) {
9758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    OnBrowserRemoved(*i);
9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  STLDeleteContainerPairSecondPointers(webcontents_to_observer_map_.begin(),
1014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                       webcontents_to_observer_map_.end());
1024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void BrowserStatusMonitor::UpdateAppItemState(
1054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    content::WebContents* contents,
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    ChromeLauncherController::AppState app_state) {
1074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(contents);
1080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // It is possible to come here from Browser::SwapTabContent where the contents
1090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // cannot be associated with a browser.
1100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  Browser* browser = chrome::FindBrowserWithWebContents(contents);
1110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  if (browser && launcher_controller_->IsBrowserFromActiveUser(browser))
1121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    launcher_controller_->UpdateAppState(contents, app_state);
1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void BrowserStatusMonitor::UpdateBrowserItemState() {
1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  launcher_controller_->GetBrowserShortcutLauncherItemController()->
1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      UpdateBrowserItemState();
118424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
119424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
120424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void BrowserStatusMonitor::OnWindowActivated(aura::Window* gained_active,
121424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                             aura::Window* lost_active) {
1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Browser* browser = NULL;
1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  content::WebContents* contents_from_gained = NULL;
1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  content::WebContents* contents_from_lost = NULL;
1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Update active webcontents's app item state of |lost_active|, if existed.
1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (lost_active) {
1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    browser = chrome::FindBrowserWithWindow(lost_active);
1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (browser)
1294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      contents_from_lost = browser->tab_strip_model()->GetActiveWebContents();
1304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (contents_from_lost) {
1314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      UpdateAppItemState(
1324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          contents_from_lost,
1334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          ChromeLauncherController::APP_STATE_INACTIVE);
1344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
135424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
136424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
1374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Update active webcontents's app item state of |gained_active|, if existed.
1384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (gained_active) {
1394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    browser = chrome::FindBrowserWithWindow(gained_active);
1404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (browser)
1414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      contents_from_gained = browser->tab_strip_model()->GetActiveWebContents();
1424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if (contents_from_gained) {
1434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      UpdateAppItemState(
1444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          contents_from_gained,
1454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          ChromeLauncherController::APP_STATE_WINDOW_ACTIVE);
1464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
147424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
1484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (contents_from_lost || contents_from_gained)
1504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    UpdateBrowserItemState();
151424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
152424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
153424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void BrowserStatusMonitor::OnWindowDestroyed(aura::Window* window) {
154424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Remove RootWindow and its ActivationClient from observed list.
155424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  observed_root_windows_.Remove(window);
156f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  observed_activation_clients_.Remove(
157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      aura::client::GetActivationClient(window));
158424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
159424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
160424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void BrowserStatusMonitor::OnBrowserAdded(Browser* browser) {
16158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
16258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
16358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
164424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (browser->is_type_popup() && browser->is_app()) {
1651e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Note: A V1 application will set the tab strip observer when the app gets
1661e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // added to the shelf. This makes sure that in the multi user case we will
1671e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // only set the observer while the app item exists in the shelf.
1681e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    AddV1AppToShelf(browser);
1691e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  } else {
1701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    browser->tab_strip_model()->AddObserver(this);
171424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
172424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
173424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
174424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void BrowserStatusMonitor::OnBrowserRemoved(Browser* browser) {
17558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
17658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
17758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
1781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (browser->is_type_popup() && browser->is_app())
1791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    RemoveV1AppFromShelf(browser);
1801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  else
1811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    browser->tab_strip_model()->RemoveObserver(this);
182424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
18358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  UpdateBrowserItemState();
184424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
185424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
186424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void BrowserStatusMonitor::OnDisplayBoundsChanged(
187424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    const gfx::Display& display) {
188424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Do nothing here.
189424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
190424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
191424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void BrowserStatusMonitor::OnDisplayAdded(const gfx::Display& new_display) {
192424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Add a new RootWindow and its ActivationClient to observed list.
1931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  aura::Window* root_window = ash::Shell::GetInstance()->
194424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      display_controller()->GetRootWindowForDisplayId(new_display.id());
195424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // When the primary root window's display get removed, the existing root
196424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // window is taken over by the new display and the observer is already set.
197424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!observed_root_windows_.IsObserving(root_window)) {
198424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    observed_root_windows_.Add(static_cast<aura::Window*>(root_window));
199424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    observed_activation_clients_.Add(
200424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        aura::client::GetActivationClient(root_window));
201424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
202424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
203424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
204424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void BrowserStatusMonitor::OnDisplayRemoved(const gfx::Display& old_display) {
205424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // When this is called, RootWindow of |old_display| is already removed.
206424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Instead, we can remove RootWindow and its ActivationClient in the
207424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // OnWindowRemoved().
208424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Do nothing here.
209424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
210424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
211424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void BrowserStatusMonitor::ActiveTabChanged(content::WebContents* old_contents,
212424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                            content::WebContents* new_contents,
213424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                            int index,
214424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                            int reason) {
215424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  Browser* browser = NULL;
2164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Use |new_contents|. |old_contents| could be NULL.
2174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(new_contents);
2184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  browser = chrome::FindBrowserWithWebContents(new_contents);
219424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
22058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  if (browser && browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
22158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return;
22258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ChromeLauncherController::AppState state =
2244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ChromeLauncherController::APP_STATE_INACTIVE;
2254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
226424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Update immediately on a tab change.
2274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (old_contents &&
228424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      (TabStripModel::kNoTab !=
2294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)           browser->tab_strip_model()->GetIndexOfWebContents(old_contents)))
2304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    UpdateAppItemState(old_contents, state);
2314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (new_contents) {
2334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    state = browser->window()->IsActive() ?
2344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        ChromeLauncherController::APP_STATE_WINDOW_ACTIVE :
2354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        ChromeLauncherController::APP_STATE_ACTIVE;
2364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    UpdateAppItemState(new_contents, state);
2374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    UpdateBrowserItemState();
238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ash::SetLauncherIDForWindow(
239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        GetLauncherIDForWebContents(new_contents),
240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        browser->window()->GetNativeWindow());
24158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  }
2424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
243424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
2444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void BrowserStatusMonitor::TabReplacedAt(TabStripModel* tab_strip_model,
2454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                         content::WebContents* old_contents,
2464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                         content::WebContents* new_contents,
2474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                         int index) {
2484e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(old_contents && new_contents);
2494e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  Browser* browser = chrome::FindBrowserWithWebContents(new_contents);
2504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (browser && browser->host_desktop_type() != chrome::HOST_DESKTOP_TYPE_ASH)
2524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return;
2534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2544e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateAppItemState(old_contents,
2554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     ChromeLauncherController::APP_STATE_REMOVED);
2564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  RemoveWebContentsObserver(old_contents);
2574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  ChromeLauncherController::AppState state =
2594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ChromeLauncherController::APP_STATE_ACTIVE;
2604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (browser->window()->IsActive() &&
2614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      (tab_strip_model->GetActiveWebContents() == new_contents))
2624e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    state = ChromeLauncherController::APP_STATE_WINDOW_ACTIVE;
2634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateAppItemState(new_contents, state);
264f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  UpdateBrowserItemState();
265f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
266f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (tab_strip_model->GetActiveWebContents() == new_contents) {
267f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    ash::SetLauncherIDForWindow(
268f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        GetLauncherIDForWebContents(new_contents),
269f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        browser->window()->GetNativeWindow());
270f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
271f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
2724e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AddWebContentsObserver(new_contents);
273424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
274424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
275424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void BrowserStatusMonitor::TabInsertedAt(content::WebContents* contents,
276424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                         int index,
277424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                         bool foreground) {
2784e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // An inserted tab is not active - ActiveTabChanged() will be called to
2794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // activate. We initialize therefore with |APP_STATE_INACTIVE|.
2804e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateAppItemState(contents,
2814e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     ChromeLauncherController::APP_STATE_INACTIVE);
2824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  AddWebContentsObserver(contents);
283424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
284424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
2854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void BrowserStatusMonitor::TabClosingAt(TabStripModel* tab_strip_mode,
2864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                        content::WebContents* contents,
2874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                        int index) {
2884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateAppItemState(contents,
2894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                     ChromeLauncherController::APP_STATE_REMOVED);
2904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  RemoveWebContentsObserver(contents);
291424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
292424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
2931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void BrowserStatusMonitor::AddV1AppToShelf(Browser* browser) {
2941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(browser->is_type_popup() && browser->is_app());
2951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2961e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  browser->tab_strip_model()->AddObserver(this);
2971e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2981e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  std::string app_id =
2991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      web_app::GetExtensionIdFromApplicationName(browser->app_name());
3001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (!app_id.empty()) {
3011e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    browser_to_app_id_map_[browser] = app_id;
3021e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    launcher_controller_->LockV1AppWithID(app_id);
3031e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
3041e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)void BrowserStatusMonitor::RemoveV1AppFromShelf(Browser* browser) {
3071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  DCHECK(browser->is_type_popup() && browser->is_app());
3081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  browser->tab_strip_model()->RemoveObserver(this);
3101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  if (browser_to_app_id_map_.find(browser) != browser_to_app_id_map_.end()) {
3121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    launcher_controller_->UnlockV1AppWithID(browser_to_app_id_map_[browser]);
3131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    browser_to_app_id_map_.erase(browser);
3141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  }
3151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)bool BrowserStatusMonitor::IsV1AppInShelf(Browser* browser) {
3181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  return browser_to_app_id_map_.find(browser) != browser_to_app_id_map_.end();
3191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)}
3201e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void BrowserStatusMonitor::AddWebContentsObserver(
32258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    content::WebContents* contents) {
3234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  if (webcontents_to_observer_map_.find(contents) ==
3244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          webcontents_to_observer_map_.end()) {
3254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    webcontents_to_observer_map_[contents] =
3264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        new LocalWebContentsObserver(contents, this);
327424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
32858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)}
329424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
3304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)void BrowserStatusMonitor::RemoveWebContentsObserver(
3314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    content::WebContents* contents) {
3324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  DCHECK(webcontents_to_observer_map_.find(contents) !=
3334e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      webcontents_to_observer_map_.end());
3344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  delete webcontents_to_observer_map_[contents];
3354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  webcontents_to_observer_map_.erase(contents);
336424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)}
337f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
338f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ash::LauncherID BrowserStatusMonitor::GetLauncherIDForWebContents(
339f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    content::WebContents* contents) {
340f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return launcher_controller_->GetLauncherIDForWebContents(contents);
341f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
342