1// Copyright 2014 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. 4 5#include "extensions/browser/app_window/app_window_registry.h" 6 7#include <string> 8#include <vector> 9 10#include "components/keyed_service/content/browser_context_dependency_manager.h" 11#include "content/public/browser/browser_context.h" 12#include "content/public/browser/devtools_agent_host.h" 13#include "content/public/browser/render_process_host.h" 14#include "content/public/browser/render_view_host.h" 15#include "content/public/browser/site_instance.h" 16#include "content/public/browser/web_contents.h" 17#include "extensions/browser/app_window/app_window.h" 18#include "extensions/browser/app_window/native_app_window.h" 19#include "extensions/browser/extensions_browser_client.h" 20#include "extensions/common/extension.h" 21 22namespace extensions { 23 24namespace { 25 26// Create a key that identifies a AppWindow in a RenderViewHost across App 27// reloads. If the window was given an id in CreateParams, the key is the 28// extension id, a colon separator, and the AppWindow's |id|. If there is no 29// |id|, the chrome-extension://extension-id/page.html URL will be used. If the 30// RenderViewHost is not for a AppWindow, return an empty string. 31std::string GetWindowKeyForRenderViewHost( 32 const AppWindowRegistry* registry, 33 content::RenderViewHost* render_view_host) { 34 AppWindow* app_window = 35 registry->GetAppWindowForRenderViewHost(render_view_host); 36 if (!app_window) 37 return std::string(); // Not a AppWindow. 38 39 if (app_window->window_key().empty()) 40 return app_window->web_contents()->GetURL().possibly_invalid_spec(); 41 42 std::string key = app_window->extension_id(); 43 key += ':'; 44 key += app_window->window_key(); 45 return key; 46} 47 48} // namespace 49 50void AppWindowRegistry::Observer::OnAppWindowAdded(AppWindow* app_window) { 51} 52 53void AppWindowRegistry::Observer::OnAppWindowIconChanged( 54 AppWindow* app_window) { 55} 56 57void AppWindowRegistry::Observer::OnAppWindowRemoved(AppWindow* app_window) { 58} 59 60void AppWindowRegistry::Observer::OnAppWindowHidden(AppWindow* app_window) { 61} 62 63void AppWindowRegistry::Observer::OnAppWindowShown(AppWindow* app_window) { 64} 65 66AppWindowRegistry::Observer::~Observer() { 67} 68 69AppWindowRegistry::AppWindowRegistry(content::BrowserContext* context) 70 : context_(context), 71 devtools_callback_(base::Bind(&AppWindowRegistry::OnDevToolsStateChanged, 72 base::Unretained(this))) { 73 content::DevToolsAgentHost::AddAgentStateCallback(devtools_callback_); 74} 75 76AppWindowRegistry::~AppWindowRegistry() { 77 content::DevToolsAgentHost::RemoveAgentStateCallback(devtools_callback_); 78} 79 80// static 81AppWindowRegistry* AppWindowRegistry::Get(content::BrowserContext* context) { 82 return Factory::GetForBrowserContext(context, true /* create */); 83} 84 85void AppWindowRegistry::AddAppWindow(AppWindow* app_window) { 86 BringToFront(app_window); 87 FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowAdded(app_window)); 88} 89 90void AppWindowRegistry::AppWindowIconChanged(AppWindow* app_window) { 91 AddAppWindowToList(app_window); 92 FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowIconChanged(app_window)); 93} 94 95void AppWindowRegistry::AppWindowActivated(AppWindow* app_window) { 96 BringToFront(app_window); 97} 98 99void AppWindowRegistry::AppWindowHidden(AppWindow* app_window) { 100 FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowHidden(app_window)); 101} 102 103void AppWindowRegistry::AppWindowShown(AppWindow* app_window) { 104 FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowShown(app_window)); 105} 106 107void AppWindowRegistry::RemoveAppWindow(AppWindow* app_window) { 108 const AppWindowList::iterator it = 109 std::find(app_windows_.begin(), app_windows_.end(), app_window); 110 if (it != app_windows_.end()) 111 app_windows_.erase(it); 112 FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowRemoved(app_window)); 113} 114 115void AppWindowRegistry::AddObserver(Observer* observer) { 116 observers_.AddObserver(observer); 117} 118 119void AppWindowRegistry::RemoveObserver(Observer* observer) { 120 observers_.RemoveObserver(observer); 121} 122 123AppWindowRegistry::AppWindowList AppWindowRegistry::GetAppWindowsForApp( 124 const std::string& app_id) const { 125 AppWindowList app_windows; 126 for (AppWindowList::const_iterator i = app_windows_.begin(); 127 i != app_windows_.end(); 128 ++i) { 129 if ((*i)->extension_id() == app_id) 130 app_windows.push_back(*i); 131 } 132 return app_windows; 133} 134 135void AppWindowRegistry::CloseAllAppWindowsForApp(const std::string& app_id) { 136 const AppWindowList windows = GetAppWindowsForApp(app_id); 137 for (AppWindowRegistry::const_iterator it = windows.begin(); 138 it != windows.end(); 139 ++it) { 140 (*it)->GetBaseWindow()->Close(); 141 } 142} 143 144AppWindow* AppWindowRegistry::GetAppWindowForRenderViewHost( 145 content::RenderViewHost* render_view_host) const { 146 for (AppWindowList::const_iterator i = app_windows_.begin(); 147 i != app_windows_.end(); 148 ++i) { 149 if ((*i)->web_contents()->GetRenderViewHost() == render_view_host) 150 return *i; 151 } 152 153 return NULL; 154} 155 156AppWindow* AppWindowRegistry::GetAppWindowForNativeWindow( 157 gfx::NativeWindow window) const { 158 for (AppWindowList::const_iterator i = app_windows_.begin(); 159 i != app_windows_.end(); 160 ++i) { 161 if ((*i)->GetNativeWindow() == window) 162 return *i; 163 } 164 165 return NULL; 166} 167 168AppWindow* AppWindowRegistry::GetCurrentAppWindowForApp( 169 const std::string& app_id) const { 170 AppWindow* result = NULL; 171 for (AppWindowList::const_iterator i = app_windows_.begin(); 172 i != app_windows_.end(); 173 ++i) { 174 if ((*i)->extension_id() == app_id) { 175 result = *i; 176 if (result->GetBaseWindow()->IsActive()) 177 return result; 178 } 179 } 180 181 return result; 182} 183 184AppWindow* AppWindowRegistry::GetAppWindowForAppAndKey( 185 const std::string& app_id, 186 const std::string& window_key) const { 187 AppWindow* result = NULL; 188 for (AppWindowList::const_iterator i = app_windows_.begin(); 189 i != app_windows_.end(); 190 ++i) { 191 if ((*i)->extension_id() == app_id && (*i)->window_key() == window_key) { 192 result = *i; 193 if (result->GetBaseWindow()->IsActive()) 194 return result; 195 } 196 } 197 return result; 198} 199 200bool AppWindowRegistry::HadDevToolsAttached( 201 content::RenderViewHost* render_view_host) const { 202 std::string key = GetWindowKeyForRenderViewHost(this, render_view_host); 203 return key.empty() ? false : inspected_windows_.count(key) != 0; 204} 205 206void AppWindowRegistry::OnDevToolsStateChanged( 207 content::DevToolsAgentHost* agent_host, 208 bool attached) { 209 content::WebContents* web_contents = agent_host->GetWebContents(); 210 // Ignore unrelated notifications. 211 if (!web_contents || web_contents->GetBrowserContext() != context_) 212 return; 213 214 std::string key = 215 GetWindowKeyForRenderViewHost(this, web_contents->GetRenderViewHost()); 216 if (key.empty()) 217 return; 218 219 if (attached) 220 inspected_windows_.insert(key); 221 else 222 inspected_windows_.erase(key); 223} 224 225void AppWindowRegistry::AddAppWindowToList(AppWindow* app_window) { 226 const AppWindowList::iterator it = 227 std::find(app_windows_.begin(), app_windows_.end(), app_window); 228 if (it != app_windows_.end()) 229 return; 230 app_windows_.push_back(app_window); 231} 232 233void AppWindowRegistry::BringToFront(AppWindow* app_window) { 234 const AppWindowList::iterator it = 235 std::find(app_windows_.begin(), app_windows_.end(), app_window); 236 if (it != app_windows_.end()) 237 app_windows_.erase(it); 238 app_windows_.push_front(app_window); 239} 240 241/////////////////////////////////////////////////////////////////////////////// 242// Factory boilerplate 243 244// static 245AppWindowRegistry* AppWindowRegistry::Factory::GetForBrowserContext( 246 content::BrowserContext* context, 247 bool create) { 248 return static_cast<AppWindowRegistry*>( 249 GetInstance()->GetServiceForBrowserContext(context, create)); 250} 251 252AppWindowRegistry::Factory* AppWindowRegistry::Factory::GetInstance() { 253 return Singleton<AppWindowRegistry::Factory>::get(); 254} 255 256AppWindowRegistry::Factory::Factory() 257 : BrowserContextKeyedServiceFactory( 258 "AppWindowRegistry", 259 BrowserContextDependencyManager::GetInstance()) {} 260 261AppWindowRegistry::Factory::~Factory() {} 262 263KeyedService* AppWindowRegistry::Factory::BuildServiceInstanceFor( 264 content::BrowserContext* context) const { 265 return new AppWindowRegistry(context); 266} 267 268bool AppWindowRegistry::Factory::ServiceIsCreatedWithBrowserContext() const { 269 return true; 270} 271 272bool AppWindowRegistry::Factory::ServiceIsNULLWhileTesting() const { 273 return false; 274} 275 276content::BrowserContext* AppWindowRegistry::Factory::GetBrowserContextToUse( 277 content::BrowserContext* context) const { 278 return ExtensionsBrowserClient::Get()->GetOriginalContext(context); 279} 280 281} // namespace extensions 282