Skip to content

Commit

Permalink
Athena: Adding basic resource management framework (un-/re-loading) o…
Browse files Browse the repository at this point in the history
…f V2 applications

Functionality:

The |AppRegistry| has for each running application an |AppActivityRegistry|.

The |AppActivityRegistry| knows all activities associated with the application it represents.
It can furthermore shut the app entirely down upon resource manager request. It will then create
an |AppActivityProxy| for the overview mode which shows a placeholder for an unloaded app. This
placeholder can then ask the |AppActivityRegistry| to restart the application again.

A shutdown request for the application is only performed when all activities were marked for
UNLOAD.

If there were multiple activities upon shutdown for one app, the app has to take care of
re-creating all windows and thus re-creating all activities. Since an activity match cannot
be performed, the |AppActivityProxy| will only be shown once and it will show in the location
of the most recently used activity of that app. If we later on find an app which really uses
multiple windows and it is imperative to keep the history for all of them tact & the app is
recreating them properly, (a lot of if's) we can revisit the single |AppActivityProxy| and
try to address it in a cleaner way, but at this time that seems rather un-useful since it is
not known if required.

BUG=388085
TEST=AppActivityTest.*

Review URL: https://codereview.chromium.org/477523002

Cr-Commit-Position: refs/heads/master@{#291221}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@291221 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
skuhne@chromium.org committed Aug 21, 2014
1 parent 65582b3 commit 23e145e
Show file tree
Hide file tree
Showing 22 changed files with 1,287 additions and 23 deletions.
8 changes: 8 additions & 0 deletions athena/activity/public/activity.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@

#include "athena/athena_export.h"

namespace aura {
class Window;
}

namespace athena {

class ActivityViewModel;
Expand Down Expand Up @@ -72,6 +76,10 @@ class ATHENA_EXPORT Activity {

// Returns the current media state.
virtual ActivityMediaState GetMediaState() = 0;

// Returns the window for the activity. This can be used to determine the
// stacking order of this activity against others.
virtual aura::Window* GetWindow() = 0;
};

} // namespace athena
Expand Down
32 changes: 26 additions & 6 deletions athena/athena.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -115,22 +115,39 @@
'ATHENA_IMPLEMENTATION',
],
'sources': [
'content/app_activity.cc',
'content/app_activity.h',
'content/app_activity_proxy.cc',
'content/app_activity_proxy.h',
'content/app_activity_registry.cc',
'content/app_activity_registry.h',
'content/app_registry_impl.cc',
'content/content_activity_factory.cc',
'content/content_app_model_builder.cc',
'content/public/app_registry.h',
'content/public/content_activity_factory.h',
'content/public/content_app_model_builder.h',
'content/public/web_contents_view_delegate_creator.h',
'content/content_activity_factory.cc',
'content/content_app_model_builder.cc',
'content/app_activity.h',
'content/app_activity.cc',
'content/render_view_context_menu_impl.cc',
'content/render_view_context_menu_impl.h',
'content/web_activity.h',
'content/web_activity.cc',
'content/web_activity.h',
'content/web_contents_view_delegate_factory_impl.cc',
'virtual_keyboard/public/virtual_keyboard_manager.h',
'virtual_keyboard/virtual_keyboard_manager_impl.cc',
],
},
{
'target_name': 'athena_content_support_lib',
'type': 'static_library',
'dependencies': [
'../content/content.gyp:content_browser',
],
'sources': [
'content/delegate/app_content_control_delegate_impl.cc',
'content/public/app_content_control_delegate.h',
],
},
{
'target_name': 'athena_test_support',
'type': 'static_library',
Expand All @@ -152,6 +169,7 @@
'resources/athena_resources.gyp:athena_resources',
],
'sources': [
'content/public/app_content_control_delegate.h',
'test/athena_test_base.cc',
'test/athena_test_base.h',
'test/athena_test_helper.cc',
Expand All @@ -160,6 +178,7 @@
'test/sample_activity.h',
'test/sample_activity_factory.cc',
'test/sample_activity_factory.h',
'test/test_app_content_control_delegate_impl.cc',
'test/test_app_model_builder.cc',
'test/test_app_model_builder.h',
'test/test_screen_manager_delegate.cc',
Expand All @@ -178,11 +197,12 @@
'resources/athena_resources.gyp:athena_pak',
],
'sources': [
'test/athena_unittests.cc',
'activity/activity_manager_unittest.cc',
'content/app_activity_unittest.cc',
'home/home_card_unittest.cc',
'input/accelerator_manager_unittest.cc',
'screen/screen_manager_unittest.cc',
'test/athena_unittests.cc',
'wm/split_view_controller_unittest.cc',
'wm/window_list_provider_impl_unittest.cc',
'wm/window_manager_unittest.cc',
Expand Down
4 changes: 4 additions & 0 deletions athena/content/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
skuhne@chromium.org
oshima@chromium.org
mukai@chromium.org

65 changes: 51 additions & 14 deletions athena/content/app_activity.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,59 +5,70 @@
#include "athena/content/app_activity.h"

#include "athena/activity/public/activity_manager.h"
#include "athena/content/app_activity_registry.h"
#include "athena/content/public/app_content_control_delegate.h"
#include "athena/content/public/app_registry.h"
#include "content/public/browser/web_contents.h"
#include "extensions/shell/browser/shell_app_window.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/widget/widget.h"

namespace athena {

// TODO(mukai): specifies the same accelerators of WebActivity.
AppActivity::AppActivity(extensions::ShellAppWindow* app_window)
: app_window_(app_window),
web_view_(NULL),
current_state_(ACTIVITY_UNLOADED) {
DCHECK(app_window_);
current_state_(ACTIVITY_UNLOADED),
app_activity_registry_(NULL) {
}

AppActivity::~AppActivity() {
if (GetCurrentState() != ACTIVITY_UNLOADED)
SetCurrentState(ACTIVITY_UNLOADED);
// If this activity is registered, we unregister it now.
if (app_activity_registry_)
app_activity_registry_->UnregisterAppActivity(this);
}

ActivityViewModel* AppActivity::GetActivityViewModel() {
return this;
}

void AppActivity::SetCurrentState(Activity::ActivityState state) {
ActivityState current_state = state;
// Remember the last requested state now so that a call to GetCurrentState()
// returns the new state.
current_state_ = state;

switch (state) {
case ACTIVITY_VISIBLE:
// Fall through (for the moment).
case ACTIVITY_INVISIBLE:
// By clearing the overview mode image we allow the content to be shown.
overview_mode_image_ = gfx::ImageSkia();
// TODO(skuhne): Find out how to reload an app from the extension system.
// Note: A reload from the unloaded state will be performed through the
// |AppActivityProxy| object and no further action isn't necessary here.
break;
case ACTIVITY_BACKGROUND_LOW_PRIORITY:
DCHECK(ACTIVITY_VISIBLE == current_state_ ||
ACTIVITY_INVISIBLE == current_state_);
DCHECK(ACTIVITY_VISIBLE == current_state ||
ACTIVITY_INVISIBLE == current_state);
// TODO(skuhne): Do this.
break;
case ACTIVITY_PERSISTENT:
DCHECK_EQ(ACTIVITY_BACKGROUND_LOW_PRIORITY, current_state_);
DCHECK_EQ(ACTIVITY_BACKGROUND_LOW_PRIORITY, current_state);
// TODO(skuhne): Do this.
break;
case ACTIVITY_UNLOADED:
DCHECK_NE(ACTIVITY_UNLOADED, current_state_);
// TODO(skuhne): Find out how to evict an app from the extension system.
// web_view_->EvictContent();
DCHECK_NE(ACTIVITY_UNLOADED, current_state);
// This will cause the application to shut down, close its windows and
// delete this object. Instead a |AppActivityProxy| will be created as
// place holder.
if (app_activity_registry_)
app_activity_registry_->Unload();
break;
}
// Remember the last requested state.
current_state_ = state;
}

Activity::ActivityState AppActivity::GetCurrentState() {
// TODO(skuhne): Check here also eviction status.
if (!web_view_) {
DCHECK_EQ(ACTIVITY_UNLOADED, current_state_);
return ACTIVITY_UNLOADED;
Expand All @@ -82,6 +93,10 @@ Activity::ActivityMediaState AppActivity::GetMediaState() {
return Activity::ACTIVITY_MEDIA_STATE_NONE;
}

aura::Window* AppActivity::GetWindow() {
return !web_view_ ? NULL : web_view_->GetWidget()->GetNativeWindow();
}

void AppActivity::Init() {
}

Expand Down Expand Up @@ -130,4 +145,26 @@ void AppActivity::DidUpdateFaviconURL(
ActivityManager::Get()->UpdateActivity(this);
}

void AppActivity::DidStartNavigationToPendingEntry(
const GURL& url,
content::NavigationController::ReloadType reload_type) {
if (!app_activity_registry_)
RegisterActivity();
}

// Register an |activity| with an application.
// Note: This should only get called once for an |app_window| of the
// |activity|.
void AppActivity::RegisterActivity() {
content::WebContents* web_contents = app_window_->GetAssociatedWebContents();
AppRegistry* app_registry = AppRegistry::Get();
// Get the application's registry.
app_activity_registry_ = app_registry->GetAppActivityRegistry(
app_registry->GetDelegate()->GetApplicationID(web_contents),
web_contents->GetBrowserContext());
DCHECK(app_activity_registry_);
// Register the activity.
app_activity_registry_->RegisterAppActivity(this);
}

} // namespace athena
21 changes: 18 additions & 3 deletions athena/content/app_activity.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef ATHENA_CONTENT_PUBLIC_APP_ACTIVITY_H_
#define ATHENA_CONTENT_PUBLIC_APP_ACTIVITY_H_
#ifndef ATHENA_CONTENT_APP_ACTIVITY_H_
#define ATHENA_CONTENT_APP_ACTIVITY_H_

#include "athena/activity/public/activity.h"
#include "athena/activity/public/activity_view_model.h"
Expand All @@ -20,20 +20,23 @@ class WebView;

namespace athena {

class AppActivityRegistry;

// The activity object for a hosted V2 application.
class AppActivity : public Activity,
public ActivityViewModel,
public content::WebContentsObserver {
public:
explicit AppActivity(extensions::ShellAppWindow* app_window);
virtual ~AppActivity();

protected:
// Activity:
virtual athena::ActivityViewModel* GetActivityViewModel() OVERRIDE;
virtual void SetCurrentState(Activity::ActivityState state) OVERRIDE;
virtual ActivityState GetCurrentState() OVERRIDE;
virtual bool IsVisible() OVERRIDE;
virtual ActivityMediaState GetMediaState() OVERRIDE;
virtual aura::Window* GetWindow() OVERRIDE;

// ActivityViewModel:
virtual void Init() OVERRIDE;
Expand All @@ -44,13 +47,20 @@ class AppActivity : public Activity,
virtual void CreateOverviewModeImage() OVERRIDE;
virtual gfx::ImageSkia GetOverviewModeImage() OVERRIDE;

protected:
// content::WebContentsObserver:
virtual void TitleWasSet(content::NavigationEntry* entry,
bool explicit_set) OVERRIDE;
virtual void DidUpdateFaviconURL(
const std::vector<content::FaviconURL>& candidates) OVERRIDE;
virtual void DidStartNavigationToPendingEntry(
const GURL& url,
content::NavigationController::ReloadType reload_type) OVERRIDE;

private:
// Register this activity with its application.
void RegisterActivity();

scoped_ptr<extensions::ShellAppWindow> app_window_;
views::WebView* web_view_;

Expand All @@ -60,6 +70,11 @@ class AppActivity : public Activity,
// The image which will be used in overview mode.
gfx::ImageSkia overview_mode_image_;

// If known the registry which holds all activities for the associated app.
// This object is owned by |AppRegistry| and will be a valid pointer as long
// as this object lives.
AppActivityRegistry* app_activity_registry_;

DISALLOW_COPY_AND_ASSIGN(AppActivity);
};

Expand Down
84 changes: 84 additions & 0 deletions athena/content/app_activity_proxy.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// 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_proxy.h"

#include "athena/content/app_activity_registry.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"

namespace athena {

AppActivityProxy::AppActivityProxy(ActivityViewModel* view_model,
AppActivityRegistry* creator) :
app_activity_registry_(creator),
title_(view_model->GetTitle()),
image_(view_model->GetOverviewModeImage()),
color_(view_model->GetRepresentativeColor()),
// TODO(skuhne): We probably need to do something better with the view
// (e.g. showing the image).
view_(new views::View()) {}

AppActivityProxy::~AppActivityProxy() {
app_activity_registry_->ProxyDestroyed(this);
}

ActivityViewModel* AppActivityProxy::GetActivityViewModel() {
return this;
}

void AppActivityProxy::SetCurrentState(ActivityState state) {
// We ignore all calls which try to re-load the application at a lower than
// running invisible state.
if (state != ACTIVITY_VISIBLE && state != ACTIVITY_INVISIBLE)
return;
app_activity_registry_->RestartApplication(this);
// Note: This object is now destroyed.
}

Activity::ActivityState AppActivityProxy::GetCurrentState() {
return ACTIVITY_UNLOADED;
}

bool AppActivityProxy::IsVisible() {
return true;
}

Activity::ActivityMediaState AppActivityProxy::GetMediaState() {
// This proxy has never any media playing.
return ACTIVITY_MEDIA_STATE_NONE;
}

aura::Window* AppActivityProxy::GetWindow() {
return view_->GetWidget()->GetNativeWindow();
}

void AppActivityProxy::Init() {
}

SkColor AppActivityProxy::GetRepresentativeColor() const {
return color_;
}

base::string16 AppActivityProxy::GetTitle() const {
return title_;
}

bool AppActivityProxy::UsesFrame() const {
return true;
}

views::View* AppActivityProxy::GetContentsView() {
return view_;
}

void AppActivityProxy::CreateOverviewModeImage() {
// Nothing we can do here.
}

gfx::ImageSkia AppActivityProxy::GetOverviewModeImage() {
return image_;
}

} // namespace athena
Loading

0 comments on commit 23e145e

Please sign in to comment.