app_activity_registry.cc revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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_content_control_delegate.h"
11#include "athena/content/public/app_registry.h"
12#include "ui/aura/window.h"
13#include "ui/views/view.h"
14#include "ui/views/widget/widget.h"
15
16namespace athena {
17
18AppActivityRegistry::AppActivityRegistry(
19    const std::string& app_id,
20    content::BrowserContext* browser_context) :
21      app_id_(app_id),
22      browser_context_(browser_context),
23      unloaded_activity_proxy_(NULL) {}
24
25AppActivityRegistry::~AppActivityRegistry() {
26  CHECK(activity_list_.empty());
27  if (unloaded_activity_proxy_)
28    ActivityManager::Get()->RemoveActivity(unloaded_activity_proxy_);
29  DCHECK(!unloaded_activity_proxy_);
30}
31
32void AppActivityRegistry::RegisterAppActivity(AppActivity* app_activity) {
33  if (unloaded_activity_proxy_) {
34    // Since we add an application window, the activity isn't unloaded anymore.
35    ActivityManager::Get()->RemoveActivity(unloaded_activity_proxy_);
36    // With the removal the object should have been deleted and we should have
37    // been informed of the object's destruction.
38    DCHECK(!unloaded_activity_proxy_);
39  }
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
47void 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
63AppActivity* AppActivityRegistry::GetAppActivityAt(size_t index) {
64  if (index >= activity_list_.size())
65    return NULL;
66  return activity_list_[index];
67}
68
69void AppActivityRegistry::Unload() {
70  CHECK(!unloaded_activity_proxy_);
71  DCHECK(!activity_list_.empty());
72
73  // In order to allow an entire application to unload we require that all of
74  // its activities are marked as unloaded.
75  for (std::vector<AppActivity*>::iterator it = activity_list_.begin();
76       it != activity_list_.end(); ++it) {
77    if ((*it)->GetCurrentState() != Activity::ACTIVITY_UNLOADED)
78      return;
79  }
80
81  // Create an activity proxy which can be used to re-activate the app. Insert
82  // the proxy then into the activity stream at the location of the (newest)
83  // current activity.
84  unloaded_activity_proxy_ =
85      new AppActivityProxy(activity_list_[0]->GetActivityViewModel(), this);
86  ActivityManager::Get()->AddActivity(unloaded_activity_proxy_);
87  // The new activity should be in the place of the most recently used app
88  // window. To get it there, we get the most recently used application window
89  // and place the proxy activities window in front or behind, so that when the
90  // activity disappears it takes its place.
91  MoveBeforeMruApplicationWindow(unloaded_activity_proxy_->GetWindow());
92
93  // Unload the application. This operation will be asynchronous.
94  if (!AppRegistry::Get()->GetDelegate()->UnloadApplication(app_id_,
95                                                            browser_context_)) {
96    while(!activity_list_.empty())
97      delete activity_list_.back();
98  }
99}
100
101void AppActivityRegistry::ProxyDestroyed(AppActivityProxy* proxy) {
102  DCHECK_EQ(unloaded_activity_proxy_, proxy);
103  unloaded_activity_proxy_ = NULL;
104  if (activity_list_.empty()) {
105    AppRegistry::Get()->RemoveAppActivityRegistry(this);
106    // |This| is gone now.
107  }
108}
109
110void AppActivityRegistry::RestartApplication(AppActivityProxy* proxy) {
111  DCHECK_EQ(unloaded_activity_proxy_, proxy);
112  // Restart the application.
113  AppRegistry::Get()->GetDelegate()->RestartApplication(app_id_,
114                                                        browser_context_);
115  // Remove the activity from the Activity manager.
116  ActivityManager::Get()->RemoveActivity(unloaded_activity_proxy_);
117  delete unloaded_activity_proxy_;  // Will call ProxyDestroyed.
118  // After this call |this| might be gone if the app did not open a window yet.
119}
120
121void AppActivityRegistry::MoveBeforeMruApplicationWindow(aura::Window* window) {
122  DCHECK(activity_list_.size());
123  // TODO(skuhne): This needs to be changed to some kind of delegate which
124  // resides in the window manager.
125  const aura::Window::Windows children =
126      activity_list_[0]->GetWindow()->parent()->children();;
127  // Find the first window in the container which is part of the application.
128  for (aura::Window::Windows::const_iterator child_iterator = children.begin();
129      child_iterator != children.end(); ++child_iterator) {
130    for (std::vector<AppActivity*>::iterator app_iterator =
131             activity_list_.begin();
132         app_iterator != activity_list_.end(); ++app_iterator) {
133      if (*child_iterator == (*app_iterator)->GetWindow()) {
134        // Since "StackChildBelow" does not change the order if the window
135        // if the window is below - but not immediately behind - the target
136        // window, we re-stack both ways.
137        window->parent()->StackChildBelow(window, *child_iterator);
138        window->parent()->StackChildBelow(*child_iterator, window);
139        return;
140      }
141    }
142  }
143  NOTREACHED() << "The application does not get tracked by the mru list";
144}
145
146}  // namespace athena
147