Home | History | Annotate | Download | only in apps
      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.
      4 
      5 #include "apps/apps_client.h"
      6 #include "apps/shell_window.h"
      7 #include "apps/shell_window_registry.h"
      8 #include "apps/ui/native_app_window.h"
      9 #include "chrome/browser/profiles/incognito_helpers.h"
     10 #include "components/browser_context_keyed_service/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/devtools_manager.h"
     14 #include "content/public/browser/render_process_host.h"
     15 #include "content/public/browser/render_view_host.h"
     16 #include "content/public/browser/site_instance.h"
     17 #include "content/public/browser/web_contents.h"
     18 #include "extensions/common/extension.h"
     19 
     20 namespace {
     21 
     22 // Create a key that identifies a ShellWindow in a RenderViewHost across App
     23 // reloads. If the window was given an id in CreateParams, the key is the
     24 // extension id, a colon separator, and the ShellWindow's |id|. If there is no
     25 // |id|, the chrome-extension://extension-id/page.html URL will be used. If the
     26 // RenderViewHost is not for a ShellWindow, return an empty string.
     27 std::string GetWindowKeyForRenderViewHost(
     28     const apps::ShellWindowRegistry* registry,
     29     content::RenderViewHost* render_view_host) {
     30   apps::ShellWindow* shell_window =
     31       registry->GetShellWindowForRenderViewHost(render_view_host);
     32   if (!shell_window)
     33     return std::string(); // Not a ShellWindow.
     34 
     35   if (shell_window->window_key().empty())
     36     return shell_window->web_contents()->GetURL().possibly_invalid_spec();
     37 
     38   std::string key = shell_window->extension()->id();
     39   key += ':';
     40   key += shell_window->window_key();
     41   return key;
     42 }
     43 
     44 }  // namespace
     45 
     46 namespace apps {
     47 
     48 ShellWindowRegistry::ShellWindowRegistry(content::BrowserContext* context)
     49     : context_(context),
     50       devtools_callback_(base::Bind(
     51           &ShellWindowRegistry::OnDevToolsStateChanged,
     52           base::Unretained(this))) {
     53   content::DevToolsManager::GetInstance()->AddAgentStateCallback(
     54       devtools_callback_);
     55 }
     56 
     57 ShellWindowRegistry::~ShellWindowRegistry() {
     58   content::DevToolsManager::GetInstance()->RemoveAgentStateCallback(
     59       devtools_callback_);
     60 }
     61 
     62 // static
     63 ShellWindowRegistry* ShellWindowRegistry::Get(
     64     content::BrowserContext* context) {
     65   return Factory::GetForBrowserContext(context, true /* create */);
     66 }
     67 
     68 void ShellWindowRegistry::AddShellWindow(ShellWindow* shell_window) {
     69   BringToFront(shell_window);
     70   FOR_EACH_OBSERVER(Observer, observers_, OnShellWindowAdded(shell_window));
     71 }
     72 
     73 void ShellWindowRegistry::ShellWindowIconChanged(ShellWindow* shell_window) {
     74   AddShellWindowToList(shell_window);
     75   FOR_EACH_OBSERVER(Observer, observers_,
     76                     OnShellWindowIconChanged(shell_window));
     77 }
     78 
     79 void ShellWindowRegistry::ShellWindowActivated(ShellWindow* shell_window) {
     80   BringToFront(shell_window);
     81 }
     82 
     83 void ShellWindowRegistry::RemoveShellWindow(ShellWindow* shell_window) {
     84   const ShellWindowList::iterator it = std::find(shell_windows_.begin(),
     85                                                  shell_windows_.end(),
     86                                                  shell_window);
     87   if (it != shell_windows_.end())
     88     shell_windows_.erase(it);
     89   FOR_EACH_OBSERVER(Observer, observers_, OnShellWindowRemoved(shell_window));
     90 }
     91 
     92 void ShellWindowRegistry::AddObserver(Observer* observer) {
     93   observers_.AddObserver(observer);
     94 }
     95 
     96 void ShellWindowRegistry::RemoveObserver(Observer* observer) {
     97   observers_.RemoveObserver(observer);
     98 }
     99 
    100 ShellWindowRegistry::ShellWindowList ShellWindowRegistry::GetShellWindowsForApp(
    101     const std::string& app_id) const {
    102   ShellWindowList app_windows;
    103   for (ShellWindowList::const_iterator i = shell_windows_.begin();
    104        i != shell_windows_.end(); ++i) {
    105     if ((*i)->extension_id() == app_id)
    106       app_windows.push_back(*i);
    107   }
    108   return app_windows;
    109 }
    110 
    111 void ShellWindowRegistry::CloseAllShellWindowsForApp(
    112     const std::string& app_id) {
    113   for (ShellWindowList::const_iterator i = shell_windows_.begin();
    114        i != shell_windows_.end(); ) {
    115     ShellWindow* shell_window = *(i++);
    116     if (shell_window->extension_id() == app_id)
    117       shell_window->GetBaseWindow()->Close();
    118   }
    119 }
    120 
    121 ShellWindow* ShellWindowRegistry::GetShellWindowForRenderViewHost(
    122     content::RenderViewHost* render_view_host) const {
    123   for (ShellWindowList::const_iterator i = shell_windows_.begin();
    124        i != shell_windows_.end(); ++i) {
    125     if ((*i)->web_contents()->GetRenderViewHost() == render_view_host)
    126       return *i;
    127   }
    128 
    129   return NULL;
    130 }
    131 
    132 ShellWindow* ShellWindowRegistry::GetShellWindowForNativeWindow(
    133     gfx::NativeWindow window) const {
    134   for (ShellWindowList::const_iterator i = shell_windows_.begin();
    135        i != shell_windows_.end(); ++i) {
    136     if ((*i)->GetNativeWindow() == window)
    137       return *i;
    138   }
    139 
    140   return NULL;
    141 }
    142 
    143 ShellWindow* ShellWindowRegistry::GetCurrentShellWindowForApp(
    144     const std::string& app_id) const {
    145   ShellWindow* result = NULL;
    146   for (ShellWindowList::const_iterator i = shell_windows_.begin();
    147        i != shell_windows_.end(); ++i) {
    148     if ((*i)->extension()->id() == app_id) {
    149       result = *i;
    150       if (result->GetBaseWindow()->IsActive())
    151         return result;
    152     }
    153   }
    154 
    155   return result;
    156 }
    157 
    158 ShellWindow* ShellWindowRegistry::GetShellWindowForAppAndKey(
    159     const std::string& app_id,
    160     const std::string& window_key) const {
    161   ShellWindow* result = NULL;
    162   for (ShellWindowList::const_iterator i = shell_windows_.begin();
    163        i != shell_windows_.end(); ++i) {
    164     if ((*i)->extension()->id() == app_id && (*i)->window_key() == window_key) {
    165       result = *i;
    166       if (result->GetBaseWindow()->IsActive())
    167         return result;
    168     }
    169   }
    170   return result;
    171 }
    172 
    173 bool ShellWindowRegistry::HadDevToolsAttached(
    174     content::RenderViewHost* render_view_host) const {
    175   std::string key = GetWindowKeyForRenderViewHost(this, render_view_host);
    176   return key.empty() ? false : inspected_windows_.count(key) != 0;
    177 }
    178 
    179 // static
    180 ShellWindow* ShellWindowRegistry::GetShellWindowForNativeWindowAnyProfile(
    181     gfx::NativeWindow window) {
    182   std::vector<content::BrowserContext*> contexts =
    183       AppsClient::Get()->GetLoadedBrowserContexts();
    184   for (std::vector<content::BrowserContext*>::const_iterator i =
    185            contexts.begin();
    186        i != contexts.end(); ++i) {
    187     ShellWindowRegistry* registry = Factory::GetForBrowserContext(
    188         *i, false /* create */);
    189     if (!registry)
    190       continue;
    191 
    192     ShellWindow* shell_window = registry->GetShellWindowForNativeWindow(window);
    193     if (shell_window)
    194       return shell_window;
    195   }
    196 
    197   return NULL;
    198 }
    199 
    200 // static
    201 bool ShellWindowRegistry::IsShellWindowRegisteredInAnyProfile(
    202     int window_type_mask) {
    203   std::vector<content::BrowserContext*> contexts =
    204       AppsClient::Get()->GetLoadedBrowserContexts();
    205   for (std::vector<content::BrowserContext*>::const_iterator i =
    206            contexts.begin();
    207        i != contexts.end(); ++i) {
    208     ShellWindowRegistry* registry = Factory::GetForBrowserContext(
    209         *i, false /* create */);
    210     if (!registry)
    211       continue;
    212 
    213     const ShellWindowList& shell_windows = registry->shell_windows();
    214     if (shell_windows.empty())
    215       continue;
    216 
    217     if (window_type_mask == 0)
    218       return true;
    219 
    220     for (const_iterator j = shell_windows.begin(); j != shell_windows.end();
    221          ++j) {
    222       if ((*j)->window_type() & window_type_mask)
    223         return true;
    224     }
    225   }
    226 
    227   return false;
    228 }
    229 
    230 void ShellWindowRegistry::OnDevToolsStateChanged(
    231     content::DevToolsAgentHost* agent_host, bool attached) {
    232   content::RenderViewHost* rvh = agent_host->GetRenderViewHost();
    233   // Ignore unrelated notifications.
    234   if (!rvh ||
    235       rvh->GetSiteInstance()->GetProcess()->GetBrowserContext() != context_)
    236     return;
    237 
    238   std::string key = GetWindowKeyForRenderViewHost(this, rvh);
    239   if (key.empty())
    240     return;
    241 
    242   if (attached)
    243     inspected_windows_.insert(key);
    244   else
    245     inspected_windows_.erase(key);
    246 }
    247 
    248 void ShellWindowRegistry::AddShellWindowToList(ShellWindow* shell_window) {
    249   const ShellWindowList::iterator it = std::find(shell_windows_.begin(),
    250                                                  shell_windows_.end(),
    251                                                  shell_window);
    252   if (it != shell_windows_.end())
    253     return;
    254   shell_windows_.push_back(shell_window);
    255 }
    256 
    257 void ShellWindowRegistry::BringToFront(ShellWindow* shell_window) {
    258   const ShellWindowList::iterator it = std::find(shell_windows_.begin(),
    259                                                  shell_windows_.end(),
    260                                                  shell_window);
    261   if (it != shell_windows_.end())
    262     shell_windows_.erase(it);
    263   shell_windows_.push_front(shell_window);
    264 }
    265 
    266 ///////////////////////////////////////////////////////////////////////////////
    267 // Factory boilerplate
    268 
    269 // static
    270 ShellWindowRegistry* ShellWindowRegistry::Factory::GetForBrowserContext(
    271     content::BrowserContext* context, bool create) {
    272   return static_cast<ShellWindowRegistry*>(
    273       GetInstance()->GetServiceForBrowserContext(context, create));
    274 }
    275 
    276 ShellWindowRegistry::Factory* ShellWindowRegistry::Factory::GetInstance() {
    277   return Singleton<ShellWindowRegistry::Factory>::get();
    278 }
    279 
    280 ShellWindowRegistry::Factory::Factory()
    281     : BrowserContextKeyedServiceFactory(
    282         "ShellWindowRegistry",
    283         BrowserContextDependencyManager::GetInstance()) {
    284 }
    285 
    286 ShellWindowRegistry::Factory::~Factory() {
    287 }
    288 
    289 BrowserContextKeyedService*
    290 ShellWindowRegistry::Factory::BuildServiceInstanceFor(
    291     content::BrowserContext* context) const {
    292   return new ShellWindowRegistry(context);
    293 }
    294 
    295 bool ShellWindowRegistry::Factory::ServiceIsCreatedWithBrowserContext() const {
    296   return true;
    297 }
    298 
    299 bool ShellWindowRegistry::Factory::ServiceIsNULLWhileTesting() const {
    300   return false;
    301 }
    302 
    303 content::BrowserContext* ShellWindowRegistry::Factory::GetBrowserContextToUse(
    304     content::BrowserContext* context) const {
    305   return chrome::GetBrowserContextRedirectedInIncognito(context);
    306 }
    307 
    308 }  // namespace extensions
    309