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/native_app_window.h"
      6 #include "apps/shell_window.h"
      7 #include "apps/shell_window_registry.h"
      8 #include "chrome/browser/browser_process.h"
      9 #include "chrome/browser/profiles/incognito_helpers.h"
     10 #include "chrome/browser/profiles/profile_manager.h"
     11 #include "chrome/common/extensions/extension.h"
     12 #include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
     13 #include "content/public/browser/devtools_agent_host.h"
     14 #include "content/public/browser/devtools_manager.h"
     15 #include "content/public/browser/render_process_host.h"
     16 #include "content/public/browser/render_view_host.h"
     17 #include "content/public/browser/site_instance.h"
     18 #include "content/public/browser/web_contents.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(Profile* profile)
     49     : profile_(profile),
     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(Profile* profile) {
     64   return Factory::GetForProfile(profile, true /* create */);
     65 }
     66 
     67 void ShellWindowRegistry::AddShellWindow(ShellWindow* shell_window) {
     68   BringToFront(shell_window);
     69   FOR_EACH_OBSERVER(Observer, observers_, OnShellWindowAdded(shell_window));
     70 }
     71 
     72 void ShellWindowRegistry::ShellWindowIconChanged(ShellWindow* shell_window) {
     73   AddShellWindowToList(shell_window);
     74   FOR_EACH_OBSERVER(Observer, observers_,
     75                     OnShellWindowIconChanged(shell_window));
     76 }
     77 
     78 void ShellWindowRegistry::ShellWindowActivated(ShellWindow* shell_window) {
     79   BringToFront(shell_window);
     80 }
     81 
     82 void ShellWindowRegistry::RemoveShellWindow(ShellWindow* shell_window) {
     83   const ShellWindowList::iterator it = std::find(shell_windows_.begin(),
     84                                                  shell_windows_.end(),
     85                                                  shell_window);
     86   if (it != shell_windows_.end())
     87     shell_windows_.erase(it);
     88   FOR_EACH_OBSERVER(Observer, observers_, OnShellWindowRemoved(shell_window));
     89 }
     90 
     91 void ShellWindowRegistry::AddObserver(Observer* observer) {
     92   observers_.AddObserver(observer);
     93 }
     94 
     95 void ShellWindowRegistry::RemoveObserver(Observer* observer) {
     96   observers_.RemoveObserver(observer);
     97 }
     98 
     99 ShellWindowRegistry::ShellWindowList ShellWindowRegistry::GetShellWindowsForApp(
    100     const std::string& app_id) const {
    101   ShellWindowList app_windows;
    102   for (ShellWindowList::const_iterator i = shell_windows_.begin();
    103        i != shell_windows_.end(); ++i) {
    104     if ((*i)->extension_id() == app_id)
    105       app_windows.push_back(*i);
    106   }
    107   return app_windows;
    108 }
    109 
    110 void ShellWindowRegistry::CloseAllShellWindowsForApp(
    111     const std::string& app_id) {
    112   for (ShellWindowList::const_iterator i = shell_windows_.begin();
    113        i != shell_windows_.end(); ) {
    114     ShellWindow* shell_window = *(i++);
    115     if (shell_window->extension_id() == app_id)
    116       shell_window->GetBaseWindow()->Close();
    117   }
    118 }
    119 
    120 ShellWindow* ShellWindowRegistry::GetShellWindowForRenderViewHost(
    121     content::RenderViewHost* render_view_host) const {
    122   for (ShellWindowList::const_iterator i = shell_windows_.begin();
    123        i != shell_windows_.end(); ++i) {
    124     if ((*i)->web_contents()->GetRenderViewHost() == render_view_host)
    125       return *i;
    126   }
    127 
    128   return NULL;
    129 }
    130 
    131 ShellWindow* ShellWindowRegistry::GetShellWindowForNativeWindow(
    132     gfx::NativeWindow window) const {
    133   for (ShellWindowList::const_iterator i = shell_windows_.begin();
    134        i != shell_windows_.end(); ++i) {
    135     if ((*i)->GetNativeWindow() == window)
    136       return *i;
    137   }
    138 
    139   return NULL;
    140 }
    141 
    142 ShellWindow* ShellWindowRegistry::GetCurrentShellWindowForApp(
    143     const std::string& app_id) const {
    144   ShellWindow* result = NULL;
    145   for (ShellWindowList::const_iterator i = shell_windows_.begin();
    146        i != shell_windows_.end(); ++i) {
    147     if ((*i)->extension()->id() == app_id) {
    148       result = *i;
    149       if (result->GetBaseWindow()->IsActive())
    150         return result;
    151     }
    152   }
    153 
    154   return result;
    155 }
    156 
    157 ShellWindow* ShellWindowRegistry::GetShellWindowForAppAndKey(
    158     const std::string& app_id,
    159     const std::string& window_key) const {
    160   ShellWindow* result = NULL;
    161   for (ShellWindowList::const_iterator i = shell_windows_.begin();
    162        i != shell_windows_.end(); ++i) {
    163     if ((*i)->extension()->id() == app_id && (*i)->window_key() == window_key) {
    164       result = *i;
    165       if (result->GetBaseWindow()->IsActive())
    166         return result;
    167     }
    168   }
    169   return result;
    170 }
    171 
    172 bool ShellWindowRegistry::HadDevToolsAttached(
    173     content::RenderViewHost* render_view_host) const {
    174   std::string key = GetWindowKeyForRenderViewHost(this, render_view_host);
    175   return key.empty() ? false : inspected_windows_.count(key) != 0;
    176 }
    177 
    178 // static
    179 ShellWindow* ShellWindowRegistry::GetShellWindowForNativeWindowAnyProfile(
    180     gfx::NativeWindow window) {
    181   std::vector<Profile*> profiles =
    182       g_browser_process->profile_manager()->GetLoadedProfiles();
    183   for (std::vector<Profile*>::const_iterator i = profiles.begin();
    184        i != profiles.end(); ++i) {
    185     ShellWindowRegistry* registry = Factory::GetForProfile(*i,
    186                                                            false /* create */);
    187     if (!registry)
    188       continue;
    189 
    190     ShellWindow* shell_window = registry->GetShellWindowForNativeWindow(window);
    191     if (shell_window)
    192       return shell_window;
    193   }
    194 
    195   return NULL;
    196 }
    197 
    198 // static
    199 bool ShellWindowRegistry::IsShellWindowRegisteredInAnyProfile(
    200     int window_type_mask) {
    201   std::vector<Profile*> profiles =
    202       g_browser_process->profile_manager()->GetLoadedProfiles();
    203   for (std::vector<Profile*>::const_iterator i = profiles.begin();
    204        i != profiles.end(); ++i) {
    205     ShellWindowRegistry* registry = Factory::GetForProfile(*i,
    206                                                            false /* create */);
    207     if (!registry)
    208       continue;
    209 
    210     const ShellWindowList& shell_windows = registry->shell_windows();
    211     if (shell_windows.empty())
    212       continue;
    213 
    214     if (window_type_mask == 0)
    215       return true;
    216 
    217     for (const_iterator j = shell_windows.begin(); j != shell_windows.end();
    218          ++j) {
    219       if ((*j)->window_type() & window_type_mask)
    220         return true;
    221     }
    222   }
    223 
    224   return false;
    225 }
    226 
    227 void ShellWindowRegistry::OnDevToolsStateChanged(
    228     content::DevToolsAgentHost* agent_host, bool attached) {
    229   content::RenderViewHost* rvh = agent_host->GetRenderViewHost();
    230   // Ignore unrelated notifications.
    231   if (!rvh ||
    232       rvh->GetSiteInstance()->GetProcess()->GetBrowserContext() != profile_)
    233     return;
    234   std::string key = GetWindowKeyForRenderViewHost(this, rvh);
    235   if (key.empty())
    236     return;
    237 
    238   if (attached)
    239     inspected_windows_.insert(key);
    240   else
    241     inspected_windows_.erase(key);
    242 }
    243 
    244 void ShellWindowRegistry::AddShellWindowToList(ShellWindow* shell_window) {
    245   const ShellWindowList::iterator it = std::find(shell_windows_.begin(),
    246                                                  shell_windows_.end(),
    247                                                  shell_window);
    248   if (it != shell_windows_.end())
    249     return;
    250   shell_windows_.push_back(shell_window);
    251 }
    252 
    253 void ShellWindowRegistry::BringToFront(ShellWindow* shell_window) {
    254   const ShellWindowList::iterator it = std::find(shell_windows_.begin(),
    255                                                  shell_windows_.end(),
    256                                                  shell_window);
    257   if (it != shell_windows_.end())
    258     shell_windows_.erase(it);
    259   shell_windows_.push_front(shell_window);
    260 }
    261 
    262 ///////////////////////////////////////////////////////////////////////////////
    263 // Factory boilerplate
    264 
    265 // static
    266 ShellWindowRegistry* ShellWindowRegistry::Factory::GetForProfile(
    267     Profile* profile, bool create) {
    268   return static_cast<ShellWindowRegistry*>(
    269       GetInstance()->GetServiceForBrowserContext(profile, create));
    270 }
    271 
    272 ShellWindowRegistry::Factory* ShellWindowRegistry::Factory::GetInstance() {
    273   return Singleton<ShellWindowRegistry::Factory>::get();
    274 }
    275 
    276 ShellWindowRegistry::Factory::Factory()
    277     : BrowserContextKeyedServiceFactory(
    278         "ShellWindowRegistry",
    279         BrowserContextDependencyManager::GetInstance()) {
    280 }
    281 
    282 ShellWindowRegistry::Factory::~Factory() {
    283 }
    284 
    285 BrowserContextKeyedService*
    286 ShellWindowRegistry::Factory::BuildServiceInstanceFor(
    287     content::BrowserContext* profile) const {
    288   return new ShellWindowRegistry(static_cast<Profile*>(profile));
    289 }
    290 
    291 bool ShellWindowRegistry::Factory::ServiceIsCreatedWithBrowserContext() const {
    292   return true;
    293 }
    294 
    295 bool ShellWindowRegistry::Factory::ServiceIsNULLWhileTesting() const {
    296   return false;
    297 }
    298 
    299 content::BrowserContext* ShellWindowRegistry::Factory::GetBrowserContextToUse(
    300     content::BrowserContext* context) const {
    301   return chrome::GetBrowserContextRedirectedInIncognito(context);
    302 }
    303 
    304 }  // namespace extensions
    305