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 22 namespace extensions { 23 24 namespace { 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. 31 std::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 50 void AppWindowRegistry::Observer::OnAppWindowAdded(AppWindow* app_window) { 51 } 52 53 void AppWindowRegistry::Observer::OnAppWindowIconChanged( 54 AppWindow* app_window) { 55 } 56 57 void AppWindowRegistry::Observer::OnAppWindowRemoved(AppWindow* app_window) { 58 } 59 60 void AppWindowRegistry::Observer::OnAppWindowHidden(AppWindow* app_window) { 61 } 62 63 void AppWindowRegistry::Observer::OnAppWindowShown(AppWindow* app_window) { 64 } 65 66 AppWindowRegistry::Observer::~Observer() { 67 } 68 69 AppWindowRegistry::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 76 AppWindowRegistry::~AppWindowRegistry() { 77 content::DevToolsAgentHost::RemoveAgentStateCallback(devtools_callback_); 78 } 79 80 // static 81 AppWindowRegistry* AppWindowRegistry::Get(content::BrowserContext* context) { 82 return Factory::GetForBrowserContext(context, true /* create */); 83 } 84 85 void AppWindowRegistry::AddAppWindow(AppWindow* app_window) { 86 BringToFront(app_window); 87 FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowAdded(app_window)); 88 } 89 90 void AppWindowRegistry::AppWindowIconChanged(AppWindow* app_window) { 91 AddAppWindowToList(app_window); 92 FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowIconChanged(app_window)); 93 } 94 95 void AppWindowRegistry::AppWindowActivated(AppWindow* app_window) { 96 BringToFront(app_window); 97 } 98 99 void AppWindowRegistry::AppWindowHidden(AppWindow* app_window) { 100 FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowHidden(app_window)); 101 } 102 103 void AppWindowRegistry::AppWindowShown(AppWindow* app_window) { 104 FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowShown(app_window)); 105 } 106 107 void 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 115 void AppWindowRegistry::AddObserver(Observer* observer) { 116 observers_.AddObserver(observer); 117 } 118 119 void AppWindowRegistry::RemoveObserver(Observer* observer) { 120 observers_.RemoveObserver(observer); 121 } 122 123 AppWindowRegistry::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 135 void 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 144 AppWindow* 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 156 AppWindow* 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 168 AppWindow* 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 184 AppWindow* 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 200 bool 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 206 void 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 225 void 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 233 void 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 245 AppWindowRegistry* AppWindowRegistry::Factory::GetForBrowserContext( 246 content::BrowserContext* context, 247 bool create) { 248 return static_cast<AppWindowRegistry*>( 249 GetInstance()->GetServiceForBrowserContext(context, create)); 250 } 251 252 AppWindowRegistry::Factory* AppWindowRegistry::Factory::GetInstance() { 253 return Singleton<AppWindowRegistry::Factory>::get(); 254 } 255 256 AppWindowRegistry::Factory::Factory() 257 : BrowserContextKeyedServiceFactory( 258 "AppWindowRegistry", 259 BrowserContextDependencyManager::GetInstance()) {} 260 261 AppWindowRegistry::Factory::~Factory() {} 262 263 KeyedService* AppWindowRegistry::Factory::BuildServiceInstanceFor( 264 content::BrowserContext* context) const { 265 return new AppWindowRegistry(context); 266 } 267 268 bool AppWindowRegistry::Factory::ServiceIsCreatedWithBrowserContext() const { 269 return true; 270 } 271 272 bool AppWindowRegistry::Factory::ServiceIsNULLWhileTesting() const { 273 return false; 274 } 275 276 content::BrowserContext* AppWindowRegistry::Factory::GetBrowserContextToUse( 277 content::BrowserContext* context) const { 278 return ExtensionsBrowserClient::Get()->GetOriginalContext(context); 279 } 280 281 } // namespace extensions 282