summaryrefslogtreecommitdiffstats
path: root/athena/content/app_activity_registry.cc
blob: 99814377846bd822d72ea3f1883beac2fea0fe29 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "athena/content/app_activity_registry.h"

#include "athena/activity/public/activity_manager.h"
#include "athena/content/app_activity.h"
#include "athena/content/app_activity_proxy.h"
#include "athena/content/public/app_registry.h"
#include "athena/extensions/public/extensions_delegate.h"
#include "athena/resource_manager/public/resource_manager.h"
#include "athena/wm/public/window_list_provider.h"
#include "athena/wm/public/window_manager.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
#include "ui/aura/window.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"

namespace athena {

AppActivityRegistry::AppActivityRegistry(
    const std::string& app_id,
    content::BrowserContext* browser_context) :
      app_id_(app_id),
      browser_context_(browser_context),
      unloaded_activity_proxy_(NULL) {}

AppActivityRegistry::~AppActivityRegistry() {
  CHECK(activity_list_.empty());
  if (unloaded_activity_proxy_)
    ActivityManager::Get()->RemoveActivity(unloaded_activity_proxy_);
  DCHECK(!unloaded_activity_proxy_);
}

void AppActivityRegistry::RegisterAppActivity(AppActivity* app_activity) {
  // The same window should never be added twice.
  CHECK(std::find(activity_list_.begin(),
                  activity_list_.end(),
                  app_activity) == activity_list_.end());
  activity_list_.push_back(app_activity);
}

void AppActivityRegistry::UnregisterAppActivity(AppActivity* app_activity) {
  // It is possible that a detach gets called without ever being attached.
  std::vector<AppActivity*>::iterator it =
      std::find(activity_list_.begin(), activity_list_.end(), app_activity);
  if (it == activity_list_.end())
    return;

  activity_list_.erase(it);
  // When the last window gets destroyed and there is no proxy to restart, we
  // delete ourselves.
  if (activity_list_.empty() && !unloaded_activity_proxy_) {
    AppRegistry::Get()->RemoveAppActivityRegistry(this);
    // after this call this object should be gone.
  }
}

AppActivity* AppActivityRegistry::GetAppActivityAt(size_t index) {
  if (index >= activity_list_.size())
    return NULL;
  return activity_list_[index];
}

void AppActivityRegistry::Unload() {
  CHECK(!unloaded_activity_proxy_);
  DCHECK(!activity_list_.empty());
  // In order to allow an entire application to unload we require that all of
  // its activities are marked as unloaded.
  for (std::vector<AppActivity*>::iterator it = activity_list_.begin();
       it != activity_list_.end(); ++it) {
    if ((*it)->GetCurrentState() != Activity::ACTIVITY_UNLOADED)
      return;
  }

  // Create an activity proxy which can be used to re-activate the app. Insert
  // the proxy then into the activity stream at the location of the (newest)
  // current activity.
  unloaded_activity_proxy_ = new AppActivityProxy(GetMruActivity(), this);
  ActivityManager::Get()->AddActivity(unloaded_activity_proxy_);

  // This function can be called through an observer call. When that happens,
  // several activities will be closed / started. That can then cause a crash.
  // We postpone therefore the activity destruction till after the observer is
  // done.
  base::ThreadTaskRunnerHandle::Get()->PostTask(
      FROM_HERE,
      base::Bind(&AppActivityRegistry::DelayedUnload, base::Unretained(this)));
}

void AppActivityRegistry::ProxyDestroyed(AppActivityProxy* proxy) {
  DCHECK_EQ(unloaded_activity_proxy_, proxy);
  unloaded_activity_proxy_ = NULL;
  if (activity_list_.empty()) {
    AppRegistry::Get()->RemoveAppActivityRegistry(this);
    // |This| is gone now.
  }
}

void AppActivityRegistry::RestartApplication(AppActivityProxy* proxy) {
  DCHECK_EQ(unloaded_activity_proxy_, proxy);
  // Restart the application. Note that the first created app window will make
  // sure that the proxy gets deleted - after - the new activity got moved
  // to the proxies activity location.
  ExtensionsDelegate::Get(browser_context_)->LaunchApp(app_id_);
}

void AppActivityRegistry::DelayedUnload() {
  if (!ExtensionsDelegate::Get(browser_context_)->UnloadApp(app_id_)) {
    while(!activity_list_.empty())
      Activity::Delete(activity_list_.back());
  }
}

AppActivity* AppActivityRegistry::GetMruActivity() {
  DCHECK(activity_list_.size());
  WindowListProvider* window_list_provider =
      WindowManager::Get()->GetWindowListProvider();
  const aura::Window::Windows& children =
      window_list_provider->GetWindowList();
  // Find the first window in the container which is part of the application.
  for (aura::Window::Windows::const_iterator child_iterator = children.begin();
      child_iterator != children.end(); ++child_iterator) {
    for (std::vector<AppActivity*>::iterator app_iterator =
             activity_list_.begin();
         app_iterator != activity_list_.end(); ++app_iterator) {
      if (*child_iterator == (*app_iterator)->GetWindow())
        return *app_iterator;
    }
  }
  NOTREACHED() << "The application does not get tracked by the mru list";
  return NULL;
}

}  // namespace athena