Home | History | Annotate | Download | only in apps
      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 "apps/app_window.h"
      6 #include "apps/app_window_registry.h"
      7 #include "apps/apps_client.h"
      8 #include "apps/ui/native_app_window.h"
      9 #include "components/keyed_service/content/browser_context_dependency_manager.h"
     10 #include "content/public/browser/browser_context.h"
     11 #include "content/public/browser/devtools_agent_host.h"
     12 #include "content/public/browser/devtools_manager.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/extensions_browser_client.h"
     18 #include "extensions/common/extension.h"
     19 
     20 namespace {
     21 
     22 // Create a key that identifies a AppWindow 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 AppWindow'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 AppWindow, return an empty string.
     27 std::string GetWindowKeyForRenderViewHost(
     28     const apps::AppWindowRegistry* registry,
     29     content::RenderViewHost* render_view_host) {
     30   apps::AppWindow* app_window =
     31       registry->GetAppWindowForRenderViewHost(render_view_host);
     32   if (!app_window)
     33     return std::string();  // Not a AppWindow.
     34 
     35   if (app_window->window_key().empty())
     36     return app_window->web_contents()->GetURL().possibly_invalid_spec();
     37 
     38   std::string key = app_window->extension_id();
     39   key += ':';
     40   key += app_window->window_key();
     41   return key;
     42 }
     43 
     44 }  // namespace
     45 
     46 namespace apps {
     47 
     48 void AppWindowRegistry::Observer::OnAppWindowAdded(AppWindow* app_window) {
     49 }
     50 
     51 void AppWindowRegistry::Observer::OnAppWindowIconChanged(
     52     AppWindow* app_window) {
     53 }
     54 
     55 void AppWindowRegistry::Observer::OnAppWindowRemoved(AppWindow* app_window) {
     56 }
     57 
     58 void AppWindowRegistry::Observer::OnAppWindowHidden(AppWindow* app_window) {
     59 }
     60 
     61 void AppWindowRegistry::Observer::OnAppWindowShown(AppWindow* app_window) {
     62 }
     63 
     64 AppWindowRegistry::Observer::~Observer() {
     65 }
     66 
     67 AppWindowRegistry::AppWindowRegistry(content::BrowserContext* context)
     68     : context_(context),
     69       devtools_callback_(base::Bind(&AppWindowRegistry::OnDevToolsStateChanged,
     70                                     base::Unretained(this))) {
     71   content::DevToolsManager::GetInstance()->AddAgentStateCallback(
     72       devtools_callback_);
     73 }
     74 
     75 AppWindowRegistry::~AppWindowRegistry() {
     76   content::DevToolsManager::GetInstance()->RemoveAgentStateCallback(
     77       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 // static
    207 AppWindow* AppWindowRegistry::GetAppWindowForNativeWindowAnyProfile(
    208     gfx::NativeWindow window) {
    209   std::vector<content::BrowserContext*> contexts =
    210       AppsClient::Get()->GetLoadedBrowserContexts();
    211   for (std::vector<content::BrowserContext*>::const_iterator i =
    212            contexts.begin();
    213        i != contexts.end();
    214        ++i) {
    215     AppWindowRegistry* registry =
    216         Factory::GetForBrowserContext(*i, false /* create */);
    217     if (!registry)
    218       continue;
    219 
    220     AppWindow* app_window = registry->GetAppWindowForNativeWindow(window);
    221     if (app_window)
    222       return app_window;
    223   }
    224 
    225   return NULL;
    226 }
    227 
    228 // static
    229 bool AppWindowRegistry::IsAppWindowRegisteredInAnyProfile(
    230     int window_type_mask) {
    231   std::vector<content::BrowserContext*> contexts =
    232       AppsClient::Get()->GetLoadedBrowserContexts();
    233   for (std::vector<content::BrowserContext*>::const_iterator i =
    234            contexts.begin();
    235        i != contexts.end();
    236        ++i) {
    237     AppWindowRegistry* registry =
    238         Factory::GetForBrowserContext(*i, false /* create */);
    239     if (!registry)
    240       continue;
    241 
    242     const AppWindowList& app_windows = registry->app_windows();
    243     if (app_windows.empty())
    244       continue;
    245 
    246     if (window_type_mask == 0)
    247       return true;
    248 
    249     for (const_iterator j = app_windows.begin(); j != app_windows.end(); ++j) {
    250       if ((*j)->window_type() & window_type_mask)
    251         return true;
    252     }
    253   }
    254 
    255   return false;
    256 }
    257 
    258 // static
    259 void AppWindowRegistry::CloseAllAppWindows() {
    260   std::vector<content::BrowserContext*> contexts =
    261       AppsClient::Get()->GetLoadedBrowserContexts();
    262   for (std::vector<content::BrowserContext*>::const_iterator i =
    263            contexts.begin();
    264        i != contexts.end();
    265        ++i) {
    266     AppWindowRegistry* registry =
    267         Factory::GetForBrowserContext(*i, false /* create */);
    268     if (!registry)
    269       continue;
    270 
    271     while (!registry->app_windows().empty())
    272       registry->app_windows().front()->GetBaseWindow()->Close();
    273   }
    274 }
    275 
    276 void AppWindowRegistry::OnDevToolsStateChanged(
    277     content::DevToolsAgentHost* agent_host,
    278     bool attached) {
    279   content::RenderViewHost* rvh = agent_host->GetRenderViewHost();
    280   // Ignore unrelated notifications.
    281   if (!rvh ||
    282       rvh->GetSiteInstance()->GetProcess()->GetBrowserContext() != context_)
    283     return;
    284 
    285   std::string key = GetWindowKeyForRenderViewHost(this, rvh);
    286   if (key.empty())
    287     return;
    288 
    289   if (attached)
    290     inspected_windows_.insert(key);
    291   else
    292     inspected_windows_.erase(key);
    293 }
    294 
    295 void AppWindowRegistry::AddAppWindowToList(AppWindow* app_window) {
    296   const AppWindowList::iterator it =
    297       std::find(app_windows_.begin(), app_windows_.end(), app_window);
    298   if (it != app_windows_.end())
    299     return;
    300   app_windows_.push_back(app_window);
    301 }
    302 
    303 void AppWindowRegistry::BringToFront(AppWindow* app_window) {
    304   const AppWindowList::iterator it =
    305       std::find(app_windows_.begin(), app_windows_.end(), app_window);
    306   if (it != app_windows_.end())
    307     app_windows_.erase(it);
    308   app_windows_.push_front(app_window);
    309 }
    310 
    311 ///////////////////////////////////////////////////////////////////////////////
    312 // Factory boilerplate
    313 
    314 // static
    315 AppWindowRegistry* AppWindowRegistry::Factory::GetForBrowserContext(
    316     content::BrowserContext* context,
    317     bool create) {
    318   return static_cast<AppWindowRegistry*>(
    319       GetInstance()->GetServiceForBrowserContext(context, create));
    320 }
    321 
    322 AppWindowRegistry::Factory* AppWindowRegistry::Factory::GetInstance() {
    323   return Singleton<AppWindowRegistry::Factory>::get();
    324 }
    325 
    326 AppWindowRegistry::Factory::Factory()
    327     : BrowserContextKeyedServiceFactory(
    328           "AppWindowRegistry",
    329           BrowserContextDependencyManager::GetInstance()) {}
    330 
    331 AppWindowRegistry::Factory::~Factory() {}
    332 
    333 KeyedService* AppWindowRegistry::Factory::BuildServiceInstanceFor(
    334     content::BrowserContext* context) const {
    335   return new AppWindowRegistry(context);
    336 }
    337 
    338 bool AppWindowRegistry::Factory::ServiceIsCreatedWithBrowserContext() const {
    339   return true;
    340 }
    341 
    342 bool AppWindowRegistry::Factory::ServiceIsNULLWhileTesting() const {
    343   return false;
    344 }
    345 
    346 content::BrowserContext* AppWindowRegistry::Factory::GetBrowserContextToUse(
    347     content::BrowserContext* context) const {
    348   return extensions::ExtensionsBrowserClient::Get()->GetOriginalContext(
    349       context);
    350 }
    351 
    352 }  // namespace apps
    353