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