Commit ae4987d6 authored by xiyuan@chromium.org's avatar xiyuan@chromium.org

[Aura] Refactor and update app list window.

- Move showing, dimissing, animation observer, click monitoring code tha into an AppList controller in aura_shell;
- Change ShellDelegate::ShowApps to an inteface to request app list widget and having a callback to notify app list controller when the widget is ready;
- Click outside to dismiss the window.
- Hide default container when app list is visible;

BUG=98308
TEST=Verify click outside applist window to dismiss it. Browser windows should be hidden when app list window is shown and should be visible when app list is gone.


Review URL: http://codereview.chromium.org/8558031

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111021 0039d316-1c4b-4281-b951-d872f2087c98
parent 8e937860
......@@ -4,63 +4,19 @@
#include "chrome/browser/ui/views/aura/app_list_window.h"
#include "base/bind.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/views/dom_view.h"
#include "chrome/common/url_constants.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/renderer_host/render_widget_host_view.h"
#include "views/widget/widget.h"
#include "ui/aura/desktop.h"
#include "ui/gfx/compositor/layer_animator.h"
#include "ui/gfx/screen.h"
namespace {
// Gets preferred bounds of app list window in show/hide state.
gfx::Rect GetPreferredBounds(bool show) {
// The y-axis offset used at the beginning of showing animation.
static const int kMoveUpAnimationOffset = 50;
gfx::Point cursor = gfx::Screen::GetCursorScreenPoint();
gfx::Rect work_area = gfx::Screen::GetMonitorWorkAreaNearestPoint(cursor);
gfx::Rect widget_bounds(work_area);
widget_bounds.Inset(150, 100);
if (!show)
widget_bounds.Offset(0, kMoveUpAnimationOffset);
return widget_bounds;
}
ui::Layer* GetWidgetLayer(views::Widget* widget) {
return widget->GetNativeView()->layer();
}
} // namespace
// static
AppListWindow* AppListWindow::instance_ = NULL;
// static
void AppListWindow::SetVisible(bool visible) {
if (!instance_) {
instance_ = new AppListWindow;
instance_->Init();
}
instance_->DoSetVisible(visible);
}
// static
bool AppListWindow::IsVisible() {
return instance_ && instance_->is_visible_;
}
AppListWindow::AppListWindow()
AppListWindow::AppListWindow(
const aura_shell::ShellDelegate::SetWidgetCallback& callback)
: widget_(NULL),
contents_(NULL),
is_visible_(false),
content_rendered_(false) {
callback_(callback) {
Init();
}
AppListWindow::~AppListWindow() {
......@@ -74,11 +30,6 @@ views::View* AppListWindow::GetContentsView() {
return contents_;
}
void AppListWindow::WindowClosing() {
aura::Desktop::GetInstance()->RemoveObserver(this);
widget_ = NULL;
}
views::Widget* AppListWindow::GetWidget() {
return widget_;
}
......@@ -87,25 +38,6 @@ const views::Widget* AppListWindow::GetWidget() const {
return widget_;
}
void AppListWindow::OnActiveWindowChanged(aura::Window* active) {
if (widget_ && !widget_->IsActive() && is_visible_)
DoSetVisible(false);
}
void AppListWindow::OnLayerAnimationEnded(
const ui::LayerAnimationSequence* sequence) {
if (!is_visible_ )
widget_->Close();
}
void AppListWindow::OnLayerAnimationAborted(
const ui::LayerAnimationSequence* sequence) {
}
void AppListWindow::OnLayerAnimationScheduled(
const ui::LayerAnimationSequence* sequence) {
}
void AppListWindow::OnRenderHostCreated(RenderViewHost* host) {
}
......@@ -113,13 +45,7 @@ void AppListWindow::OnTabMainFrameLoaded() {
}
void AppListWindow::OnTabMainFrameFirstRender() {
content_rendered_ = true;
// Do deferred show animation if necessary.
if (is_visible_ && GetWidgetLayer(widget_)->opacity() == 0) {
is_visible_ = false;
DoSetVisible(true);
}
callback_.Run(widget_);
}
void AppListWindow::Init() {
......@@ -130,7 +56,6 @@ void AppListWindow::Init() {
TabContents* tab = contents_->dom_contents()->tab_contents();
tab_watcher_.reset(new TabFirstRenderWatcher(tab, this));
content_rendered_ = false;
contents_->LoadURL(GURL(chrome::kChromeUIAppListURL));
......@@ -145,7 +70,10 @@ void AppListWindow::Init() {
views::Widget::InitParams widget_params(
views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
widget_params.bounds = GetPreferredBounds(false);
// A non-empty bounds so that we get rendered notification. Make the size
// close the final size so that card slider resize handler does no generate
// unexpected animation.
widget_params.bounds = gfx::Rect(0, 0, 900, 700);
widget_params.delegate = this;
widget_params.keep_on_top = true;
widget_params.transparent = true;
......@@ -153,32 +81,4 @@ void AppListWindow::Init() {
widget_ = new views::Widget;
widget_->Init(widget_params);
widget_->SetContentsView(contents_);
widget_->SetOpacity(0);
GetWidgetLayer(widget_)->GetAnimator()->AddObserver(this);
aura::Desktop::GetInstance()->AddObserver(this);
}
void AppListWindow::DoSetVisible(bool visible) {
if (visible == is_visible_)
return;
is_visible_ = visible;
// Skip show animation if contents is not rendered.
// TODO(xiyuan): Should we show a loading UI if it takes too long?
if (visible && !content_rendered_)
return;
ui::Layer* layer = GetWidgetLayer(widget_);
ui::LayerAnimator::ScopedSettings settings(layer->GetAnimator());
layer->SetBounds(GetPreferredBounds(visible));
layer->SetOpacity(visible ? 1.0 : 0.0);
if (visible) {
widget_->Show();
widget_->Activate();
} else {
instance_ = NULL; // Closing and don't reuse this instance_.
}
}
......@@ -8,8 +8,7 @@
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/tab_first_render_watcher.h"
#include "ui/aura/desktop_observer.h"
#include "ui/gfx/compositor/layer_animation_observer.h"
#include "ui/aura_shell/shell_delegate.h"
#include "views/widget/widget_delegate.h"
class DOMView;
......@@ -19,38 +18,20 @@ class Widget;
}
class AppListWindow : public views::WidgetDelegate,
public aura::DesktopObserver,
public ui::LayerAnimationObserver,
public TabFirstRenderWatcher::Delegate {
public:
// Show/hide app list window.
static void SetVisible(bool visible);
// Whether app list window is visible (shown or being shown).
static bool IsVisible();
explicit AppListWindow(
const aura_shell::ShellDelegate::SetWidgetCallback& callback);
private:
AppListWindow();
virtual ~AppListWindow();
// views::WidgetDelegate overrides:
virtual void DeleteDelegate() OVERRIDE;
virtual views::View* GetContentsView() OVERRIDE;
virtual void WindowClosing() OVERRIDE;
virtual views::Widget* GetWidget() OVERRIDE;
virtual const views::Widget* GetWidget() const OVERRIDE;
// aura::DesktopObserver overrides:
virtual void OnActiveWindowChanged(aura::Window* active) OVERRIDE;
// ui::LayerAnimationObserver overrides:
virtual void OnLayerAnimationEnded(
const ui::LayerAnimationSequence* sequence) OVERRIDE;
virtual void OnLayerAnimationAborted(
const ui::LayerAnimationSequence* sequence) OVERRIDE;
virtual void OnLayerAnimationScheduled(
const ui::LayerAnimationSequence* sequence) OVERRIDE;
// TabFirstRenderWatcher::Delegate implementation:
virtual void OnRenderHostCreated(RenderViewHost* host) OVERRIDE;
virtual void OnTabMainFrameLoaded() OVERRIDE;
......@@ -59,22 +40,14 @@ class AppListWindow : public views::WidgetDelegate,
// Initializes the window.
void Init();
// Shows/hides the window.
void DoSetVisible(bool visible);
// Current visible app list window.
static AppListWindow* instance_;
views::Widget* widget_;
DOMView* contents_;
bool is_visible_;
// Monitors TabContents and set |content_rendered_| flag when it's rendered.
scoped_ptr<TabFirstRenderWatcher> tab_watcher_;
// Flag of whether the web contents is rendered. Showing animation is
// deferred until this flag is set to true.
bool content_rendered_;
// Callback to set app list widget when it's ready.
aura_shell::ShellDelegate::SetWidgetCallback callback_;
DISALLOW_COPY_AND_ASSIGN(AppListWindow);
};
......
......@@ -57,8 +57,9 @@ views::Widget* ChromeShellDelegate::CreateStatusArea() {
return status_area_widget;
}
void ChromeShellDelegate::ShowApps() {
AppListWindow::SetVisible(!AppListWindow::IsVisible());
void ChromeShellDelegate::RequestAppListWidget(
const SetWidgetCallback& callback) {
new AppListWindow(callback); // AppListWindow deletes itself when closed.
}
void ChromeShellDelegate::LauncherItemClicked(
......
......@@ -37,7 +37,7 @@ class ChromeShellDelegate : public aura_shell::ShellDelegate {
// aura_shell::ShellDelegate overrides;
virtual void CreateNewWindow() OVERRIDE;
virtual views::Widget* CreateStatusArea() OVERRIDE;
virtual void ShowApps() OVERRIDE;
virtual void RequestAppListWidget(const SetWidgetCallback& callback) OVERRIDE;
virtual void LauncherItemClicked(
const aura_shell::LauncherItem& item) OVERRIDE;
virtual bool ConfigureLauncherItem(aura_shell::LauncherItem* item) OVERRIDE;
......
// Copyright (c) 2011 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 "ui/aura_shell/app_list.h"
#include "base/bind.h"
#include "ui/aura/event.h"
#include "ui/aura/window.h"
#include "ui/aura_shell/shell.h"
#include "ui/aura_shell/shell_delegate.h"
#include "ui/aura_shell/shell_window_ids.h"
#include "ui/gfx/screen.h"
namespace aura_shell {
namespace internal {
namespace {
// Gets preferred bounds of app list window in show/hide state.
gfx::Rect GetPreferredBounds(bool show) {
// The y-axis offset used at the beginning of showing animation.
static const int kMoveUpAnimationOffset = 50;
gfx::Point cursor = gfx::Screen::GetCursorScreenPoint();
gfx::Rect work_area = gfx::Screen::GetMonitorWorkAreaNearestPoint(cursor);
gfx::Rect widget_bounds(work_area);
widget_bounds.Inset(150, 100);
if (!show)
widget_bounds.Offset(0, kMoveUpAnimationOffset);
return widget_bounds;
}
ui::Layer* GetLayer(views::Widget* widget) {
return widget->GetNativeView()->layer();
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
// AppList, public:
AppList::AppList()
: aura::EventFilter(NULL),
is_visible_(false),
widget_(NULL),
ALLOW_THIS_IN_INITIALIZER_LIST(set_widget_factory_(this)) {
}
AppList::~AppList() {
ResetWidget();
}
void AppList::SetVisible(bool visible) {
if (visible == is_visible_)
return;
is_visible_ = visible;
if (widget_) {
ScheduleAnimation();
} else if (is_visible_ && !set_widget_factory_.HasWeakPtrs()) {
Shell::GetInstance()->delegate()->RequestAppListWidget(
base::Bind(&AppList::SetWidget, set_widget_factory_.GetWeakPtr()));
}
}
bool AppList::IsVisible() {
return widget_ && widget_->IsVisible();
}
////////////////////////////////////////////////////////////////////////////////
// AppList, private:
void AppList::SetWidget(views::Widget* widget) {
DCHECK(widget_ == NULL);
set_widget_factory_.InvalidateWeakPtrs();
if (is_visible_) {
widget_ = widget;
widget_->AddObserver(this);
GetLayer(widget_)->GetAnimator()->AddObserver(this);
Shell::GetInstance()->AddDesktopEventFilter(this);
widget_->SetBounds(GetPreferredBounds(false));
widget_->SetOpacity(0);
ScheduleAnimation();
widget_->Show();
widget_->Activate();
} else {
widget->Close();
}
}
void AppList::ResetWidget() {
if (!widget_)
return;
widget_->RemoveObserver(this);
GetLayer(widget_)->GetAnimator()->RemoveObserver(this);
Shell::GetInstance()->RemoveDesktopEventFilter(this);
widget_ = NULL;
}
void AppList::ScheduleAnimation() {
ui::Layer* layer = GetLayer(widget_);
ui::LayerAnimator::ScopedSettings app_list_animation(layer->GetAnimator());
layer->SetBounds(GetPreferredBounds(is_visible_));
layer->SetOpacity(is_visible_ ? 1.0 : 0.0);
ui::Layer* default_container_layer = Shell::GetInstance()->GetContainer(
internal::kShellWindowId_DefaultContainer)->layer();
ui::LayerAnimator::ScopedSettings default_container_animation(
default_container_layer->GetAnimator());
default_container_layer->SetOpacity(is_visible_ ? 0.0 : 1.0);
}
////////////////////////////////////////////////////////////////////////////////
// AppList, aura::EventFilter implementation:
bool AppList::PreHandleKeyEvent(aura::Window* target,
aura::KeyEvent* event) {
return false;
}
bool AppList::PreHandleMouseEvent(aura::Window* target,
aura::MouseEvent* event) {
if (widget_ && is_visible_ && event->type() == ui::ET_MOUSE_PRESSED) {
aura::MouseEvent translated(*event, target, widget_->GetNativeView());
if (!widget_->GetNativeView()->ContainsPoint(translated.location()))
SetVisible(false);
}
return false;
}
ui::TouchStatus AppList::PreHandleTouchEvent(aura::Window* target,
aura::TouchEvent* event) {
return ui::TOUCH_STATUS_UNKNOWN;
}
////////////////////////////////////////////////////////////////////////////////
// AppList, ui::LayerAnimationObserver implementation:
void AppList::OnLayerAnimationEnded(
const ui::LayerAnimationSequence* sequence) {
if (!is_visible_ )
widget_->Close();
}
void AppList::OnLayerAnimationAborted(
const ui::LayerAnimationSequence* sequence) {
}
void AppList::OnLayerAnimationScheduled(
const ui::LayerAnimationSequence* sequence) {
}
////////////////////////////////////////////////////////////////////////////////
// AppList, views::Widget::Observer implementation:
void AppList::OnWidgetClosing(views::Widget* widget) {
DCHECK(widget_ == widget);
ResetWidget();
}
void AppList::OnWidgetActivationChanged(views::Widget* widget, bool active) {
DCHECK(widget_ == widget);
if (widget_ && is_visible_ && !active)
SetVisible(false);
}
} // namespace internal
} // namespace aura_shell
// Copyright (c) 2011 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 UI_AURA_SHELL_APP_LIST_H_
#define UI_AURA_SHELL_APP_LIST_H_
#pragma once
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
#include "ui/aura/event_filter.h"
#include "ui/gfx/compositor/layer_animation_observer.h"
#include "views/widget/widget.h"
namespace aura_shell {
namespace internal {
// AppList is a controller that manages app list UI for shell. To show the UI,
// it requests app list widget from ShellDelegate and shows it when ready.
// While the UI is visible, it monitors things such as app list widget's
// activation state and desktop mouse click to auto dismiss the UI.
class AppList : public aura::EventFilter,
public ui::LayerAnimationObserver,
public views::Widget::Observer {
public:
AppList();
virtual ~AppList();
// Show/hide app list window.
void SetVisible(bool visible);
// Whether app list window is visible (shown or being shown).
bool IsVisible();
private:
// Sets app list widget. If we are in visible mode, start showing animation.
// Otherwise, we just close the widget.
void SetWidget(views::Widget* widget);
// Forgets the widget.
void ResetWidget();
// Starts show/hide animation.
void ScheduleAnimation();
// aura::EventFilter overrides:
virtual bool PreHandleKeyEvent(aura::Window* target,
aura::KeyEvent* event) OVERRIDE;
virtual bool PreHandleMouseEvent(aura::Window* target,
aura::MouseEvent* event) OVERRIDE;
virtual ui::TouchStatus PreHandleTouchEvent(aura::Window* target,
aura::TouchEvent* event) OVERRIDE;
// ui::LayerAnimationObserver overrides:
virtual void OnLayerAnimationEnded(
const ui::LayerAnimationSequence* sequence) OVERRIDE;
virtual void OnLayerAnimationAborted(
const ui::LayerAnimationSequence* sequence) OVERRIDE;
virtual void OnLayerAnimationScheduled(
const ui::LayerAnimationSequence* sequence) OVERRIDE;
// views::Widget::Observer overrides:
virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE;
virtual void OnWidgetActivationChanged(views::Widget* widget,
bool active) OVERRIDE;
// Whether we should show or hide app list widget.
bool is_visible_;
// App list widget we get from ShellDelegate.
views::Widget* widget_;
// A weak ptr factory for callbacks that ShellDelegate used to set widget.
base::WeakPtrFactory<AppList> set_widget_factory_;
DISALLOW_COPY_AND_ASSIGN(AppList);
};
} // namespace internal
} // namespace aura_shell
#endif // UI_AURA_SHELL_APP_LIST_H_
......@@ -35,6 +35,8 @@
# All .cc, .h under views, except unittests
'always_on_top_controller.cc',
'always_on_top_controller.h',
'app_list.cc',
'app_list.h',
'default_container_event_filter.cc',
'default_container_event_filter.h',
'default_container_layout_manager.cc',
......
......@@ -15,10 +15,40 @@
#include "ui/aura_shell/shell_factory.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_paths.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/compositor/test/compositor_test_support.h"
#include "views/widget/widget_delegate.h"
#include "views/widget/widget.h"
namespace {
class AppListWindow : public views::WidgetDelegateView {
public:
AppListWindow() {
}
// static
static views::Widget* Create() {
AppListWindow* app_list = new AppListWindow;
views::Widget::InitParams widget_params(
views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
widget_params.delegate = app_list;
widget_params.keep_on_top = true;
widget_params.transparent = true;
views::Widget* widget = new views::Widget;
widget->Init(widget_params);
widget->SetContentsView(app_list);
return widget;
}
// Overridden from views::View:
virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
canvas->FillRect(SkColorSetARGB(0x4F, 0xFF, 0, 0), bounds());
}
};
class ShellDelegateImpl : public aura_shell::ShellDelegate {
public:
ShellDelegateImpl() {
......@@ -35,8 +65,9 @@ class ShellDelegateImpl : public aura_shell::ShellDelegate {
return aura_shell::internal::CreateStatusArea();
}
virtual void ShowApps() OVERRIDE {
NOTIMPLEMENTED();
virtual void RequestAppListWidget(
const SetWidgetCallback& callback) OVERRIDE {
callback.Run(AppListWindow::Create());
}
virtual void LauncherItemClicked(
......
......@@ -598,7 +598,7 @@ void LauncherView::ButtonPressed(views::Button* sender,
if (sender == new_browser_button_) {
delegate->CreateNewWindow();
} else if (sender == show_apps_button_) {
delegate->ShowApps();
Shell::GetInstance()->ToggleAppList();
} else if (sender == overflow_button_) {
ShowOverflowMenu();
} else {
......
......@@ -12,6 +12,7 @@
#include "ui/aura/desktop.h"
#include "ui/aura/window.h"
#include "ui/aura/window_types.h"
#include "ui/aura_shell/app_list.h"
#include "ui/aura_shell/default_container_event_filter.h"
#include "ui/aura_shell/default_container_layout_manager.h"
#include "ui/aura_shell/desktop_event_filter.h"
......@@ -219,6 +220,12 @@ void Shell::ToggleOverview() {
workspace_controller_->ToggleOverview();
}
void Shell::ToggleAppList() {
if (!app_list_.get())
app_list_.reset(new internal::AppList);
app_list_->SetVisible(!app_list_->IsVisible());
}
////////////////////////////////////////////////////////////////////////////////
// Shell, private:
......
......@@ -30,6 +30,7 @@ class Launcher;
class ShellDelegate;
namespace internal {
class AppList;
class DragDropController;
class ShadowController;
class ShelfLayoutController;
......@@ -62,6 +63,9 @@ class AURA_SHELL_EXPORT Shell {
// Toggles between overview mode and normal mode.
void ToggleOverview();
// Toggles app list.
void ToggleAppList();
ShellDelegate* delegate() { return delegate_.get(); }
Launcher* launcher() { return launcher_.get(); }
......@@ -91,6 +95,8 @@ class AURA_SHELL_EXPORT Shell {
scoped_ptr<Launcher> launcher_;
scoped_ptr<internal::AppList> app_list_;
scoped_ptr<internal::DragDropController> drag_drop_controller_;
scoped_ptr<internal::WorkspaceController> workspace_controller_;
scoped_ptr<internal::ShelfLayoutController> shelf_layout_controller_;
......
......@@ -6,6 +6,7 @@
#define UI_AURA_SHELL_SHELL_DELEGATE_H_
#pragma once
#include "base/callback.h"
#include "ui/aura_shell/aura_shell_export.h"
namespace views {
......@@ -19,6 +20,9 @@ struct LauncherItem;
// Delegate of the Shell.
class AURA_SHELL_EXPORT ShellDelegate {
public:
// Callback to pass back a widget used by RequestAppListWidget.
typedef base::Callback<void(views::Widget*)> SetWidgetCallback;
// The Shell owns the delegate.
virtual ~ShellDelegate() {}
......@@ -29,8 +33,9 @@ class AURA_SHELL_EXPORT ShellDelegate {
// Invoked to create a new status area. Can return NULL.
virtual views::Widget* CreateStatusArea() = 0;
// Invoked when the user clicks the app list button on the launcher.
virtual void ShowApps() = 0;
// Invoked to create app list widget. The Delegate calls the callback
// when the widget is ready to show.
virtual void RequestAppListWidget(const SetWidgetCallback& callback) = 0;
// Invoked when the user clicks on a window entry in the launcher.
virtual void LauncherItemClicked(const LauncherItem& item) = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment