Home | History | Annotate | Download | only in content
      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 "athena/content/app_activity_registry.h"
      6 
      7 #include "athena/activity/public/activity_manager.h"
      8 #include "athena/content/app_activity.h"
      9 #include "athena/content/app_activity_proxy.h"
     10 #include "athena/content/public/app_registry.h"
     11 #include "athena/extensions/public/extensions_delegate.h"
     12 #include "athena/resource_manager/public/resource_manager.h"
     13 #include "athena/wm/public/window_list_provider.h"
     14 #include "athena/wm/public/window_manager.h"
     15 #include "base/bind.h"
     16 #include "base/location.h"
     17 #include "base/single_thread_task_runner.h"
     18 #include "base/thread_task_runner_handle.h"
     19 #include "ui/aura/window.h"
     20 #include "ui/views/view.h"
     21 #include "ui/views/widget/widget.h"
     22 
     23 namespace athena {
     24 
     25 AppActivityRegistry::AppActivityRegistry(
     26     const std::string& app_id,
     27     content::BrowserContext* browser_context) :
     28       app_id_(app_id),
     29       browser_context_(browser_context),
     30       unloaded_activity_proxy_(NULL) {}
     31 
     32 AppActivityRegistry::~AppActivityRegistry() {
     33   CHECK(activity_list_.empty());
     34   if (unloaded_activity_proxy_)
     35     ActivityManager::Get()->RemoveActivity(unloaded_activity_proxy_);
     36   DCHECK(!unloaded_activity_proxy_);
     37 }
     38 
     39 void AppActivityRegistry::RegisterAppActivity(AppActivity* app_activity) {
     40   // The same window should never be added twice.
     41   CHECK(std::find(activity_list_.begin(),
     42                   activity_list_.end(),
     43                   app_activity) == activity_list_.end());
     44   activity_list_.push_back(app_activity);
     45 }
     46 
     47 void AppActivityRegistry::UnregisterAppActivity(AppActivity* app_activity) {
     48   // It is possible that a detach gets called without ever being attached.
     49   std::vector<AppActivity*>::iterator it =
     50       std::find(activity_list_.begin(), activity_list_.end(), app_activity);
     51   if (it == activity_list_.end())
     52     return;
     53 
     54   activity_list_.erase(it);
     55   // When the last window gets destroyed and there is no proxy to restart, we
     56   // delete ourselves.
     57   if (activity_list_.empty() && !unloaded_activity_proxy_) {
     58     AppRegistry::Get()->RemoveAppActivityRegistry(this);
     59     // after this call this object should be gone.
     60   }
     61 }
     62 
     63 AppActivity* AppActivityRegistry::GetAppActivityAt(size_t index) {
     64   if (index >= activity_list_.size())
     65     return NULL;
     66   return activity_list_[index];
     67 }
     68 
     69 void AppActivityRegistry::Unload() {
     70   CHECK(!unloaded_activity_proxy_);
     71   DCHECK(!activity_list_.empty());
     72   // In order to allow an entire application to unload we require that all of
     73   // its activities are marked as unloaded.
     74   for (std::vector<AppActivity*>::iterator it = activity_list_.begin();
     75        it != activity_list_.end(); ++it) {
     76     if ((*it)->GetCurrentState() != Activity::ACTIVITY_UNLOADED)
     77       return;
     78   }
     79 
     80   // Create an activity proxy which can be used to re-activate the app. Insert
     81   // the proxy then into the activity stream at the location of the (newest)
     82   // current activity.
     83   unloaded_activity_proxy_ = new AppActivityProxy(GetMruActivity(), this);
     84   ActivityManager::Get()->AddActivity(unloaded_activity_proxy_);
     85 
     86   // This function can be called through an observer call. When that happens,
     87   // several activities will be closed / started. That can then cause a crash.
     88   // We postpone therefore the activity destruction till after the observer is
     89   // done.
     90   base::ThreadTaskRunnerHandle::Get()->PostTask(
     91       FROM_HERE,
     92       base::Bind(&AppActivityRegistry::DelayedUnload, base::Unretained(this)));
     93 }
     94 
     95 void AppActivityRegistry::ProxyDestroyed(AppActivityProxy* proxy) {
     96   DCHECK_EQ(unloaded_activity_proxy_, proxy);
     97   unloaded_activity_proxy_ = NULL;
     98   if (activity_list_.empty()) {
     99     AppRegistry::Get()->RemoveAppActivityRegistry(this);
    100     // |This| is gone now.
    101   }
    102 }
    103 
    104 void AppActivityRegistry::RestartApplication(AppActivityProxy* proxy) {
    105   DCHECK_EQ(unloaded_activity_proxy_, proxy);
    106   // Restart the application. Note that the first created app window will make
    107   // sure that the proxy gets deleted - after - the new activity got moved
    108   // to the proxies activity location.
    109   ExtensionsDelegate::Get(browser_context_)->LaunchApp(app_id_);
    110 }
    111 
    112 void AppActivityRegistry::DelayedUnload() {
    113   if (!ExtensionsDelegate::Get(browser_context_)->UnloadApp(app_id_)) {
    114     while(!activity_list_.empty())
    115       Activity::Delete(activity_list_.back());
    116   }
    117 }
    118 
    119 AppActivity* AppActivityRegistry::GetMruActivity() {
    120   DCHECK(activity_list_.size());
    121   WindowListProvider* window_list_provider =
    122       WindowManager::Get()->GetWindowListProvider();
    123   const aura::Window::Windows& children =
    124       window_list_provider->GetWindowList();
    125   // Find the first window in the container which is part of the application.
    126   for (aura::Window::Windows::const_iterator child_iterator = children.begin();
    127       child_iterator != children.end(); ++child_iterator) {
    128     for (std::vector<AppActivity*>::iterator app_iterator =
    129              activity_list_.begin();
    130          app_iterator != activity_list_.end(); ++app_iterator) {
    131       if (*child_iterator == (*app_iterator)->GetWindow())
    132         return *app_iterator;
    133     }
    134   }
    135   NOTREACHED() << "The application does not get tracked by the mru list";
    136   return NULL;
    137 }
    138 
    139 }  // namespace athena
    140