普通文本  |  353行  |  10.56 KB

// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "apps/app_window.h"
#include "apps/app_window_registry.h"
#include "apps/apps_client.h"
#include "apps/ui/native_app_window.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/devtools_manager.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/extensions_browser_client.h"
#include "extensions/common/extension.h"

namespace {

// Create a key that identifies a AppWindow in a RenderViewHost across App
// reloads. If the window was given an id in CreateParams, the key is the
// extension id, a colon separator, and the AppWindow's |id|. If there is no
// |id|, the chrome-extension://extension-id/page.html URL will be used. If the
// RenderViewHost is not for a AppWindow, return an empty string.
std::string GetWindowKeyForRenderViewHost(
    const apps::AppWindowRegistry* registry,
    content::RenderViewHost* render_view_host) {
  apps::AppWindow* app_window =
      registry->GetAppWindowForRenderViewHost(render_view_host);
  if (!app_window)
    return std::string();  // Not a AppWindow.

  if (app_window->window_key().empty())
    return app_window->web_contents()->GetURL().possibly_invalid_spec();

  std::string key = app_window->extension_id();
  key += ':';
  key += app_window->window_key();
  return key;
}

}  // namespace

namespace apps {

void AppWindowRegistry::Observer::OnAppWindowAdded(AppWindow* app_window) {
}

void AppWindowRegistry::Observer::OnAppWindowIconChanged(
    AppWindow* app_window) {
}

void AppWindowRegistry::Observer::OnAppWindowRemoved(AppWindow* app_window) {
}

void AppWindowRegistry::Observer::OnAppWindowHidden(AppWindow* app_window) {
}

void AppWindowRegistry::Observer::OnAppWindowShown(AppWindow* app_window) {
}

AppWindowRegistry::Observer::~Observer() {
}

AppWindowRegistry::AppWindowRegistry(content::BrowserContext* context)
    : context_(context),
      devtools_callback_(base::Bind(&AppWindowRegistry::OnDevToolsStateChanged,
                                    base::Unretained(this))) {
  content::DevToolsManager::GetInstance()->AddAgentStateCallback(
      devtools_callback_);
}

AppWindowRegistry::~AppWindowRegistry() {
  content::DevToolsManager::GetInstance()->RemoveAgentStateCallback(
      devtools_callback_);
}

// static
AppWindowRegistry* AppWindowRegistry::Get(content::BrowserContext* context) {
  return Factory::GetForBrowserContext(context, true /* create */);
}

void AppWindowRegistry::AddAppWindow(AppWindow* app_window) {
  BringToFront(app_window);
  FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowAdded(app_window));
}

void AppWindowRegistry::AppWindowIconChanged(AppWindow* app_window) {
  AddAppWindowToList(app_window);
  FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowIconChanged(app_window));
}

void AppWindowRegistry::AppWindowActivated(AppWindow* app_window) {
  BringToFront(app_window);
}

void AppWindowRegistry::AppWindowHidden(AppWindow* app_window) {
  FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowHidden(app_window));
}

void AppWindowRegistry::AppWindowShown(AppWindow* app_window) {
  FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowShown(app_window));
}

void AppWindowRegistry::RemoveAppWindow(AppWindow* app_window) {
  const AppWindowList::iterator it =
      std::find(app_windows_.begin(), app_windows_.end(), app_window);
  if (it != app_windows_.end())
    app_windows_.erase(it);
  FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowRemoved(app_window));
}

void AppWindowRegistry::AddObserver(Observer* observer) {
  observers_.AddObserver(observer);
}

void AppWindowRegistry::RemoveObserver(Observer* observer) {
  observers_.RemoveObserver(observer);
}

AppWindowRegistry::AppWindowList AppWindowRegistry::GetAppWindowsForApp(
    const std::string& app_id) const {
  AppWindowList app_windows;
  for (AppWindowList::const_iterator i = app_windows_.begin();
       i != app_windows_.end();
       ++i) {
    if ((*i)->extension_id() == app_id)
      app_windows.push_back(*i);
  }
  return app_windows;
}

void AppWindowRegistry::CloseAllAppWindowsForApp(const std::string& app_id) {
  const AppWindowList windows = GetAppWindowsForApp(app_id);
  for (AppWindowRegistry::const_iterator it = windows.begin();
       it != windows.end();
       ++it) {
    (*it)->GetBaseWindow()->Close();
  }
}

AppWindow* AppWindowRegistry::GetAppWindowForRenderViewHost(
    content::RenderViewHost* render_view_host) const {
  for (AppWindowList::const_iterator i = app_windows_.begin();
       i != app_windows_.end();
       ++i) {
    if ((*i)->web_contents()->GetRenderViewHost() == render_view_host)
      return *i;
  }

  return NULL;
}

AppWindow* AppWindowRegistry::GetAppWindowForNativeWindow(
    gfx::NativeWindow window) const {
  for (AppWindowList::const_iterator i = app_windows_.begin();
       i != app_windows_.end();
       ++i) {
    if ((*i)->GetNativeWindow() == window)
      return *i;
  }

  return NULL;
}

AppWindow* AppWindowRegistry::GetCurrentAppWindowForApp(
    const std::string& app_id) const {
  AppWindow* result = NULL;
  for (AppWindowList::const_iterator i = app_windows_.begin();
       i != app_windows_.end();
       ++i) {
    if ((*i)->extension_id() == app_id) {
      result = *i;
      if (result->GetBaseWindow()->IsActive())
        return result;
    }
  }

  return result;
}

AppWindow* AppWindowRegistry::GetAppWindowForAppAndKey(
    const std::string& app_id,
    const std::string& window_key) const {
  AppWindow* result = NULL;
  for (AppWindowList::const_iterator i = app_windows_.begin();
       i != app_windows_.end();
       ++i) {
    if ((*i)->extension_id() == app_id && (*i)->window_key() == window_key) {
      result = *i;
      if (result->GetBaseWindow()->IsActive())
        return result;
    }
  }
  return result;
}

bool AppWindowRegistry::HadDevToolsAttached(
    content::RenderViewHost* render_view_host) const {
  std::string key = GetWindowKeyForRenderViewHost(this, render_view_host);
  return key.empty() ? false : inspected_windows_.count(key) != 0;
}

// static
AppWindow* AppWindowRegistry::GetAppWindowForNativeWindowAnyProfile(
    gfx::NativeWindow window) {
  std::vector<content::BrowserContext*> contexts =
      AppsClient::Get()->GetLoadedBrowserContexts();
  for (std::vector<content::BrowserContext*>::const_iterator i =
           contexts.begin();
       i != contexts.end();
       ++i) {
    AppWindowRegistry* registry =
        Factory::GetForBrowserContext(*i, false /* create */);
    if (!registry)
      continue;

    AppWindow* app_window = registry->GetAppWindowForNativeWindow(window);
    if (app_window)
      return app_window;
  }

  return NULL;
}

// static
bool AppWindowRegistry::IsAppWindowRegisteredInAnyProfile(
    int window_type_mask) {
  std::vector<content::BrowserContext*> contexts =
      AppsClient::Get()->GetLoadedBrowserContexts();
  for (std::vector<content::BrowserContext*>::const_iterator i =
           contexts.begin();
       i != contexts.end();
       ++i) {
    AppWindowRegistry* registry =
        Factory::GetForBrowserContext(*i, false /* create */);
    if (!registry)
      continue;

    const AppWindowList& app_windows = registry->app_windows();
    if (app_windows.empty())
      continue;

    if (window_type_mask == 0)
      return true;

    for (const_iterator j = app_windows.begin(); j != app_windows.end(); ++j) {
      if ((*j)->window_type() & window_type_mask)
        return true;
    }
  }

  return false;
}

// static
void AppWindowRegistry::CloseAllAppWindows() {
  std::vector<content::BrowserContext*> contexts =
      AppsClient::Get()->GetLoadedBrowserContexts();
  for (std::vector<content::BrowserContext*>::const_iterator i =
           contexts.begin();
       i != contexts.end();
       ++i) {
    AppWindowRegistry* registry =
        Factory::GetForBrowserContext(*i, false /* create */);
    if (!registry)
      continue;

    while (!registry->app_windows().empty())
      registry->app_windows().front()->GetBaseWindow()->Close();
  }
}

void AppWindowRegistry::OnDevToolsStateChanged(
    content::DevToolsAgentHost* agent_host,
    bool attached) {
  content::RenderViewHost* rvh = agent_host->GetRenderViewHost();
  // Ignore unrelated notifications.
  if (!rvh ||
      rvh->GetSiteInstance()->GetProcess()->GetBrowserContext() != context_)
    return;

  std::string key = GetWindowKeyForRenderViewHost(this, rvh);
  if (key.empty())
    return;

  if (attached)
    inspected_windows_.insert(key);
  else
    inspected_windows_.erase(key);
}

void AppWindowRegistry::AddAppWindowToList(AppWindow* app_window) {
  const AppWindowList::iterator it =
      std::find(app_windows_.begin(), app_windows_.end(), app_window);
  if (it != app_windows_.end())
    return;
  app_windows_.push_back(app_window);
}

void AppWindowRegistry::BringToFront(AppWindow* app_window) {
  const AppWindowList::iterator it =
      std::find(app_windows_.begin(), app_windows_.end(), app_window);
  if (it != app_windows_.end())
    app_windows_.erase(it);
  app_windows_.push_front(app_window);
}

///////////////////////////////////////////////////////////////////////////////
// Factory boilerplate

// static
AppWindowRegistry* AppWindowRegistry::Factory::GetForBrowserContext(
    content::BrowserContext* context,
    bool create) {
  return static_cast<AppWindowRegistry*>(
      GetInstance()->GetServiceForBrowserContext(context, create));
}

AppWindowRegistry::Factory* AppWindowRegistry::Factory::GetInstance() {
  return Singleton<AppWindowRegistry::Factory>::get();
}

AppWindowRegistry::Factory::Factory()
    : BrowserContextKeyedServiceFactory(
          "AppWindowRegistry",
          BrowserContextDependencyManager::GetInstance()) {}

AppWindowRegistry::Factory::~Factory() {}

KeyedService* AppWindowRegistry::Factory::BuildServiceInstanceFor(
    content::BrowserContext* context) const {
  return new AppWindowRegistry(context);
}

bool AppWindowRegistry::Factory::ServiceIsCreatedWithBrowserContext() const {
  return true;
}

bool AppWindowRegistry::Factory::ServiceIsNULLWhileTesting() const {
  return false;
}

content::BrowserContext* AppWindowRegistry::Factory::GetBrowserContextToUse(
    content::BrowserContext* context) const {
  return extensions::ExtensionsBrowserClient::Get()->GetOriginalContext(
      context);
}

}  // namespace apps