summaryrefslogtreecommitdiff
path: root/athena
diff options
context:
space:
mode:
Diffstat (limited to 'athena')
-rw-r--r--athena/DEPS11
-rw-r--r--athena/activity/DEPS6
-rw-r--r--athena/activity/activity_view_manager_impl.cc6
-rw-r--r--athena/activity/public/activity_factory.h8
-rw-r--r--athena/activity/public/activity_view_model.h8
-rw-r--r--athena/athena.gyp17
-rw-r--r--athena/common/switches.cc22
-rw-r--r--athena/common/switches.h16
-rw-r--r--athena/content/DEPS7
-rw-r--r--athena/content/app_activity.cc60
-rw-r--r--athena/content/app_activity.h54
-rw-r--r--athena/content/content_activity_factory.cc7
-rw-r--r--athena/content/content_app_model_builder.cc123
-rw-r--r--athena/content/public/content_activity_factory.h2
-rw-r--r--athena/content/public/content_app_model_builder.h32
-rw-r--r--athena/content/web_activity.cc150
-rw-r--r--athena/content/web_activity.h5
-rw-r--r--athena/home/app_list_view_delegate.cc124
-rw-r--r--athena/home/app_list_view_delegate.h13
-rw-r--r--athena/home/home_card_impl.cc53
-rw-r--r--athena/home/public/app_model_builder.h29
-rw-r--r--athena/home/public/home_card.h17
-rw-r--r--athena/input/DEPS6
-rw-r--r--athena/input/accelerator_manager_impl.cc184
-rw-r--r--athena/input/accelerator_manager_impl.h36
-rw-r--r--athena/input/accelerator_manager_unittest.cc13
-rw-r--r--athena/input/input_manager_impl.cc6
-rw-r--r--athena/input/public/accelerator_manager.h25
-rw-r--r--athena/main/DEPS5
-rw-r--r--athena/main/athena_app_window_controller.cc34
-rw-r--r--athena/main/athena_app_window_controller.h31
-rw-r--r--athena/main/athena_launcher.cc5
-rw-r--r--athena/main/athena_launcher.h4
-rw-r--r--athena/main/athena_main.cc51
-rw-r--r--athena/main/athena_main.gyp6
-rw-r--r--athena/main/url_search_provider.cc61
-rw-r--r--athena/main/url_search_provider.h34
-rw-r--r--athena/screen/DEPS2
-rw-r--r--athena/screen/background_controller.cc2
-rw-r--r--athena/screen/screen_accelerator_handler.cc96
-rw-r--r--athena/screen/screen_accelerator_handler.h33
-rw-r--r--athena/screen/screen_manager_impl.cc8
-rw-r--r--athena/test/DEPS2
-rw-r--r--athena/test/athena_test_base.cc7
-rw-r--r--athena/test/athena_test_helper.cc9
-rw-r--r--athena/test/sample_activity.cc7
-rw-r--r--athena/test/sample_activity.h7
-rw-r--r--athena/test/sample_activity_factory.cc15
-rw-r--r--athena/test/sample_activity_factory.h2
-rw-r--r--athena/test/test_app_model_builder.cc107
-rw-r--r--athena/test/test_app_model_builder.h27
-rw-r--r--athena/wm/DEPS7
-rw-r--r--athena/wm/window_manager_impl.cc5
-rw-r--r--athena/wm/window_overview_mode.cc93
54 files changed, 1486 insertions, 214 deletions
diff --git a/athena/DEPS b/athena/DEPS
index c60bd791d3..b8ec7302dc 100644
--- a/athena/DEPS
+++ b/athena/DEPS
@@ -1,6 +1,15 @@
# Please do not add dependency to chrome/ and its subdirectories
include_rules = [
- # Components within athena must state their dependencies explicitly.
+ # Components within athena must state their dependencies explicitly
+ # except for common.
"-athena",
+ "+athena/common",
]
+
+specific_include_rules = {
+ ".*unittest\.cc": [
+ "+athena/test",
+ ],
+}
+
diff --git a/athena/activity/DEPS b/athena/activity/DEPS
index d8c9b8eb1d..aafc6d4c6d 100644
--- a/athena/activity/DEPS
+++ b/athena/activity/DEPS
@@ -3,9 +3,3 @@ include_rules = [
"+ui/aura",
"+ui/views",
]
-
-specific_include_rules = {
- ".*unittest\.cc": [
- "+athena/test",
- ],
-}
diff --git a/athena/activity/activity_view_manager_impl.cc b/athena/activity/activity_view_manager_impl.cc
index d18879280f..a67e6bbd2f 100644
--- a/athena/activity/activity_view_manager_impl.cc
+++ b/athena/activity/activity_view_manager_impl.cc
@@ -10,7 +10,6 @@
#include "athena/activity/public/activity.h"
#include "athena/activity/public/activity_view_model.h"
#include "athena/screen/public/screen_manager.h"
-#include "base/strings/utf_string_conversions.h"
#include "ui/aura/window.h"
#include "ui/views/background.h"
#include "ui/views/controls/label.h"
@@ -49,6 +48,8 @@ class ActivityWidget : public views::LayoutManager {
params.activatable = views::Widget::InitParams::ACTIVATABLE_YES;
widget_->Init(params);
widget_->SetContentsView(container_);
+
+ activity_->GetActivityViewModel()->Init();
}
virtual ~ActivityWidget() {}
@@ -59,8 +60,7 @@ class ActivityWidget : public views::LayoutManager {
}
void Update() {
- title_->SetText(
- base::UTF8ToUTF16(activity_->GetActivityViewModel()->GetTitle()));
+ title_->SetText(activity_->GetActivityViewModel()->GetTitle());
SkColor bgcolor =
activity_->GetActivityViewModel()->GetRepresentativeColor();
title_->set_background(views::Background::CreateSolidBackground(bgcolor));
diff --git a/athena/activity/public/activity_factory.h b/athena/activity/public/activity_factory.h
index 8cea669e10..bc95893e25 100644
--- a/athena/activity/public/activity_factory.h
+++ b/athena/activity/public/activity_factory.h
@@ -8,6 +8,10 @@
#include "athena/athena_export.h"
#include "url/gurl.h"
+namespace apps {
+class ShellAppWindow;
+}
+
namespace content {
class BrowserContext;
}
@@ -31,6 +35,10 @@ class ATHENA_EXPORT ActivityFactory {
// Create an activity of a web page.
virtual Activity* CreateWebActivity(content::BrowserContext* browser_context,
const GURL& url) = 0;
+
+ // Create an activity of an app with |app_window|. The returned activity
+ // should own |app_window|.
+ virtual Activity* CreateAppActivity(apps::ShellAppWindow* app_window) = 0;
};
} // namespace athena
diff --git a/athena/activity/public/activity_view_model.h b/athena/activity/public/activity_view_model.h
index b7eb2212a8..5e6614c8cb 100644
--- a/athena/activity/public/activity_view_model.h
+++ b/athena/activity/public/activity_view_model.h
@@ -5,9 +5,8 @@
#ifndef ATHENA_ACTIVITY_PUBLIC_ACTIVITY_VIEW_MODEL_H_
#define ATHENA_ACTIVITY_PUBLIC_ACTIVITY_VIEW_MODEL_H_
-#include <string>
-
#include "athena/athena_export.h"
+#include "base/strings/string16.h"
typedef unsigned int SkColor;
@@ -21,11 +20,14 @@ class ATHENA_EXPORT ActivityViewModel {
public:
virtual ~ActivityViewModel() {}
+ // Called after the view model is attaced to the widget/window tree.
+ virtual void Init() = 0;
+
// Returns a color most representative of this activity.
virtual SkColor GetRepresentativeColor() = 0;
// Returns a title for the activity.
- virtual std::string GetTitle() = 0;
+ virtual base::string16 GetTitle() = 0;
// Returns the contents view.
virtual views::View* GetContentsView() = 0;
diff --git a/athena/athena.gyp b/athena/athena.gyp
index b007235341..6bdc07b9d3 100644
--- a/athena/athena.gyp
+++ b/athena/athena.gyp
@@ -31,10 +31,14 @@
'activity/public/activity_manager.h',
'activity/public/activity_view_manager.h',
'activity/public/activity_view_model.h',
+ # move athena_export.h to common/
'athena_export.h',
+ 'common/switches.cc',
+ 'common/switches.h',
'home/app_list_view_delegate.cc',
'home/app_list_view_delegate.h',
'home/home_card_impl.cc',
+ 'home/public/app_model_builder.h',
'home/public/home_card.h',
'input/public/input_manager.h',
'input/public/accelerator_manager.h',
@@ -44,6 +48,8 @@
'screen/background_controller.cc',
'screen/background_controller.h',
'screen/public/screen_manager.h',
+ 'screen/screen_accelerator_handler.cc',
+ 'screen/screen_accelerator_handler.h',
'screen/screen_manager_impl.cc',
'wm/public/window_manager.h',
'wm/window_manager_impl.cc',
@@ -53,10 +59,11 @@
},
{
'target_name': 'athena_content_lib',
- 'type': '<(component)',
+ 'type': 'static_library',
'dependencies': [
'athena_lib',
'../content/content.gyp:content_browser',
+ '../ui/app_list/app_list.gyp:app_list',
'../ui/views/controls/webview/webview.gyp:webview',
'../skia/skia.gyp:skia',
],
@@ -65,7 +72,11 @@
],
'sources': [
'content/public/content_activity_factory.h',
+ 'content/public/content_app_model_builder.h',
'content/content_activity_factory.cc',
+ 'content/content_app_model_builder.cc',
+ 'content/app_activity.h',
+ 'content/app_activity.cc',
'content/web_activity.h',
'content/web_activity.cc',
],
@@ -78,6 +89,7 @@
'../skia/skia.gyp:skia',
'../testing/gtest.gyp:gtest',
'../ui/accessibility/accessibility.gyp:ax_gen',
+ '../ui/app_list/app_list.gyp:app_list',
'../ui/aura/aura.gyp:aura_test_support',
'../ui/base/ui_base.gyp:ui_base_test_support',
'../ui/compositor/compositor.gyp:compositor_test_support',
@@ -99,6 +111,8 @@
'test/sample_activity.h',
'test/sample_activity_factory.cc',
'test/sample_activity_factory.h',
+ 'test/test_app_model_builder.cc',
+ 'test/test_app_model_builder.h',
],
},
{
@@ -106,6 +120,7 @@
'type': 'executable',
'dependencies': [
'../testing/gtest.gyp:gtest',
+ '../skia/skia.gyp:skia',
'athena_lib',
'athena_test_support',
],
diff --git a/athena/common/switches.cc b/athena/common/switches.cc
new file mode 100644
index 0000000000..09dc12ae8e
--- /dev/null
+++ b/athena/common/switches.cc
@@ -0,0 +1,22 @@
+// 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/common/switches.h"
+
+#include "base/command_line.h"
+
+namespace athena {
+namespace switches {
+
+bool IsDebugAcceleratorsEnabled() {
+#if NDEBUG
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ "debug-accelerators");
+#else
+ return true;
+#endif
+}
+
+} // namespace switches
+} // namespace athena
diff --git a/athena/common/switches.h b/athena/common/switches.h
new file mode 100644
index 0000000000..ce68164e81
--- /dev/null
+++ b/athena/common/switches.h
@@ -0,0 +1,16 @@
+// 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.
+
+#ifndef ATHENA_COMMON_SWITCHES_H_
+#define ATHENA_COMMON_SWITCHES_H_
+
+namespace athena {
+namespace switches {
+
+bool IsDebugAcceleratorsEnabled();
+
+} // namespace switches
+} // namespace athena
+
+#endif // ATHENA_COMMON_SWITCHES_H_
diff --git a/athena/content/DEPS b/athena/content/DEPS
index 4432260b8e..f674843103 100644
--- a/athena/content/DEPS
+++ b/athena/content/DEPS
@@ -1,5 +1,10 @@
include_rules = [
+ "+apps/shell/browser",
"+athena/activity/public",
+ "+athena/home/public",
+ "+athena/input/public",
"+content/public",
- "+ui/views/controls/webview",
+ "+extensions/common",
+ "+ui/app_list",
+ "+ui/views",
]
diff --git a/athena/content/app_activity.cc b/athena/content/app_activity.cc
new file mode 100644
index 0000000000..e25d9f3215
--- /dev/null
+++ b/athena/content/app_activity.cc
@@ -0,0 +1,60 @@
+// 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.h"
+
+#include "apps/shell/browser/shell_app_window.h"
+#include "athena/activity/public/activity_manager.h"
+#include "content/public/browser/web_contents.h"
+#include "ui/views/controls/webview/webview.h"
+
+namespace athena {
+
+// TODO(mukai): specifies the same accelerators of WebActivity.
+AppActivity::AppActivity(apps::ShellAppWindow* app_window)
+ : app_window_(app_window), web_view_(NULL) {
+ DCHECK(app_window_);
+}
+
+AppActivity::~AppActivity() {
+}
+
+ActivityViewModel* AppActivity::GetActivityViewModel() {
+ return this;
+}
+
+void AppActivity::Init() {
+}
+
+SkColor AppActivity::GetRepresentativeColor() {
+ // TODO(sad): Compute the color from the favicon.
+ return SK_ColorGRAY;
+}
+
+base::string16 AppActivity::GetTitle() {
+ return web_view_->GetWebContents()->GetTitle();
+}
+
+views::View* AppActivity::GetContentsView() {
+ if (!web_view_) {
+ content::WebContents* web_contents =
+ app_window_->GetAssociatedWebContents();
+ web_view_ = new views::WebView(web_contents->GetBrowserContext());
+ web_view_->SetWebContents(web_contents);
+ Observe(web_contents);
+ }
+ return web_view_;
+}
+
+void AppActivity::TitleWasSet(content::NavigationEntry* entry,
+ bool explicit_set) {
+ ActivityManager::Get()->UpdateActivity(this);
+}
+
+void AppActivity::DidUpdateFaviconURL(
+ const std::vector<content::FaviconURL>& candidates) {
+ ActivityManager::Get()->UpdateActivity(this);
+}
+
+} // namespace athena
diff --git a/athena/content/app_activity.h b/athena/content/app_activity.h
new file mode 100644
index 0000000000..6c5a7422e7
--- /dev/null
+++ b/athena/content/app_activity.h
@@ -0,0 +1,54 @@
+// 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.
+
+#ifndef ATHENA_CONTENT_PUBLIC_APP_ACTIVITY_H_
+#define ATHENA_CONTENT_PUBLIC_APP_ACTIVITY_H_
+
+#include "athena/activity/public/activity.h"
+#include "athena/activity/public/activity_view_model.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace apps {
+class ShellAppWindow;
+}
+
+namespace views {
+class WebView;
+}
+
+namespace athena {
+
+class AppActivity : public Activity,
+ public ActivityViewModel,
+ public content::WebContentsObserver {
+ public:
+ explicit AppActivity(apps::ShellAppWindow* app_window);
+ virtual ~AppActivity();
+
+ protected:
+ // Activity:
+ virtual athena::ActivityViewModel* GetActivityViewModel() OVERRIDE;
+
+ // ActivityViewModel:
+ virtual void Init() OVERRIDE;
+ virtual SkColor GetRepresentativeColor() OVERRIDE;
+ virtual base::string16 GetTitle() OVERRIDE;
+ virtual views::View* GetContentsView() OVERRIDE;
+
+ // content::WebContentsObserver:
+ virtual void TitleWasSet(content::NavigationEntry* entry,
+ bool explicit_set) OVERRIDE;
+ virtual void DidUpdateFaviconURL(
+ const std::vector<content::FaviconURL>& candidates) OVERRIDE;
+
+ private:
+ scoped_ptr<apps::ShellAppWindow> app_window_;
+ views::WebView* web_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppActivity);
+};
+
+} // namespace athena
+
+#endif // ATHENA_CONTENT_APP_ACTIVITY_H_
diff --git a/athena/content/content_activity_factory.cc b/athena/content/content_activity_factory.cc
index 9486d1fef3..3a086410f6 100644
--- a/athena/content/content_activity_factory.cc
+++ b/athena/content/content_activity_factory.cc
@@ -4,7 +4,9 @@
#include "athena/content/public/content_activity_factory.h"
+#include "athena/content/app_activity.h"
#include "athena/content/web_activity.h"
+#include "base/logging.h"
namespace athena {
@@ -19,4 +21,9 @@ Activity* ContentActivityFactory::CreateWebActivity(
return new WebActivity(browser_context, url);
}
+Activity* ContentActivityFactory::CreateAppActivity(
+ apps::ShellAppWindow* app_window) {
+ return new AppActivity(app_window);
+}
+
} // namespace athena
diff --git a/athena/content/content_app_model_builder.cc b/athena/content/content_app_model_builder.cc
new file mode 100644
index 0000000000..f91b1c1061
--- /dev/null
+++ b/athena/content/content_app_model_builder.cc
@@ -0,0 +1,123 @@
+// 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/public/content_app_model_builder.h"
+
+#include "apps/shell/browser/shell_extension_system.h"
+#include "athena/activity/public/activity_factory.h"
+#include "athena/activity/public/activity_manager.h"
+#include "extensions/common/extension.h"
+#include "ui/app_list/app_list_item.h"
+#include "ui/app_list/app_list_model.h"
+
+using extensions::ShellExtensionSystem;
+
+namespace athena {
+
+namespace {
+
+const int kIconSize = 64;
+
+ShellExtensionSystem* GetShellExtensionSystem(
+ content::BrowserContext* context) {
+ return static_cast<ShellExtensionSystem*>(
+ extensions::ExtensionSystem::Get(context));
+}
+
+gfx::ImageSkia CreateFlatColorImage(SkColor color) {
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, kIconSize, kIconSize);
+ bitmap.allocPixels();
+ bitmap.eraseColor(color);
+ return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
+}
+
+// Same dummy item.
+class DummyItem : public app_list::AppListItem {
+ public:
+ DummyItem(const std::string& id,
+ const GURL& url,
+ SkColor color,
+ content::BrowserContext* browser_context)
+ : app_list::AppListItem(id),
+ url_(url),
+ browser_context_(browser_context) {
+
+ SetIcon(CreateFlatColorImage(color), false /* has_shadow */);
+ SetName(id);
+ }
+
+ private:
+ // Overridden from app_list::AppListItem:
+ virtual void Activate(int event_flags) OVERRIDE {
+ ActivityManager::Get()->AddActivity(
+ ActivityFactory::Get()->CreateWebActivity(browser_context_, url_));
+ }
+
+ GURL url_;
+ content::BrowserContext* browser_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(DummyItem);
+};
+
+class AppItem : public app_list::AppListItem {
+ public:
+ AppItem(scoped_refptr<extensions::Extension> extension,
+ content::BrowserContext* browser_context)
+ : app_list::AppListItem(extension->id()),
+ extension_(extension),
+ browser_context_(browser_context) {
+ // TODO(mukai): componentize extension_icon_image and use it.
+ SetIcon(CreateFlatColorImage(SK_ColorBLACK), false);
+ SetName(extension->name());
+ }
+
+ private:
+ // Overridden from app_list::AppListItem:
+ virtual void Activate(int event_flags) OVERRIDE {
+ // TODO(mukai): Pass |extension_| when the extension system supports
+ // multiple extensions.
+ GetShellExtensionSystem(browser_context_)->LaunchApp();
+ }
+
+ scoped_refptr<extensions::Extension> extension_;
+ content::BrowserContext* browser_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppItem);
+};
+
+} // namespace
+
+ContentAppModelBuilder::ContentAppModelBuilder(
+ content::BrowserContext* browser_context)
+ : browser_context_(browser_context) {
+}
+
+ContentAppModelBuilder::~ContentAppModelBuilder() {
+}
+
+void ContentAppModelBuilder::PopulateApps(app_list::AppListModel* model) {
+ model->AddItem(scoped_ptr<app_list::AppListItem>(new DummyItem(
+ "mail", GURL("http://gmail.com/"), SK_ColorRED, browser_context_)));
+ model->AddItem(scoped_ptr<app_list::AppListItem>(new DummyItem(
+ "calendar", GURL("https://calendar.google.com/"),
+ SK_ColorBLUE, browser_context_)));
+ model->AddItem(scoped_ptr<app_list::AppListItem>(new DummyItem(
+ "video", GURL("http://youtube.com/"), SK_ColorGREEN, browser_context_)));
+ model->AddItem(scoped_ptr<app_list::AppListItem>(new DummyItem(
+ "music", GURL("http://play.google.com/music"),
+ SK_ColorYELLOW, browser_context_)));
+ model->AddItem(scoped_ptr<app_list::AppListItem>(new DummyItem(
+ "contact", GURL("https://www.google.com/contacts"),
+ SK_ColorCYAN, browser_context_)));
+
+ ShellExtensionSystem* extension_system =
+ GetShellExtensionSystem(browser_context_);
+ if (extension_system && extension_system->extension()) {
+ model->AddItem(scoped_ptr<app_list::AppListItem>(
+ new AppItem(extension_system->extension(), browser_context_)));
+ }
+}
+
+} // namespace athena
diff --git a/athena/content/public/content_activity_factory.h b/athena/content/public/content_activity_factory.h
index 25d6fe4760..2698123fc7 100644
--- a/athena/content/public/content_activity_factory.h
+++ b/athena/content/public/content_activity_factory.h
@@ -19,6 +19,8 @@ class ATHENA_EXPORT ContentActivityFactory : public ActivityFactory {
// Overridden from ActivityFactory:
virtual Activity* CreateWebActivity(content::BrowserContext* browser_context,
const GURL& url) OVERRIDE;
+ virtual Activity* CreateAppActivity(
+ apps::ShellAppWindow* app_window) OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(ContentActivityFactory);
diff --git a/athena/content/public/content_app_model_builder.h b/athena/content/public/content_app_model_builder.h
new file mode 100644
index 0000000000..85c79998ae
--- /dev/null
+++ b/athena/content/public/content_app_model_builder.h
@@ -0,0 +1,32 @@
+// 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.
+
+#ifndef ATHENA_CONTENT_PUBLIC_CONTENT_APP_MODEL_BUILDER_H_
+#define ATHENA_CONTENT_PUBLIC_CONTENT_APP_MODEL_BUILDER_H_
+
+#include "athena/home/public/app_model_builder.h"
+#include "base/macros.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace athena {
+
+class ATHENA_EXPORT ContentAppModelBuilder : public AppModelBuilder {
+ public:
+ explicit ContentAppModelBuilder(content::BrowserContext* browser_context);
+ virtual ~ContentAppModelBuilder();
+
+ virtual void PopulateApps(app_list::AppListModel* model) OVERRIDE;
+
+ private:
+ content::BrowserContext* browser_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContentAppModelBuilder);
+};
+
+} // namespace athena
+
+#endif // ATHENA_CONTENT_PUBLIC_CONTENT_APP_MODEL_BUILDER_H_
diff --git a/athena/content/web_activity.cc b/athena/content/web_activity.cc
index fa7b6da241..0385b47460 100644
--- a/athena/content/web_activity.cc
+++ b/athena/content/web_activity.cc
@@ -5,11 +5,148 @@
#include "athena/content/web_activity.h"
#include "athena/activity/public/activity_manager.h"
-#include "base/strings/utf_string_conversions.h"
+#include "athena/input/public/accelerator_manager.h"
+#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/web_contents.h"
+#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
#include "ui/views/controls/webview/webview.h"
+#include "ui/views/focus/focus_manager.h"
namespace athena {
+namespace {
+
+class WebActivityController : public AcceleratorHandler {
+ public:
+ enum Command {
+ CMD_BACK,
+ CMD_FORWARD,
+ CMD_RELOAD,
+ CMD_RELOAD_IGNORE_CACHE,
+ };
+
+ explicit WebActivityController(views::WebView* web_view)
+ : web_view_(web_view), reserved_accelerator_enabled_(true) {}
+ virtual ~WebActivityController() {}
+
+ // Installs accelerators for web activity.
+ void InstallAccelerators() {
+ accelerator_manager_ = AcceleratorManager::CreateForFocusManager(
+ web_view_->GetFocusManager()).Pass();
+ const AcceleratorData accelerator_data[] = {
+ {TRIGGER_ON_PRESS, ui::VKEY_R, ui::EF_CONTROL_DOWN, CMD_RELOAD,
+ AF_NONE},
+ {TRIGGER_ON_PRESS, ui::VKEY_BROWSER_REFRESH, ui::EF_NONE, CMD_RELOAD,
+ AF_NONE},
+ {TRIGGER_ON_PRESS, ui::VKEY_BROWSER_REFRESH, ui::EF_CONTROL_DOWN,
+ CMD_RELOAD_IGNORE_CACHE, AF_NONE},
+ {TRIGGER_ON_PRESS, ui::VKEY_BROWSER_FORWARD, ui::EF_NONE, CMD_FORWARD,
+ AF_NONE},
+ {TRIGGER_ON_PRESS, ui::VKEY_BROWSER_BACK, ui::EF_NONE, CMD_BACK,
+ AF_NONE},
+ };
+ accelerator_manager_->RegisterAccelerators(
+ accelerator_data, arraysize(accelerator_data), this);
+ }
+
+ // Methods that are called before and after key events are consumed by the web
+ // contents.
+ // See the documentation in WebContentsDelegate: for more details.
+ bool PreHandleKeyboardEvent(content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event,
+ bool* is_keyboard_shortcut) {
+ ui::Accelerator accelerator(
+ static_cast<ui::KeyboardCode>(event.windowsKeyCode),
+ content::GetModifiersFromNativeWebKeyboardEvent(event));
+ if (event.type == blink::WebInputEvent::KeyUp)
+ accelerator.set_type(ui::ET_KEY_RELEASED);
+
+ if (reserved_accelerator_enabled_ &&
+ accelerator_manager_->IsRegistered(accelerator, AF_RESERVED)) {
+ return web_view_->GetFocusManager()->ProcessAccelerator(accelerator);
+ }
+ *is_keyboard_shortcut =
+ accelerator_manager_->IsRegistered(accelerator, AF_NONE);
+ return false;
+ }
+
+ void HandleKeyboardEvent(content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event) {
+ unhandled_keyboard_event_handler_.HandleKeyboardEvent(
+ event, web_view_->GetFocusManager());
+ }
+
+ private:
+ // AcceleratorHandler:
+ virtual bool IsCommandEnabled(int command_id) const OVERRIDE {
+ switch (command_id) {
+ case CMD_RELOAD:
+ return true;
+ case CMD_BACK:
+ return web_view_->GetWebContents()->GetController().CanGoBack();
+ case CMD_FORWARD:
+ return web_view_->GetWebContents()->GetController().CanGoForward();
+ }
+ return false;
+ }
+
+ virtual bool OnAcceleratorFired(int command_id,
+ const ui::Accelerator& accelerator) OVERRIDE {
+ switch (command_id) {
+ case CMD_RELOAD:
+ web_view_->GetWebContents()->GetController().Reload(false);
+ return true;
+ case CMD_RELOAD_IGNORE_CACHE:
+ web_view_->GetWebContents()->GetController().ReloadIgnoringCache(false);
+ return true;
+ case CMD_BACK:
+ web_view_->GetWebContents()->GetController().GoBack();
+ return true;
+ case CMD_FORWARD:
+ web_view_->GetWebContents()->GetController().GoForward();
+ return true;
+ }
+ return false;
+ }
+
+ views::WebView* web_view_;
+ bool reserved_accelerator_enabled_;
+ scoped_ptr<AcceleratorManager> accelerator_manager_;
+ views::UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebActivityController);
+};
+
+// A web view for athena's web activity.
+class AthenaWebView : public views::WebView {
+ public:
+ AthenaWebView(content::BrowserContext* context)
+ : views::WebView(context), controller_(new WebActivityController(this)) {}
+ virtual ~AthenaWebView() {}
+
+ void InstallAccelerators() { controller_->InstallAccelerators(); }
+
+ private:
+ // WebContentsDelegate:
+ virtual bool PreHandleKeyboardEvent(
+ content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event,
+ bool* is_keyboard_shortcut) OVERRIDE {
+ return controller_->PreHandleKeyboardEvent(
+ source, event, is_keyboard_shortcut);
+ }
+
+ virtual void HandleKeyboardEvent(
+ content::WebContents* source,
+ const content::NativeWebKeyboardEvent& event) OVERRIDE {
+ controller_->HandleKeyboardEvent(source, event);
+ }
+
+ scoped_ptr<WebActivityController> controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(AthenaWebView);
+};
+
+} // namespace
WebActivity::WebActivity(content::BrowserContext* browser_context,
const GURL& url)
@@ -23,18 +160,23 @@ ActivityViewModel* WebActivity::GetActivityViewModel() {
return this;
}
+void WebActivity::Init() {
+ DCHECK(web_view_);
+ static_cast<AthenaWebView*>(web_view_)->InstallAccelerators();
+}
+
SkColor WebActivity::GetRepresentativeColor() {
// TODO(sad): Compute the color from the favicon.
return SK_ColorGRAY;
}
-std::string WebActivity::GetTitle() {
- return base::UTF16ToUTF8(web_view_->GetWebContents()->GetTitle());
+base::string16 WebActivity::GetTitle() {
+ return web_view_->GetWebContents()->GetTitle();
}
views::View* WebActivity::GetContentsView() {
if (!web_view_) {
- web_view_ = new views::WebView(browser_context_);
+ web_view_ = new AthenaWebView(browser_context_);
web_view_->LoadInitialURL(url_);
Observe(web_view_->GetWebContents());
}
diff --git a/athena/content/web_activity.h b/athena/content/web_activity.h
index 32a8425c8a..840cceefb3 100644
--- a/athena/content/web_activity.h
+++ b/athena/content/web_activity.h
@@ -11,6 +11,7 @@
namespace content {
class BrowserContext;
+class WebContents;
}
namespace views {
@@ -31,8 +32,9 @@ class WebActivity : public Activity,
virtual athena::ActivityViewModel* GetActivityViewModel() OVERRIDE;
// ActivityViewModel:
+ virtual void Init() OVERRIDE;
virtual SkColor GetRepresentativeColor() OVERRIDE;
- virtual std::string GetTitle() OVERRIDE;
+ virtual base::string16 GetTitle() OVERRIDE;
virtual views::View* GetContentsView() OVERRIDE;
// content::WebContentsObserver:
@@ -43,6 +45,7 @@ class WebActivity : public Activity,
private:
content::BrowserContext* browser_context_;
+ content::WebContents* web_contents_;
const GURL url_;
views::WebView* web_view_;
diff --git a/athena/home/app_list_view_delegate.cc b/athena/home/app_list_view_delegate.cc
index b7f45fb8c6..2bd79aea38 100644
--- a/athena/home/app_list_view_delegate.cc
+++ b/athena/home/app_list_view_delegate.cc
@@ -6,120 +6,54 @@
#include <string>
+#include "athena/home/public/app_model_builder.h"
#include "base/basictypes.h"
+#include "base/bind.h"
#include "base/callback.h"
#include "base/files/file_path.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/app_list/app_list_item.h"
-#include "ui/app_list/app_list_item_list.h"
#include "ui/app_list/app_list_model.h"
#include "ui/app_list/search_box_model.h"
+#include "ui/app_list/search_provider.h"
#include "ui/app_list/search_result.h"
#include "ui/app_list/speech_ui_model.h"
#include "ui/gfx/image/image_skia.h"
namespace athena {
-namespace {
-
-const int kIconSize = 64;
-
-class DummyItem : public app_list::AppListItem {
- public:
- enum Type {
- DUMMY_MAIL,
- DUMMY_CALENDAR,
- DUMMY_VIDEO,
- DUMMY_MUSIC,
- DUMMY_CONTACT,
- LAST_TYPE,
- };
-
- static std::string GetTitle(Type type) {
- switch (type) {
- case DUMMY_MAIL:
- return "mail";
- case DUMMY_CALENDAR:
- return "calendar";
- case DUMMY_VIDEO:
- return "video";
- case DUMMY_MUSIC:
- return "music";
- case DUMMY_CONTACT:
- return "contact";
- case LAST_TYPE:
- break;
- }
- NOTREACHED();
- return "";
- }
-
- static std::string GetId(Type type) {
- return std::string("id-") + GetTitle(type);
- }
-
- explicit DummyItem(Type type)
- : app_list::AppListItem(GetId(type)),
- type_(type) {
- SetIcon(GetIcon(), false /* has_shadow */);
- SetName(GetTitle(type_));
- }
-
- private:
- gfx::ImageSkia GetIcon() const {
- SkColor color = SK_ColorWHITE;
- switch (type_) {
- case DUMMY_MAIL:
- color = SK_ColorRED;
- break;
- case DUMMY_CALENDAR:
- color = SK_ColorBLUE;
- break;
- case DUMMY_VIDEO:
- color = SK_ColorGREEN;
- break;
- case DUMMY_MUSIC:
- color = SK_ColorYELLOW;
- break;
- case DUMMY_CONTACT:
- color = SK_ColorCYAN;
- break;
- case LAST_TYPE:
- NOTREACHED();
- break;
- }
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, kIconSize, kIconSize);
- bitmap.allocPixels();
- bitmap.eraseColor(color);
- return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
- }
-
- Type type_;
-
- DISALLOW_COPY_AND_ASSIGN(DummyItem);
-};
-
-} // namespace
-
-AppListViewDelegate::AppListViewDelegate()
+AppListViewDelegate::AppListViewDelegate(AppModelBuilder* model_builder)
: model_(new app_list::AppListModel),
speech_ui_(new app_list::SpeechUIModel(
app_list::SPEECH_RECOGNITION_OFF)) {
- PopulateApps();
+ model_builder->PopulateApps(model_.get());
// TODO(mukai): get the text from the resources.
model_->search_box()->SetHintText(base::ASCIIToUTF16("Search"));
}
AppListViewDelegate::~AppListViewDelegate() {
+ for (size_t i = 0; i < search_providers_.size(); ++i)
+ search_providers_[i]->set_result_changed_callback(base::Closure());
}
-void AppListViewDelegate::PopulateApps() {
- for (int i = 0; i < static_cast<int>(DummyItem::LAST_TYPE); ++i) {
- model_->AddItem(scoped_ptr<app_list::AppListItem>(
- new DummyItem(static_cast<DummyItem::Type>(i))));
- }
+void AppListViewDelegate::RegisterSearchProvider(
+ app_list::SearchProvider* search_provider) {
+ // Right now we allow only one provider.
+ // TODO(mukai): port app-list's mixer and remove this restriction.
+ DCHECK(search_providers_.empty());
+ search_provider->set_result_changed_callback(base::Bind(
+ &AppListViewDelegate::SearchResultChanged, base::Unretained(this)));
+ search_providers_.push_back(search_provider);
+}
+
+void AppListViewDelegate::SearchResultChanged() {
+ // TODO(mukai): port app-list's Mixer to reorder the results properly.
+ app_list::SearchProvider* search_provider = search_providers_[0];
+ std::vector<app_list::SearchResult*> results;
+ search_provider->ReleaseResult(&results);
+ model_->results()->DeleteAll();
+ for (size_t i = 0; i < results.size(); ++i)
+ model_->results()->Add(results[i]);
}
bool AppListViewDelegate::ForceNativeDesktop() const {
@@ -145,17 +79,19 @@ void AppListViewDelegate::GetShortcutPathForApp(
}
void AppListViewDelegate::StartSearch() {
- // TODO(mukai): implement this.
+ for (size_t i = 0; i < search_providers_.size(); ++i)
+ search_providers_[i]->Start(model_->search_box()->text());
}
void AppListViewDelegate::StopSearch() {
- // TODO(mukai): implement this.
+ for (size_t i = 0; i < search_providers_.size(); ++i)
+ search_providers_[i]->Stop();
}
void AppListViewDelegate::OpenSearchResult(app_list::SearchResult* result,
bool auto_launch,
int event_flags) {
- // TODO(mukai): implement this.
+ result->Open(event_flags);
}
void AppListViewDelegate::InvokeSearchResultAction(
diff --git a/athena/home/app_list_view_delegate.h b/athena/home/app_list_view_delegate.h
index 4e044cff45..752eb78256 100644
--- a/athena/home/app_list_view_delegate.h
+++ b/athena/home/app_list_view_delegate.h
@@ -9,15 +9,22 @@
#include "base/memory/scoped_ptr.h"
#include "ui/app_list/app_list_view_delegate.h"
+namespace app_list {
+class SearchProvider;
+}
+
namespace athena {
+class AppModelBuilder;
class AppListViewDelegate : public app_list::AppListViewDelegate {
public:
- AppListViewDelegate();
+ explicit AppListViewDelegate(AppModelBuilder* model_builder);
virtual ~AppListViewDelegate();
+ void RegisterSearchProvider(app_list::SearchProvider* search_provider);
+
private:
- void PopulateApps();
+ void SearchResultChanged();
// Overridden from app_list::AppListViewDelegate:
virtual bool ForceNativeDesktop() const OVERRIDE;
@@ -56,6 +63,8 @@ class AppListViewDelegate : public app_list::AppListViewDelegate {
scoped_ptr<app_list::SpeechUIModel> speech_ui_;
Users users_;
+ std::vector<app_list::SearchProvider*> search_providers_;
+
DISALLOW_COPY_AND_ASSIGN(AppListViewDelegate);
};
diff --git a/athena/home/home_card_impl.cc b/athena/home/home_card_impl.cc
index 949d5512d4..aa605540c6 100644
--- a/athena/home/home_card_impl.cc
+++ b/athena/home/home_card_impl.cc
@@ -5,10 +5,10 @@
#include "athena/home/public/home_card.h"
#include "athena/home/app_list_view_delegate.h"
+#include "athena/home/public/app_model_builder.h"
#include "athena/input/public/accelerator_manager.h"
-#include "athena/input/public/input_manager.h"
#include "athena/screen/public/screen_manager.h"
-#include "ui/app_list/pagination_model.h"
+#include "ui/app_list/search_provider.h"
#include "ui/app_list/views/app_list_view.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/window.h"
@@ -72,7 +72,7 @@ class HomeCardLayoutManager : public aura::LayoutManager {
class HomeCardImpl : public HomeCard, public AcceleratorHandler {
public:
- HomeCardImpl();
+ explicit HomeCardImpl(AppModelBuilder* model_builder);
virtual ~HomeCardImpl();
void Init();
@@ -83,22 +83,37 @@ class HomeCardImpl : public HomeCard, public AcceleratorHandler {
};
void InstallAccelerators();
+ // Overridden from HomeCard:
+ virtual void RegisterSearchProvider(
+ app_list::SearchProvider* search_provider) OVERRIDE;
+
// AcceleratorHandler:
virtual bool IsCommandEnabled(int command_id) const OVERRIDE { return true; }
virtual bool OnAcceleratorFired(int command_id,
const ui::Accelerator& accelerator) OVERRIDE {
DCHECK_EQ(COMMAND_SHOW_HOME_CARD, command_id);
- home_card_widget_->Show();
+ if (home_card_widget_->IsVisible())
+ home_card_widget_->Hide();
+ else
+ home_card_widget_->Show();
return true;
}
+ scoped_ptr<AppModelBuilder> model_builder_;
+
views::Widget* home_card_widget_;
+ AppListViewDelegate* view_delegate_;
+
+ // Right now HomeCard allows only one search provider.
+ // TODO(mukai): port app-list's SearchController and Mixer.
+ scoped_ptr<app_list::SearchProvider> search_provider_;
DISALLOW_COPY_AND_ASSIGN(HomeCardImpl);
};
-HomeCardImpl::HomeCardImpl()
- : home_card_widget_(NULL) {
+HomeCardImpl::HomeCardImpl(AppModelBuilder* model_builder)
+ : model_builder_(model_builder),
+ home_card_widget_(NULL) {
DCHECK(!instance);
instance = this;
}
@@ -106,9 +121,17 @@ HomeCardImpl::HomeCardImpl()
HomeCardImpl::~HomeCardImpl() {
DCHECK(instance);
home_card_widget_->CloseNow();
+ view_delegate_ = NULL;
instance = NULL;
}
+void HomeCardImpl::RegisterSearchProvider(
+ app_list::SearchProvider* search_provider) {
+ DCHECK(!search_provider_);
+ search_provider_.reset(search_provider);
+ view_delegate_->RegisterSearchProvider(search_provider_.get());
+}
+
void HomeCardImpl::Init() {
InstallAccelerators();
@@ -117,8 +140,10 @@ void HomeCardImpl::Init() {
container->SetLayoutManager(new HomeCardLayoutManager(container));
wm::SetChildWindowVisibilityChangesAnimated(container);
- app_list::AppListView* view = new app_list::AppListView(
- new AppListViewDelegate);
+ view_delegate_ = new AppListViewDelegate(model_builder_.get());
+ if (search_provider_)
+ view_delegate_->RegisterSearchProvider(search_provider_.get());
+ app_list::AppListView* view = new app_list::AppListView(view_delegate_);
view->InitAsBubbleAtFixedLocation(
container,
0 /* initial_apps_page */,
@@ -134,15 +159,15 @@ void HomeCardImpl::InstallAccelerators() {
{TRIGGER_ON_PRESS, ui::VKEY_L, ui::EF_CONTROL_DOWN,
COMMAND_SHOW_HOME_CARD, AF_NONE},
};
- InputManager::Get()->GetAcceleratorManager()->RegisterAccelerators(
+ AcceleratorManager::Get()->RegisterAccelerators(
accelerator_data, arraysize(accelerator_data), this);
}
} // namespace
// static
-HomeCard* HomeCard::Create() {
- (new HomeCardImpl())->Init();
+HomeCard* HomeCard::Create(AppModelBuilder* model_builder) {
+ (new HomeCardImpl(model_builder))->Init();
DCHECK(instance);
return instance;
}
@@ -154,4 +179,10 @@ void HomeCard::Shutdown() {
instance = NULL;
}
+// static
+HomeCard* HomeCard::Get() {
+ DCHECK(instance);
+ return instance;
+}
+
} // namespace athena
diff --git a/athena/home/public/app_model_builder.h b/athena/home/public/app_model_builder.h
new file mode 100644
index 0000000000..5cfa8902c1
--- /dev/null
+++ b/athena/home/public/app_model_builder.h
@@ -0,0 +1,29 @@
+// 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.
+
+#ifndef ATHENA_HOME_PUBLIC_APP_MODEL_BUILDER_H_
+#define ATHENA_HOME_PUBLIC_APP_MODEL_BUILDER_H_
+
+#include "athena/athena_export.h"
+
+namespace app_list {
+class AppListModel;
+} // namespace app_list
+
+namespace athena {
+
+// An interface to fill the list of apps in the home card.
+// TODO(mukai): integrate the interface with chrome/browser/ui/app_list/
+// extension_app_model_builder.
+class ATHENA_EXPORT AppModelBuilder {
+ public:
+ virtual ~AppModelBuilder() {}
+
+ // Fills |model| with the currently available app_list::AppListItems.
+ virtual void PopulateApps(app_list::AppListModel* model) = 0;
+};
+
+} // namespace athena
+
+#endif // ATHENA_HOME_PUBLIC_APP_MODEL_BUILDER_H_
diff --git a/athena/home/public/home_card.h b/athena/home/public/home_card.h
index b2b5dccbe0..6438d4f43c 100644
--- a/athena/home/public/home_card.h
+++ b/athena/home/public/home_card.h
@@ -7,16 +7,27 @@
#include "athena/athena_export.h"
+namespace app_list {
+class SearchProvider;
+}
+
namespace athena {
+class AppModelBuilder;
class ATHENA_EXPORT HomeCard {
public:
- // Creates and deletes the singleton object of the HomeCard
- // implementation.
- static HomeCard* Create();
+ // Creates/deletes/gets the singleton object of the HomeCard
+ // implementation. Takes the ownership of |model_builder|.
+ static HomeCard* Create(AppModelBuilder* model_builder);
static void Shutdown();
+ static HomeCard* Get();
virtual ~HomeCard() {}
+
+ // Registers a search_provider to the HomeCard. Receiver will take
+ // the ownership of the specified provider.
+ virtual void RegisterSearchProvider(
+ app_list::SearchProvider* search_provider) = 0;
};
} // namespace athena
diff --git a/athena/input/DEPS b/athena/input/DEPS
index 5b66b22c14..c280756495 100644
--- a/athena/input/DEPS
+++ b/athena/input/DEPS
@@ -4,10 +4,6 @@ include_rules = [
"+ui/events",
"+ui/wm/core",
"+ui/wm/public",
+ "+ui/views",
]
-specific_include_rules = {
- ".*unittest\.cc": [
- "+athena/test",
- ],
-}
diff --git a/athena/input/accelerator_manager_impl.cc b/athena/input/accelerator_manager_impl.cc
index cdd4673b2b..4fabe62808 100644
--- a/athena/input/accelerator_manager_impl.cc
+++ b/athena/input/accelerator_manager_impl.cc
@@ -4,12 +4,16 @@
#include "athena/input/accelerator_manager_impl.h"
+#include "athena/common/switches.h"
#include "athena/input/public/input_manager.h"
#include "base/logging.h"
#include "ui/aura/window.h"
#include "ui/base/accelerators/accelerator_manager.h"
#include "ui/events/event.h"
#include "ui/events/event_target.h"
+#include "ui/views/focus/focus_manager.h"
+#include "ui/views/focus/focus_manager_delegate.h"
+#include "ui/views/focus/focus_manager_factory.h"
#include "ui/wm/core/accelerator_delegate.h"
#include "ui/wm/core/accelerator_filter.h"
#include "ui/wm/core/nested_accelerator_controller.h"
@@ -18,6 +22,18 @@
namespace athena {
+// This wrapper interface provides a common interface that handles global
+// accelerators as well as local accelerators.
+class AcceleratorManagerImpl::AcceleratorWrapper {
+ public:
+ virtual ~AcceleratorWrapper() {}
+ virtual void Register(const ui::Accelerator& accelerator,
+ ui::AcceleratorTarget* target) = 0;
+ virtual bool Process(const ui::Accelerator& accelerator) = 0;
+ virtual ui::AcceleratorTarget* GetCurrentTarget(
+ const ui::Accelerator& accelertor) const = 0;
+};
+
namespace {
// Accelerators inside nested message loop are handled by
@@ -37,9 +53,8 @@ class NestedAcceleratorDelegate : public wm::NestedAcceleratorDelegate {
// wm::NestedAcceleratorDelegate:
virtual Result ProcessAccelerator(
const ui::Accelerator& accelerator) OVERRIDE {
- return accelerator_manager_->ProcessAccelerator(accelerator)
- ? RESULT_PROCESSED
- : RESULT_NOT_PROCESSED;
+ return accelerator_manager_->Process(accelerator) ? RESULT_PROCESSED
+ : RESULT_NOT_PROCESSED;
}
AcceleratorManagerImpl* accelerator_manager_;
@@ -60,17 +75,120 @@ class AcceleratorDelegate : public wm::AcceleratorDelegate {
KeyType key_type) OVERRIDE {
aura::Window* target = static_cast<aura::Window*>(event.target());
if (!target->IsRootWindow() &&
- !accelerator_manager_->IsReservedAccelerator(accelerator)) {
+ !accelerator_manager_->IsRegistered(accelerator, AF_RESERVED)) {
// TODO(oshima): do the same when the active window is in fullscreen.
return false;
}
- return accelerator_manager_->ProcessAccelerator(accelerator);
+ return accelerator_manager_->Process(accelerator);
}
AcceleratorManagerImpl* accelerator_manager_;
DISALLOW_COPY_AND_ASSIGN(AcceleratorDelegate);
};
+class FocusManagerDelegate : public views::FocusManagerDelegate {
+ public:
+ explicit FocusManagerDelegate(AcceleratorManagerImpl* accelerator_manager)
+ : accelerator_manager_(accelerator_manager) {}
+ virtual ~FocusManagerDelegate() {}
+
+ virtual bool ProcessAccelerator(const ui::Accelerator& accelerator) OVERRIDE {
+ return accelerator_manager_->Process(accelerator);
+ }
+
+ virtual ui::AcceleratorTarget* GetCurrentTargetForAccelerator(
+ const ui::Accelerator& accelerator) const OVERRIDE {
+ return accelerator_manager_->IsRegistered(accelerator, AF_NONE)
+ ? accelerator_manager_
+ : NULL;
+ }
+
+ private:
+ AcceleratorManagerImpl* accelerator_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(FocusManagerDelegate);
+};
+
+// Key strokes must be sent to web contents to give them a chance to
+// consume them unless they are reserved, and unhandled key events are
+// sent back to focus manager asynchronously. This installs the athena's
+// focus manager that handles athena shell's accelerators.
+class FocusManagerFactory : public views::FocusManagerFactory {
+ public:
+ explicit FocusManagerFactory(AcceleratorManagerImpl* accelerator_manager)
+ : accelerator_manager_(accelerator_manager) {}
+ virtual ~FocusManagerFactory() {}
+
+ virtual views::FocusManager* CreateFocusManager(
+ views::Widget* widget,
+ bool desktop_widget) OVERRIDE {
+ return new views::FocusManager(
+ widget,
+ desktop_widget ? NULL : new FocusManagerDelegate(accelerator_manager_));
+ }
+
+ private:
+ AcceleratorManagerImpl* accelerator_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(FocusManagerFactory);
+};
+
+class UIAcceleratorManagerWrapper
+ : public AcceleratorManagerImpl::AcceleratorWrapper {
+ public:
+ UIAcceleratorManagerWrapper()
+ : ui_accelerator_manager_(new ui::AcceleratorManager) {}
+ virtual ~UIAcceleratorManagerWrapper() {}
+
+ virtual void Register(const ui::Accelerator& accelerator,
+ ui::AcceleratorTarget* target) OVERRIDE {
+ return ui_accelerator_manager_->Register(
+ accelerator, ui::AcceleratorManager::kNormalPriority, target);
+ }
+
+ virtual bool Process(const ui::Accelerator& accelerator) OVERRIDE {
+ return ui_accelerator_manager_->Process(accelerator);
+ }
+
+ virtual ui::AcceleratorTarget* GetCurrentTarget(
+ const ui::Accelerator& accelerator) const OVERRIDE {
+ return ui_accelerator_manager_->GetCurrentTarget(accelerator);
+ }
+
+ private:
+ scoped_ptr<ui::AcceleratorManager> ui_accelerator_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(UIAcceleratorManagerWrapper);
+};
+
+class FocusManagerWrapper : public AcceleratorManagerImpl::AcceleratorWrapper {
+ public:
+ explicit FocusManagerWrapper(views::FocusManager* focus_manager)
+ : focus_manager_(focus_manager) {}
+ virtual ~FocusManagerWrapper() {}
+
+ virtual void Register(const ui::Accelerator& accelerator,
+ ui::AcceleratorTarget* target) OVERRIDE {
+ return focus_manager_->RegisterAccelerator(
+ accelerator, ui::AcceleratorManager::kNormalPriority, target);
+ }
+
+ virtual bool Process(const ui::Accelerator& accelerator) OVERRIDE {
+ NOTREACHED();
+ return true;
+ }
+
+ virtual ui::AcceleratorTarget* GetCurrentTarget(
+ const ui::Accelerator& accelerator) const OVERRIDE {
+ return focus_manager_->GetCurrentTargetForAccelerator(accelerator);
+ }
+
+ private:
+ views::FocusManager* focus_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(FocusManagerWrapper);
+};
+
} // namespace
class AcceleratorManagerImpl::InternalData {
@@ -80,7 +198,7 @@ class AcceleratorManagerImpl::InternalData {
bool IsNonAutoRepeatable() const { return flags_ & AF_NON_AUTO_REPEATABLE; }
bool IsDebug() const { return flags_ & AF_DEBUG; }
- bool IsReserved() const { return flags_ & AF_RESERVED; }
+ int flags() const { return flags_; }
bool IsCommandEnabled() const {
return handler_->IsCommandEnabled(command_id_);
@@ -98,16 +216,30 @@ class AcceleratorManagerImpl::InternalData {
// This class is copyable by design.
};
-AcceleratorManagerImpl::AcceleratorManagerImpl()
- : accelerator_manager_(new ui::AcceleratorManager) {
+// static
+AcceleratorManagerImpl*
+AcceleratorManagerImpl::CreateGlobalAcceleratorManager() {
+ return new AcceleratorManagerImpl(new UIAcceleratorManagerWrapper());
+}
+
+scoped_ptr<AcceleratorManager> AcceleratorManagerImpl::CreateForFocusManager(
+ views::FocusManager* focus_manager) {
+ return scoped_ptr<AcceleratorManager>(
+ new AcceleratorManagerImpl(new FocusManagerWrapper(focus_manager)))
+ .Pass();
}
AcceleratorManagerImpl::~AcceleratorManagerImpl() {
nested_accelerator_controller_.reset();
accelerator_filter_.reset();
+ // Reset to use the default focus manager because the athena's
+ // FocusManager has the reference to this object.
+ views::FocusManagerFactory::Install(NULL);
}
void AcceleratorManagerImpl::Init() {
+ views::FocusManagerFactory::Install(new FocusManagerFactory(this));
+
ui::EventTarget* toplevel = InputManager::Get()->GetTopmostEventTarget();
nested_accelerator_controller_.reset(
new wm::NestedAcceleratorController(new NestedAcceleratorDelegate(this)));
@@ -125,18 +257,24 @@ void AcceleratorManagerImpl::OnRootWindowCreated(aura::Window* root_window) {
nested_accelerator_controller_.get());
}
-bool AcceleratorManagerImpl::IsReservedAccelerator(
- const ui::Accelerator& accelerator) const {
+bool AcceleratorManagerImpl::Process(const ui::Accelerator& accelerator) {
+ return accelerator_wrapper_->Process(accelerator);
+}
+
+bool AcceleratorManagerImpl::IsRegistered(const ui::Accelerator& accelerator,
+ int flags) const {
std::map<ui::Accelerator, InternalData>::const_iterator iter =
accelerators_.find(accelerator);
if (iter == accelerators_.end())
return false;
- return iter->second.IsReserved();
+ DCHECK(accelerator_wrapper_->GetCurrentTarget(accelerator));
+ return flags == AF_NONE || iter->second.flags() & flags;
}
-bool AcceleratorManagerImpl::ProcessAccelerator(
- const ui::Accelerator& accelerator) {
- return accelerator_manager_->Process(accelerator);
+AcceleratorManagerImpl::AcceleratorManagerImpl(
+ AcceleratorWrapper* accelerator_wrapper)
+ : accelerator_wrapper_(accelerator_wrapper),
+ debug_accelerators_enabled_(switches::IsDebugAcceleratorsEnabled()) {
}
void AcceleratorManagerImpl::RegisterAccelerators(
@@ -147,8 +285,8 @@ void AcceleratorManagerImpl::RegisterAccelerators(
RegisterAccelerator(accelerators[i], handler);
}
-void AcceleratorManagerImpl::EnableDebugAccelerators() {
- debug_accelerators_enabled_ = true;
+void AcceleratorManagerImpl::SetDebugAcceleratorsEnabled(bool enabled) {
+ debug_accelerators_enabled_ = enabled;
}
bool AcceleratorManagerImpl::AcceleratorPressed(
@@ -178,8 +316,7 @@ void AcceleratorManagerImpl::RegisterAccelerator(
accelerator.set_type(accelerator_data.trigger_event == TRIGGER_ON_PRESS
? ui::ET_KEY_PRESSED
: ui::ET_KEY_RELEASED);
- accelerator_manager_->Register(
- accelerator, ui::AcceleratorManager::kNormalPriority, this);
+ accelerator_wrapper_->Register(accelerator, this);
accelerators_.insert(
std::make_pair(accelerator,
InternalData(accelerator_data.command_id,
@@ -187,4 +324,15 @@ void AcceleratorManagerImpl::RegisterAccelerator(
accelerator_data.accelerator_flags)));
}
+// static
+AcceleratorManager* AcceleratorManager::Get() {
+ return InputManager::Get()->GetAcceleratorManager();
+}
+
+// static
+scoped_ptr<AcceleratorManager> AcceleratorManager::CreateForFocusManager(
+ views::FocusManager* focus_manager) {
+ return AcceleratorManagerImpl::CreateForFocusManager(focus_manager).Pass();
+}
+
} // namespace athena
diff --git a/athena/input/accelerator_manager_impl.h b/athena/input/accelerator_manager_impl.h
index 1a5e8a95eb..5891b8599e 100644
--- a/athena/input/accelerator_manager_impl.h
+++ b/athena/input/accelerator_manager_impl.h
@@ -17,10 +17,6 @@ namespace aura {
class Window;
}
-namespace ui {
-class AcceleratorManager;
-}
-
namespace wm {
class AcceleratorFilter;
class NestedAcceleratorController;
@@ -35,38 +31,52 @@ namespace athena {
class AcceleratorManagerImpl : public AcceleratorManager,
public ui::AcceleratorTarget {
public:
- AcceleratorManagerImpl();
+ class AcceleratorWrapper;
+
+ // Creates an AcceleratorManager for global accelerators.
+ // This is the one returned by AcceleratorManager::Get()
+ static AcceleratorManagerImpl* CreateGlobalAcceleratorManager();
+
+ // Creates an AcceleratorManager for focus manager.
+ static scoped_ptr<AcceleratorManager> CreateForFocusManager(
+ views::FocusManager* focus_manager);
+
virtual ~AcceleratorManagerImpl();
void Init();
void OnRootWindowCreated(aura::Window* root_window);
- bool IsReservedAccelerator(const ui::Accelerator& accelerator) const;
- bool ProcessAccelerator(const ui::Accelerator& accelerator);
+ bool Process(const ui::Accelerator& accelerator);
+
+ // AcceleratorManager:
+ // This is made public so that implementation classes can use this.
+ virtual bool IsRegistered(const ui::Accelerator& accelerator,
+ int flags) const OVERRIDE;
private:
+ class InternalData;
+
+ explicit AcceleratorManagerImpl(AcceleratorWrapper* wrapper);
+
// AcceleratorManager:
virtual void RegisterAccelerators(const AcceleratorData accelerators[],
size_t num_accelerators,
AcceleratorHandler* handler) OVERRIDE;
- virtual void EnableDebugAccelerators() OVERRIDE;
+ virtual void SetDebugAcceleratorsEnabled(bool enabled) OVERRIDE;
// ui::AcceleratorTarget:
virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE;
virtual bool CanHandleAccelerators() const OVERRIDE;
- class InternalData;
-
void RegisterAccelerator(const AcceleratorData& accelerator,
AcceleratorHandler* handler);
- bool debug_accelerators_enabled_;
std::map<ui::Accelerator, InternalData> accelerators_;
- scoped_ptr<ui::AcceleratorManager> accelerator_manager_;
-
+ scoped_ptr<AcceleratorWrapper> accelerator_wrapper_;
scoped_ptr<wm::AcceleratorFilter> accelerator_filter_;
scoped_ptr<wm::NestedAcceleratorController> nested_accelerator_controller_;
+ bool debug_accelerators_enabled_;
DISALLOW_COPY_AND_ASSIGN(AcceleratorManagerImpl);
};
diff --git a/athena/input/accelerator_manager_unittest.cc b/athena/input/accelerator_manager_unittest.cc
index cd80e8658d..4f4c753356 100644
--- a/athena/input/accelerator_manager_unittest.cc
+++ b/athena/input/accelerator_manager_unittest.cc
@@ -96,12 +96,13 @@ TEST_F(InputManagerTest, Basic) {
EXPECT_EQ(COMMAND_A, test_handler.GetFiredCommandIdAndReset());
// Debug accelerators.
+ accelerator_manager->SetDebugAcceleratorsEnabled(false);
generator.PressKey(ui::VKEY_C, ui::EF_SHIFT_DOWN);
EXPECT_EQ(kInvalidCommandId, test_handler.GetFiredCommandIdAndReset());
-
- accelerator_manager->EnableDebugAccelerators();
+ accelerator_manager->SetDebugAcceleratorsEnabled(true);
generator.PressKey(ui::VKEY_C, ui::EF_SHIFT_DOWN);
EXPECT_EQ(COMMAND_C, test_handler.GetFiredCommandIdAndReset());
+ accelerator_manager->SetDebugAcceleratorsEnabled(false);
// Non auto repeatable
generator.PressKey(ui::VKEY_D, ui::EF_SHIFT_DOWN);
@@ -109,12 +110,10 @@ TEST_F(InputManagerTest, Basic) {
generator.PressKey(ui::VKEY_D, ui::EF_SHIFT_DOWN | ui::EF_IS_REPEAT);
EXPECT_EQ(kInvalidCommandId, test_handler.GetFiredCommandIdAndReset());
- // Non reserved accelerator won't be handled unless there is
- // a view's focus manager.
- // TODO(oshima): Support view's focus manager. Investigate we can implement
- // the non reserved behavior without view's focus manager.
+ // TODO(oshima): Add scenario where the key event is consumed by
+ // an app.
generator.PressKey(ui::VKEY_E, ui::EF_SHIFT_DOWN);
- EXPECT_EQ(kInvalidCommandId, test_handler.GetFiredCommandIdAndReset());
+ EXPECT_EQ(COMMAND_E, test_handler.GetFiredCommandIdAndReset());
}
} // namespace athena
diff --git a/athena/input/input_manager_impl.cc b/athena/input/input_manager_impl.cc
index 3d1c803783..b0b11a9e39 100644
--- a/athena/input/input_manager_impl.cc
+++ b/athena/input/input_manager_impl.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "ui/aura/client/event_client.h"
#include "ui/aura/env.h"
+#include "ui/aura/window.h"
#include "ui/events/event_target.h"
namespace athena {
@@ -36,7 +37,7 @@ class InputManagerImpl : public InputManager,
// Overridden from aura::client::EventClient:
virtual bool CanProcessEventsWithinSubtree(
const aura::Window* window) const OVERRIDE {
- return true;
+ return window && !window->ignore_events();
}
virtual ui::EventTarget* GetToplevelEventTarget() OVERRIDE { return this; }
@@ -53,7 +54,8 @@ class InputManagerImpl : public InputManager,
};
InputManagerImpl::InputManagerImpl()
- : accelerator_manager_(new AcceleratorManagerImpl) {
+ : accelerator_manager_(
+ AcceleratorManagerImpl::CreateGlobalAcceleratorManager()) {
DCHECK(!instance);
instance = this;
}
diff --git a/athena/input/public/accelerator_manager.h b/athena/input/public/accelerator_manager.h
index e0a1ad447b..b572c50f75 100644
--- a/athena/input/public/accelerator_manager.h
+++ b/athena/input/public/accelerator_manager.h
@@ -6,12 +6,17 @@
#define ATHENA_INPUT_PUBLIC_ACCELERATOR_MANAGER_H_
#include "athena/athena_export.h"
+#include "base/memory/scoped_ptr.h"
#include "ui/events/keycodes/keyboard_codes.h"
namespace ui {
class Accelerator;
}
+namespace views {
+class FocusManager;
+}
+
namespace athena {
enum TriggerEvent {
@@ -53,18 +58,32 @@ class ATHENA_EXPORT AcceleratorHandler {
const ui::Accelerator& accelerator) = 0;
};
-class AcceleratorManager {
+class ATHENA_EXPORT AcceleratorManager {
public:
+ // Returns an AccelerarManager for global acelerators.
+ static AcceleratorManager* Get();
+
+ // Creates an AcceleratorManager for application windows that
+ // define their own accelerators.
+ static scoped_ptr<AcceleratorManager> CreateForFocusManager(
+ views::FocusManager* focus_manager);
+
virtual ~AcceleratorManager() {}
+ // Tells if the accelerator is registered with the given flag. If
+ // flags is AF_NONE, it simply tells if the accelerator is
+ // registered with any flags.
+ virtual bool IsRegistered(const ui::Accelerator& accelerator,
+ int flags) const = 0;
+
// Register accelerators and its handler that will be invoked when
// one of accelerator is fired.
virtual void RegisterAccelerators(const AcceleratorData accelerators[],
size_t num_accelerators,
AcceleratorHandler* handler) = 0;
- // Enables accelerators that has a AF_DEBUG flag.
- virtual void EnableDebugAccelerators() = 0;
+ // Enables/Disables accelerators that has a AF_DEBUG flag.
+ virtual void SetDebugAcceleratorsEnabled(bool enabled) = 0;
};
} // namespace athena
diff --git a/athena/main/DEPS b/athena/main/DEPS
index 2f77e06ed4..b03fcf4d45 100644
--- a/athena/main/DEPS
+++ b/athena/main/DEPS
@@ -8,6 +8,7 @@ include_rules = [
"+athena/wm/public",
"+content/public",
"+ui/aura",
+ "+ui/app_list",
"+ui/base",
"+ui/compositor",
"+ui/events",
@@ -19,8 +20,12 @@ specific_include_rules = {
"athena_main\.cc": [
"+apps/shell/app",
"+apps/shell/browser",
+ "+apps/shell/renderer",
"+content/public/app",
],
+ "athena_app_window_controller\.*": [
+ "+apps/shell/browser",
+ ],
"athena_shell\.cc": [
"+athena/test",
],
diff --git a/athena/main/athena_app_window_controller.cc b/athena/main/athena_app_window_controller.cc
new file mode 100644
index 0000000000..df44bc5b58
--- /dev/null
+++ b/athena/main/athena_app_window_controller.cc
@@ -0,0 +1,34 @@
+// 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/main/athena_app_window_controller.h"
+
+#include "apps/shell/browser/shell_app_window.h"
+#include "athena/activity/public/activity_factory.h"
+#include "athena/activity/public/activity_manager.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace athena {
+
+AthenaAppWindowController::AthenaAppWindowController() {
+}
+
+AthenaAppWindowController::~AthenaAppWindowController() {
+}
+
+apps::ShellAppWindow* AthenaAppWindowController::CreateAppWindow(
+ content::BrowserContext* context) {
+ apps::ShellAppWindow* app_window = new apps::ShellAppWindow();
+ app_window->Init(context, gfx::Size(100, 100));
+ ActivityManager::Get()->AddActivity(ActivityFactory::Get()->CreateAppActivity(
+ app_window));
+ return app_window;
+}
+
+void AthenaAppWindowController::CloseAppWindows() {
+ // Do nothing.
+}
+
+} // namespace athena
diff --git a/athena/main/athena_app_window_controller.h b/athena/main/athena_app_window_controller.h
new file mode 100644
index 0000000000..78684d5623
--- /dev/null
+++ b/athena/main/athena_app_window_controller.h
@@ -0,0 +1,31 @@
+// 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.
+
+#ifndef ATHENA_MAIN_ATHENA_APP_WINDOW_CONTROLLER_H_
+#define ATHENA_MAIN_ATHENA_APP_WINDOW_CONTROLLER_H_
+
+#include "apps/shell/browser/shell_app_window_controller.h"
+#include "base/macros.h"
+
+namespace athena {
+
+// The shell app window controller for athena. It embeds the web_contents of
+// an app window into an Athena activity.
+class AthenaAppWindowController : public apps::ShellAppWindowController {
+ public:
+ AthenaAppWindowController();
+ virtual ~AthenaAppWindowController();
+
+ // Overridden from apps::ShellAppWindowController:
+ virtual apps::ShellAppWindow* CreateAppWindow(
+ content::BrowserContext* context) OVERRIDE;
+ virtual void CloseAppWindows() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AthenaAppWindowController);
+};
+
+} // namespace athena
+
+#endif // ATHENA_MAIN_ATHENA_APP_WINDOW_CONTROLLER_H_
diff --git a/athena/main/athena_launcher.cc b/athena/main/athena_launcher.cc
index 6faa396a1c..5da92745ca 100644
--- a/athena/main/athena_launcher.cc
+++ b/athena/main/athena_launcher.cc
@@ -37,7 +37,8 @@ DEFINE_OWNED_WINDOW_PROPERTY_KEY(athena::RootWindowState,
NULL);
void StartAthena(aura::Window* root_window,
- athena::ActivityFactory* activity_factory) {
+ athena::ActivityFactory* activity_factory,
+ athena::AppModelBuilder* app_model_builder) {
#if defined(USE_X11)
ui::TouchFactory::SetTouchDeviceListFromCommandLine();
#endif
@@ -51,7 +52,7 @@ void StartAthena(aura::Window* root_window,
athena::InputManager::Create()->OnRootWindowCreated(root_window);
athena::ScreenManager::Create(root_window);
athena::WindowManager::Create();
- athena::HomeCard::Create();
+ athena::HomeCard::Create(app_model_builder);
athena::ActivityManager::Create();
athena::ActivityFactory::RegisterActivityFactory(activity_factory);
SetupBackgroundImage();
diff --git a/athena/main/athena_launcher.h b/athena/main/athena_launcher.h
index 4b36b6d71c..6ea439fcdb 100644
--- a/athena/main/athena_launcher.h
+++ b/athena/main/athena_launcher.h
@@ -11,10 +11,12 @@ class Window;
namespace athena {
class ActivityFactory;
+class AppModelBuilder;
// Starts/shuts down the athena shell environment.
void StartAthena(aura::Window* root_window,
- ActivityFactory* activity_factory);
+ ActivityFactory* activity_factory,
+ AppModelBuilder* app_model_builder);
void ShutdownAthena();
} // namespace athena
diff --git a/athena/main/athena_main.cc b/athena/main/athena_main.cc
index 99f5fa0ae2..6ac6efc6fd 100644
--- a/athena/main/athena_main.cc
+++ b/athena/main/athena_main.cc
@@ -5,13 +5,25 @@
#include "apps/shell/app/shell_main_delegate.h"
#include "apps/shell/browser/shell_browser_main_delegate.h"
#include "apps/shell/browser/shell_desktop_controller.h"
+#include "apps/shell/browser/shell_extension_system.h"
+#include "apps/shell/renderer/shell_renderer_main_delegate.h"
#include "athena/content/public/content_activity_factory.h"
+#include "athena/content/public/content_app_model_builder.h"
+#include "athena/home/public/home_card.h"
+#include "athena/main/athena_app_window_controller.h"
#include "athena/main/athena_launcher.h"
#include "athena/main/placeholder.h"
+#include "athena/main/url_search_provider.h"
+#include "base/command_line.h"
+#include "base/file_util.h"
#include "content/public/app/content_main.h"
#include "ui/aura/window_tree_host.h"
#include "ui/wm/core/visibility_controller.h"
+namespace {
+const std::string kAppSwitch = "app";
+} // namespace
+
class AthenaBrowserMainDelegate : public apps::ShellBrowserMainDelegate {
public:
AthenaBrowserMainDelegate() {}
@@ -19,9 +31,22 @@ class AthenaBrowserMainDelegate : public apps::ShellBrowserMainDelegate {
// apps::ShellBrowserMainDelegate:
virtual void Start(content::BrowserContext* context) OVERRIDE {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(kAppSwitch)) {
+ base::FilePath app_dir(command_line->GetSwitchValueNative(kAppSwitch));
+ base::FilePath app_absolute_dir = base::MakeAbsoluteFilePath(app_dir);
+ extensions::ShellExtensionSystem* extension_system =
+ static_cast<extensions::ShellExtensionSystem*>(
+ extensions::ExtensionSystem::Get(context));
+ extension_system->LoadApp(app_absolute_dir);
+ }
+
athena::StartAthena(
apps::ShellDesktopController::instance()->host()->window(),
- new athena::ContentActivityFactory());
+ new athena::ContentActivityFactory(),
+ new athena::ContentAppModelBuilder(context));
+ athena::HomeCard::Get()->RegisterSearchProvider(
+ new athena::UrlSearchProvider(context));
CreateTestPages(context);
}
@@ -30,13 +55,29 @@ class AthenaBrowserMainDelegate : public apps::ShellBrowserMainDelegate {
virtual apps::ShellDesktopController* CreateDesktopController() OVERRIDE {
// TODO(mukai): create Athena's own ShellDesktopController subclass so that
// it can initialize its own window manager logic.
- return new apps::ShellDesktopController();
+ apps::ShellDesktopController* desktop = new apps::ShellDesktopController();
+ desktop->SetAppWindowController(new athena::AthenaAppWindowController());
+ return desktop;
}
private:
DISALLOW_COPY_AND_ASSIGN(AthenaBrowserMainDelegate);
};
+class AthenaRendererMainDelegate : public apps::ShellRendererMainDelegate {
+ public:
+ AthenaRendererMainDelegate() {}
+ virtual ~AthenaRendererMainDelegate() {}
+
+ private:
+ // apps::ShellRendererMainDelegate:
+ virtual void OnThreadStarted(content::RenderThread* thread) OVERRIDE {}
+
+ virtual void OnViewCreated(content::RenderView* render_view) OVERRIDE {}
+
+ DISALLOW_COPY_AND_ASSIGN(AthenaRendererMainDelegate);
+};
+
class AthenaMainDelegate : public apps::ShellMainDelegate {
public:
AthenaMainDelegate() {}
@@ -49,6 +90,12 @@ class AthenaMainDelegate : public apps::ShellMainDelegate {
return new AthenaBrowserMainDelegate();
}
+ virtual scoped_ptr<apps::ShellRendererMainDelegate>
+ CreateShellRendererMainDelegate() OVERRIDE {
+ return scoped_ptr<apps::ShellRendererMainDelegate>(
+ new AthenaRendererMainDelegate());
+ }
+
DISALLOW_COPY_AND_ASSIGN(AthenaMainDelegate);
};
diff --git a/athena/main/athena_main.gyp b/athena/main/athena_main.gyp
index 81af2579df..09dc19741a 100644
--- a/athena/main/athena_main.gyp
+++ b/athena/main/athena_main.gyp
@@ -16,6 +16,7 @@
'../../apps/shell/app_shell.gyp:app_shell_lib',
'../../skia/skia.gyp:skia',
'../../ui/accessibility/accessibility.gyp:ax_gen',
+ '../../ui/app_list/app_list.gyp:app_list',
'../../ui/views/views.gyp:views',
'../../url/url.gyp:url_lib',
],
@@ -23,8 +24,12 @@
'../..',
],
'sources': [
+ 'athena_app_window_controller.cc',
+ 'athena_app_window_controller.h',
'athena_launcher.cc',
'athena_launcher.h',
+ 'url_search_provider.cc',
+ 'url_search_provider.h',
'athena_main.cc',
'placeholder.cc',
'placeholder.h',
@@ -41,6 +46,7 @@
'../../ui/aura/aura.gyp:aura',
'../../ui/compositor/compositor.gyp:compositor_test_support',
'../../ui/gfx/gfx.gyp:gfx',
+ '../../ui/resources/ui_resources.gyp:ui_test_pak',
'../athena.gyp:athena_lib',
'../athena.gyp:athena_test_support',
],
diff --git a/athena/main/url_search_provider.cc b/athena/main/url_search_provider.cc
new file mode 100644
index 0000000000..ce386ea286
--- /dev/null
+++ b/athena/main/url_search_provider.cc
@@ -0,0 +1,61 @@
+// 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/main/url_search_provider.h"
+
+#include "athena/activity/public/activity_factory.h"
+#include "athena/activity/public/activity_manager.h"
+#include "base/strings/utf_string_conversions.h"
+#include "ui/app_list/search_result.h"
+#include "url/gurl.h"
+
+namespace athena {
+
+namespace {
+
+class UrlSearchResult : public app_list::SearchResult {
+ public:
+ UrlSearchResult(content::BrowserContext* browser_context,
+ const base::string16& query)
+ : browser_context_(browser_context), url_(query) {
+ set_title(query);
+ app_list::SearchResult::Tags title_tags;
+ title_tags.push_back(app_list::SearchResult::Tag(
+ app_list::SearchResult::Tag::URL, 0, query.size()));
+ set_title_tags(title_tags);
+ set_id(base::UTF16ToUTF8(query));
+ }
+
+ private:
+ // Overriddenn from app_list::SearchResult:
+ virtual void Open(int event_flags) OVERRIDE {
+ ActivityManager::Get()->AddActivity(
+ ActivityFactory::Get()->CreateWebActivity(browser_context_, url_));
+ }
+
+ content::BrowserContext* browser_context_;
+ const GURL url_;
+
+ DISALLOW_COPY_AND_ASSIGN(UrlSearchResult);
+};
+
+} // namespace
+
+UrlSearchProvider::UrlSearchProvider(content::BrowserContext* browser_context)
+ : browser_context_(browser_context) {
+}
+
+UrlSearchProvider::~UrlSearchProvider() {
+}
+
+void UrlSearchProvider::Start(const base::string16& query) {
+ ClearResults();
+ Add(scoped_ptr<app_list::SearchResult>(
+ new UrlSearchResult(browser_context_, query)));
+}
+
+void UrlSearchProvider::Stop() {
+}
+
+} // namespace athena
diff --git a/athena/main/url_search_provider.h b/athena/main/url_search_provider.h
new file mode 100644
index 0000000000..6ee83014d2
--- /dev/null
+++ b/athena/main/url_search_provider.h
@@ -0,0 +1,34 @@
+// 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.
+
+#ifndef ATHENA_MAIN_URL_SEARCH_PROVIDER_H_
+#define ATHENA_MAIN_URL_SEARCH_PROVIDER_H_
+
+#include "ui/app_list/search_provider.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace athena {
+
+// A sample search provider.
+class UrlSearchProvider : public app_list::SearchProvider {
+ public:
+ UrlSearchProvider(content::BrowserContext* browser_context);
+ virtual ~UrlSearchProvider();
+
+ // Overridden from app_list::SearchProvider
+ virtual void Start(const base::string16& query) OVERRIDE;
+ virtual void Stop() OVERRIDE;
+
+ private:
+ content::BrowserContext* browser_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(UrlSearchProvider);
+};
+
+} // namespace athena
+
+#endif // ATHENA_MAIN_URL_SEARCH_PROVIDER_H_
diff --git a/athena/screen/DEPS b/athena/screen/DEPS
index 08856b1c42..0dbb68d29b 100644
--- a/athena/screen/DEPS
+++ b/athena/screen/DEPS
@@ -1,6 +1,8 @@
include_rules = [
+ "+athena/input/public",
"+ui/aura",
"+ui/compositor",
"+ui/gfx",
"+ui/views",
+ "+ui/wm",
]
diff --git a/athena/screen/background_controller.cc b/athena/screen/background_controller.cc
index 53cf3e2491..66686d0ca8 100644
--- a/athena/screen/background_controller.cc
+++ b/athena/screen/background_controller.cc
@@ -51,11 +51,13 @@ BackgroundController::BackgroundController(aura::Window* container) {
views::Widget* background_widget = new views::Widget;
views::Widget::InitParams params(
views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+ params.accept_events = false;
params.parent = container;
background_widget->Init(params);
background_widget->GetNativeWindow()->layer()->SetMasksToBounds(true);
background_view_ = new BackgroundView;
background_widget->SetContentsView(background_view_);
+ background_widget->GetNativeView()->SetName("BackgroundWidget");
background_widget->Show();
}
diff --git a/athena/screen/screen_accelerator_handler.cc b/athena/screen/screen_accelerator_handler.cc
new file mode 100644
index 0000000000..031a039dc6
--- /dev/null
+++ b/athena/screen/screen_accelerator_handler.cc
@@ -0,0 +1,96 @@
+// 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/screen/screen_accelerator_handler.h"
+
+#include "athena/input/public/accelerator_manager.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_event_dispatcher.h"
+#include "ui/aura/window_tree_host.h"
+#include "ui/compositor/debug_utils.h"
+#include "ui/wm/public/activation_client.h"
+
+namespace athena {
+namespace {
+
+enum Command {
+ CMD_PRINT_LAYER_HIERARCHY,
+ CMD_PRINT_WINDOW_HIERARCHY,
+};
+
+const int EF_ALL_DOWN =
+ ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN;
+
+const AcceleratorData accelerator_data[] = {
+ {TRIGGER_ON_PRESS, ui::VKEY_L, EF_ALL_DOWN, CMD_PRINT_LAYER_HIERARCHY,
+ AF_DEBUG},
+ {TRIGGER_ON_PRESS, ui::VKEY_W, EF_ALL_DOWN, CMD_PRINT_WINDOW_HIERARCHY,
+ AF_DEBUG},
+};
+
+void PrintLayerHierarchy(aura::Window* root_window) {
+ ui::PrintLayerHierarchy(
+ root_window->layer(),
+ root_window->GetHost()->dispatcher()->GetLastMouseLocationInRoot());
+}
+
+void PrintWindowHierarchy(aura::Window* window,
+ aura::Window* active,
+ int indent,
+ std::ostringstream* out) {
+ std::string indent_str(indent, ' ');
+ std::string name(window->name());
+ if (name.empty())
+ name = "\"\"";
+ *out << indent_str << name << " (" << window << ")"
+ << " type=" << window->type()
+ << ((window == active) ? " [active] " : " ")
+ << (window->IsVisible() ? " visible " : " ")
+ << window->bounds().ToString() << '\n';
+
+ for (size_t i = 0; i < window->children().size(); ++i)
+ PrintWindowHierarchy(window->children()[i], active, indent + 3, out);
+}
+
+void HandlePrintWindowHierarchy(aura::Window* root_window) {
+ aura::Window* active =
+ aura::client::GetActivationClient(root_window)->GetActiveWindow();
+ std::ostringstream out;
+ out << "RootWindow :\n";
+ PrintWindowHierarchy(root_window, active, 0, &out);
+ // Error so logs can be collected from end-users.
+ LOG(ERROR) << out.str();
+}
+
+} // namespace
+
+// static
+ScreenAcceleratorHandler::ScreenAcceleratorHandler(aura::Window* root_window)
+ : root_window_(root_window) {
+ AcceleratorManager::Get()->RegisterAccelerators(
+ accelerator_data, arraysize(accelerator_data), this);
+}
+
+ScreenAcceleratorHandler::~ScreenAcceleratorHandler() {
+}
+
+bool ScreenAcceleratorHandler::IsCommandEnabled(int command_id) const {
+ return true;
+}
+
+bool ScreenAcceleratorHandler::OnAcceleratorFired(
+ int command_id,
+ const ui::Accelerator& accelerator) {
+ switch (command_id) {
+ case CMD_PRINT_LAYER_HIERARCHY:
+ PrintLayerHierarchy(root_window_);
+ return true;
+ case CMD_PRINT_WINDOW_HIERARCHY:
+ HandlePrintWindowHierarchy(root_window_);
+ return true;
+ }
+ return false;
+}
+
+} // namesapce athena
diff --git a/athena/screen/screen_accelerator_handler.h b/athena/screen/screen_accelerator_handler.h
new file mode 100644
index 0000000000..7e7a9eaf20
--- /dev/null
+++ b/athena/screen/screen_accelerator_handler.h
@@ -0,0 +1,33 @@
+// 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/input/public/accelerator_manager.h"
+
+#include "base/macros.h"
+
+namespace aura {
+class Window;
+}
+
+namespace athena {
+
+// Handles screen related accelerators.
+class ScreenAcceleratorHandler : public AcceleratorHandler {
+ public:
+ explicit ScreenAcceleratorHandler(aura::Window* root_window);
+
+ private:
+ virtual ~ScreenAcceleratorHandler();
+
+ // AcceleratorHandler:
+ virtual bool IsCommandEnabled(int command_id) const OVERRIDE;
+ virtual bool OnAcceleratorFired(int command_id,
+ const ui::Accelerator& accelerator) OVERRIDE;
+
+ aura::Window* root_window_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenAcceleratorHandler);
+};
+
+} // namespace athena
diff --git a/athena/screen/screen_manager_impl.cc b/athena/screen/screen_manager_impl.cc
index ca3101a769..e426a80f87 100644
--- a/athena/screen/screen_manager_impl.cc
+++ b/athena/screen/screen_manager_impl.cc
@@ -4,12 +4,15 @@
#include "athena/screen/public/screen_manager.h"
+#include "athena/input/public/accelerator_manager.h"
#include "athena/screen/background_controller.h"
+#include "athena/screen/screen_accelerator_handler.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "ui/aura/client/window_tree_client.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/window.h"
+#include "ui/wm/core/capture_controller.h"
namespace athena {
namespace {
@@ -103,6 +106,8 @@ class ScreenManagerImpl : public ScreenManager {
scoped_ptr<BackgroundController> background_controller_;
scoped_ptr<aura::client::WindowTreeClient> window_tree_client_;
+ scoped_ptr<AcceleratorHandler> accelerator_handler_;
+ scoped_ptr< ::wm::ScopedCaptureClient> capture_client_;
DISALLOW_COPY_AND_ASSIGN(ScreenManagerImpl);
};
@@ -114,6 +119,9 @@ void ScreenManagerImpl::Init() {
background_window_->SetLayoutManager(
new FillLayoutManager(background_window_));
background_controller_.reset(new BackgroundController(background_window_));
+
+ capture_client_.reset(new ::wm::ScopedCaptureClient(root_window_));
+ accelerator_handler_.reset(new ScreenAcceleratorHandler(root_window_));
}
aura::Window* ScreenManagerImpl::CreateDefaultContainer(
diff --git a/athena/test/DEPS b/athena/test/DEPS
index 2256268a16..24ed79d008 100644
--- a/athena/test/DEPS
+++ b/athena/test/DEPS
@@ -1,7 +1,9 @@
include_rules = [
"+athena/activity",
+ "+athena/home/public",
"+athena/main",
"+third_party/skia/include",
+ "+ui/app_list",
"+ui/aura",
"+ui/base",
"+ui/compositor",
diff --git a/athena/test/athena_test_base.cc b/athena/test/athena_test_base.cc
index d1f6260369..a8ee6d3e2c 100644
--- a/athena/test/athena_test_base.cc
+++ b/athena/test/athena_test_base.cc
@@ -7,6 +7,10 @@
#include "athena/test/athena_test_helper.h"
#include "ui/compositor/test/context_factories_for_test.h"
+#if defined(USE_X11)
+#include "ui/aura/window_tree_host_x11.h"
+#endif
+
namespace athena {
namespace test {
@@ -31,6 +35,9 @@ void AthenaTestBase::SetUp() {
ui::InitializeContextFactoryForTests(enable_pixel_output);
helper_.reset(new AthenaTestHelper(&message_loop_));
+#if defined(USE_X11)
+ aura::test::SetUseOverrideRedirectWindowByDefault(true);
+#endif
helper_->SetUp(context_factory);
}
diff --git a/athena/test/athena_test_helper.cc b/athena/test/athena_test_helper.cc
index 88961bad1e..1b99ea8531 100644
--- a/athena/test/athena_test_helper.cc
+++ b/athena/test/athena_test_helper.cc
@@ -6,6 +6,7 @@
#include "athena/main/athena_launcher.h"
#include "athena/test/sample_activity_factory.h"
+#include "athena/test/test_app_model_builder.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "ui/aura/client/aura_constants.h"
@@ -22,7 +23,6 @@
#include "ui/wm/core/input_method_event_filter.h"
#if defined(USE_X11)
-#include "ui/aura/window_tree_host_x11.h"
#include "ui/base/x/x11_util.h"
#endif
@@ -36,9 +36,6 @@ AthenaTestHelper::AthenaTestHelper(base::MessageLoopForUI* message_loop)
// Disable animations during tests.
zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode(
ui::ScopedAnimationDurationScaleMode::ZERO_DURATION));
-#if defined(USE_X11)
- aura::test::SetUseOverrideRedirectWindowByDefault(true);
-#endif
}
AthenaTestHelper::~AthenaTestHelper() {
@@ -78,7 +75,9 @@ void AthenaTestHelper::SetUp(ui::ContextFactory* context_factory) {
// Ensure width != height so tests won't confuse them.
host()->SetBounds(gfx::Rect(800, 600));
- athena::StartAthena(root_window(), new SampleActivityFactory());
+ athena::StartAthena(root_window(),
+ new SampleActivityFactory(),
+ new TestAppModelBuilder());
}
void AthenaTestHelper::TearDown() {
diff --git a/athena/test/sample_activity.cc b/athena/test/sample_activity.cc
index 6b3713d61a..9f2da73e67 100644
--- a/athena/test/sample_activity.cc
+++ b/athena/test/sample_activity.cc
@@ -12,7 +12,7 @@ namespace test {
SampleActivity::SampleActivity(SkColor color,
SkColor contents_color,
- const std::string& title)
+ const base::string16& title)
: color_(color),
contents_color_(contents_color),
title_(title),
@@ -26,11 +26,14 @@ athena::ActivityViewModel* SampleActivity::GetActivityViewModel() {
return this;
}
+void SampleActivity::Init() {
+}
+
SkColor SampleActivity::GetRepresentativeColor() {
return color_;
}
-std::string SampleActivity::GetTitle() {
+base::string16 SampleActivity::GetTitle() {
return title_;
}
diff --git a/athena/test/sample_activity.h b/athena/test/sample_activity.h
index 04745a51d7..8f423056b6 100644
--- a/athena/test/sample_activity.h
+++ b/athena/test/sample_activity.h
@@ -17,7 +17,7 @@ class SampleActivity : public Activity,
public:
SampleActivity(SkColor color,
SkColor contents_color,
- const std::string& title);
+ const base::string16& title);
virtual ~SampleActivity();
private:
@@ -25,13 +25,14 @@ class SampleActivity : public Activity,
virtual athena::ActivityViewModel* GetActivityViewModel() OVERRIDE;
// athena::ActivityViewModel:
+ virtual void Init() OVERRIDE;
virtual SkColor GetRepresentativeColor() OVERRIDE;
- virtual std::string GetTitle() OVERRIDE;
+ virtual base::string16 GetTitle() OVERRIDE;
virtual views::View* GetContentsView() OVERRIDE;
SkColor color_;
SkColor contents_color_;
- std::string title_;
+ base::string16 title_;
views::View* contents_view_;
DISALLOW_COPY_AND_ASSIGN(SampleActivity);
diff --git a/athena/test/sample_activity_factory.cc b/athena/test/sample_activity_factory.cc
index af2d147776..cdd059d88e 100644
--- a/athena/test/sample_activity_factory.cc
+++ b/athena/test/sample_activity_factory.cc
@@ -7,6 +7,8 @@
#include <string>
#include "athena/test/sample_activity.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkColor.h"
#include "url/gurl.h"
@@ -16,6 +18,9 @@ namespace test {
namespace {
const SkColor kDefaultColor = SK_ColorRED;
const SkColor kDefaultContentColor = SK_ColorGREEN;
+
+const SkColor kDefaultAppColor = SK_ColorYELLOW;
+const SkColor kDefaultAppContentColor = SK_ColorBLUE;
}
SampleActivityFactory::SampleActivityFactory() {}
@@ -26,7 +31,15 @@ Activity* SampleActivityFactory::CreateWebActivity(
content::BrowserContext* browser_context,
const GURL& url) {
return new SampleActivity(
- kDefaultColor, kDefaultContentColor, url.spec());
+ kDefaultColor, kDefaultContentColor, base::UTF8ToUTF16(url.spec()));
+}
+
+Activity* SampleActivityFactory::CreateAppActivity(
+ apps::ShellAppWindow* app_window) {
+ // SampleActivityFactory can't own the |app_window|, so it must be NULL.
+ DCHECK(app_window == NULL);
+ return new SampleActivity(
+ kDefaultAppColor, kDefaultAppContentColor, base::UTF8ToUTF16("App"));
}
} // namespace test
diff --git a/athena/test/sample_activity_factory.h b/athena/test/sample_activity_factory.h
index a02d417731..38b672ac39 100644
--- a/athena/test/sample_activity_factory.h
+++ b/athena/test/sample_activity_factory.h
@@ -19,6 +19,8 @@ class SampleActivityFactory : public ActivityFactory {
// Overridden from ActivityFactory:
virtual Activity* CreateWebActivity(content::BrowserContext* browser_context,
const GURL& url) OVERRIDE;
+ virtual Activity* CreateAppActivity(
+ apps::ShellAppWindow* app_window) OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(SampleActivityFactory);
diff --git a/athena/test/test_app_model_builder.cc b/athena/test/test_app_model_builder.cc
new file mode 100644
index 0000000000..f7db8a0abe
--- /dev/null
+++ b/athena/test/test_app_model_builder.cc
@@ -0,0 +1,107 @@
+// 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/test/test_app_model_builder.h"
+
+#include "ui/app_list/app_list_item.h"
+#include "ui/app_list/app_list_model.h"
+
+namespace athena {
+
+namespace {
+
+const int kIconSize = 64;
+
+class DummyItem : public app_list::AppListItem {
+ public:
+ enum Type {
+ DUMMY_MAIL,
+ DUMMY_CALENDAR,
+ DUMMY_VIDEO,
+ DUMMY_MUSIC,
+ DUMMY_CONTACT,
+ LAST_TYPE,
+ };
+
+ static std::string GetTitle(Type type) {
+ switch (type) {
+ case DUMMY_MAIL:
+ return "mail";
+ case DUMMY_CALENDAR:
+ return "calendar";
+ case DUMMY_VIDEO:
+ return "video";
+ case DUMMY_MUSIC:
+ return "music";
+ case DUMMY_CONTACT:
+ return "contact";
+ case LAST_TYPE:
+ break;
+ }
+ NOTREACHED();
+ return "";
+ }
+
+ static std::string GetId(Type type) {
+ return std::string("id-") + GetTitle(type);
+ }
+
+ explicit DummyItem(Type type)
+ : app_list::AppListItem(GetId(type)),
+ type_(type) {
+ SetIcon(GetIcon(), false /* has_shadow */);
+ SetName(GetTitle(type_));
+ }
+
+ private:
+ gfx::ImageSkia GetIcon() const {
+ SkColor color = SK_ColorWHITE;
+ switch (type_) {
+ case DUMMY_MAIL:
+ color = SK_ColorRED;
+ break;
+ case DUMMY_CALENDAR:
+ color = SK_ColorBLUE;
+ break;
+ case DUMMY_VIDEO:
+ color = SK_ColorGREEN;
+ break;
+ case DUMMY_MUSIC:
+ color = SK_ColorYELLOW;
+ break;
+ case DUMMY_CONTACT:
+ color = SK_ColorCYAN;
+ break;
+ case LAST_TYPE:
+ NOTREACHED();
+ break;
+ }
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, kIconSize, kIconSize);
+ bitmap.allocPixels();
+ bitmap.eraseColor(color);
+ return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
+ }
+
+ Type type_;
+
+ DISALLOW_COPY_AND_ASSIGN(DummyItem);
+};
+
+} // namespace
+
+TestAppModelBuilder::TestAppModelBuilder() {
+}
+
+TestAppModelBuilder::~TestAppModelBuilder() {
+}
+
+void TestAppModelBuilder::PopulateApps(app_list::AppListModel* model) {
+ for (int i = 0; i < static_cast<int>(DummyItem::LAST_TYPE); ++i) {
+ model->AddItem(scoped_ptr<app_list::AppListItem>(
+ new DummyItem(static_cast<DummyItem::Type>(i))));
+ }
+}
+
+} // namespace athena
diff --git a/athena/test/test_app_model_builder.h b/athena/test/test_app_model_builder.h
new file mode 100644
index 0000000000..661174779e
--- /dev/null
+++ b/athena/test/test_app_model_builder.h
@@ -0,0 +1,27 @@
+// 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.
+
+#ifndef ATHENA_TEST_TEST_APP_MODEL_BUILDER_H_
+#define ATHENA_TEST_TEST_APP_MODEL_BUILDER_H_
+
+#include "athena/home/public/app_model_builder.h"
+#include "base/macros.h"
+
+namespace athena {
+
+class TestAppModelBuilder : public AppModelBuilder {
+ public:
+ TestAppModelBuilder();
+ virtual ~TestAppModelBuilder();
+
+ // Overridden from AppModelBuilder:
+ virtual void PopulateApps(app_list::AppListModel* model) OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestAppModelBuilder);
+};
+
+} // namespace athena
+
+#endif // ATHENA_TEST_TEST_APP_MODEL_BUILDER_H_
diff --git a/athena/wm/DEPS b/athena/wm/DEPS
index 5c9e0d8642..800257fffa 100644
--- a/athena/wm/DEPS
+++ b/athena/wm/DEPS
@@ -4,10 +4,5 @@ include_rules = [
"+ui/compositor",
"+ui/events",
"+ui/gfx",
+ "+ui/wm",
]
-
-specific_include_rules = {
- ".*unittest\.cc": [
- "+athena/test",
- ],
-}
diff --git a/athena/wm/window_manager_impl.cc b/athena/wm/window_manager_impl.cc
index 2c61ab1d7b..589da39073 100644
--- a/athena/wm/window_manager_impl.cc
+++ b/athena/wm/window_manager_impl.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "ui/aura/layout_manager.h"
#include "ui/aura/window.h"
+#include "ui/wm/public/window_types.h"
namespace athena {
namespace {
@@ -124,7 +125,9 @@ void WindowManagerImpl::Layout() {
for (aura::Window::Windows::const_iterator iter = children.begin();
iter != children.end();
++iter) {
- (*iter)->SetBounds(bounds);
+ if ((*iter)->type() == ui::wm::WINDOW_TYPE_NORMAL ||
+ (*iter)->type() == ui::wm::WINDOW_TYPE_POPUP)
+ (*iter)->SetBounds(bounds);
}
}
diff --git a/athena/wm/window_overview_mode.cc b/athena/wm/window_overview_mode.cc
index 8c98bcb019..16f889cab3 100644
--- a/athena/wm/window_overview_mode.cc
+++ b/athena/wm/window_overview_mode.cc
@@ -17,6 +17,7 @@
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/events/event_handler.h"
#include "ui/gfx/transform.h"
+#include "ui/wm/core/shadow.h"
namespace {
@@ -30,6 +31,8 @@ struct WindowOverviewState {
// The current overview state of the window. 0.f means the window is at the
// topmost position. 1.f means the window is at the bottom-most position.
float progress;
+
+ scoped_ptr<wm::Shadow> shadow;
};
} // namespace
@@ -140,7 +143,7 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
top_transform.Scale(kMinScale, kMinScale);
gfx::Transform bottom_transform;
- int bottom = container_size.height() - (index * kGapBetweenWindowsBottom);
+ int bottom = GetScrollableHeight() - (index * kGapBetweenWindowsBottom);
x_translate = container_size.width() * (1 - kMaxScale) / 2.;
bottom_transform.Translate(x_translate, bottom - window->bounds().y());
bottom_transform.Scale(kMaxScale, kMaxScale);
@@ -149,6 +152,7 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
state->top = top_transform;
state->bottom = bottom_transform;
state->progress = 0.f;
+ state->shadow = CreateShadowForWindow(window);
window->SetProperty(kWindowOverviewState, state);
}
}
@@ -187,6 +191,15 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
}
}
+ scoped_ptr<wm::Shadow> CreateShadowForWindow(aura::Window* window) {
+ scoped_ptr<wm::Shadow> shadow(new wm::Shadow());
+ shadow->Init(wm::Shadow::STYLE_ACTIVE);
+ shadow->SetContentBounds(gfx::Rect(window->bounds().size()));
+ shadow->layer()->SetVisible(true);
+ window->layer()->Add(shadow->layer());
+ return shadow.Pass();
+ }
+
aura::Window* SelectWindowAt(ui::LocatedEvent* event) {
CHECK_EQ(container_, event->target());
// Find the old targeter to find the target of the event.
@@ -205,24 +218,78 @@ class WindowOverviewModeImpl : public WindowOverviewMode,
return target;
}
+ // Scroll the window list by |delta_y| amount. |delta_y| is negative when
+ // scrolling up; and positive when scrolling down.
+ void DoScroll(float delta_y) {
+ const float kEpsilon = 1e-3f;
+ aura::Window::Windows windows = container_->children();
+ float delta_y_p = std::abs(delta_y) / GetScrollableHeight();
+ if (delta_y < 0) {
+ // Scroll up. Start with the top-most (i.e. behind-most in terms of
+ // z-index) window, and try to scroll them up.
+ for (aura::Window::Windows::iterator iter = windows.begin();
+ delta_y_p > kEpsilon && iter != windows.end();
+ ++iter) {
+ aura::Window* window = (*iter);
+ WindowOverviewState* state = window->GetProperty(kWindowOverviewState);
+ if (state->progress > kEpsilon) {
+ // It is possible to scroll |window| up. Scroll it up, and update
+ // |delta_y_p| for the next window.
+ float apply = delta_y_p * state->progress;
+ SetWindowProgress(window, std::max(0.f, state->progress - apply * 3));
+ delta_y_p -= apply;
+ }
+ }
+ } else {
+ // Scroll down. Start with the bottom-most (i.e. front-most in terms of
+ // z-index) window, and try to scroll them down.
+ for (aura::Window::Windows::reverse_iterator iter = windows.rbegin();
+ delta_y_p > kEpsilon && iter != windows.rend();
+ ++iter) {
+ aura::Window* window = (*iter);
+ WindowOverviewState* state = window->GetProperty(kWindowOverviewState);
+ if (1.f - state->progress > kEpsilon) {
+ // It is possible to scroll |window| down. Scroll it down, and update
+ // |delta_y_p| for the next window.
+ SetWindowProgress(window, std::min(1.f, state->progress + delta_y_p));
+ delta_y_p /= 2.f;
+ }
+ }
+ }
+ }
+
+ int GetScrollableHeight() const {
+ const float kScrollableFraction = 0.65f;
+ return container_->bounds().height() * kScrollableFraction;
+ }
+
// ui::EventHandler:
virtual void OnMouseEvent(ui::MouseEvent* mouse) OVERRIDE {
- if (mouse->type() != ui::ET_MOUSE_PRESSED)
- return;
- aura::Window* select = SelectWindowAt(mouse);
- if (select) {
- mouse->SetHandled();
- delegate_->OnSelectWindow(select);
+ if (mouse->type() == ui::ET_MOUSE_PRESSED) {
+ aura::Window* select = SelectWindowAt(mouse);
+ if (select) {
+ mouse->SetHandled();
+ delegate_->OnSelectWindow(select);
+ }
+ } else if (mouse->type() == ui::ET_MOUSEWHEEL) {
+ DoScroll(static_cast<ui::MouseWheelEvent*>(mouse)->y_offset());
}
}
+ virtual void OnScrollEvent(ui::ScrollEvent* scroll) OVERRIDE {
+ if (scroll->type() == ui::ET_SCROLL)
+ DoScroll(scroll->y_offset());
+ }
+
virtual void OnGestureEvent(ui::GestureEvent* gesture) OVERRIDE {
- if (gesture->type() != ui::ET_GESTURE_TAP)
- return;
- aura::Window* select = SelectWindowAt(gesture);
- if (select) {
- gesture->SetHandled();
- delegate_->OnSelectWindow(select);
+ if (gesture->type() == ui::ET_GESTURE_TAP) {
+ aura::Window* select = SelectWindowAt(gesture);
+ if (select) {
+ gesture->SetHandled();
+ delegate_->OnSelectWindow(select);
+ }
+ } else if (gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
+ DoScroll(gesture->details().scroll_y());
}
}