diff options
author | dzhioev@chromium.org <dzhioev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-12 22:07:01 +0000 |
---|---|---|
committer | dzhioev@chromium.org <dzhioev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-12-12 22:07:01 +0000 |
commit | a5c78806b1a745b41f1c900adb3c9bdc9789a6d2 (patch) | |
tree | 0e739a606d8b50dd81a77075fe1e3accbbeb4bbb | |
parent | 1cbf5e53835a5943813049cc5ea1cd51f54f3ecf (diff) | |
download | chromium_src-a5c78806b1a745b41f1c900adb3c9bdc9789a6d2.zip chromium_src-a5c78806b1a745b41f1c900adb3c9bdc9789a6d2.tar.gz chromium_src-a5c78806b1a745b41f1c900adb3c9bdc9789a6d2.tar.bz2 |
Windows and notifications are hidden during first-run tutorial.
Windows are hidden by hiding kShellWindowId_DefaultContainer and
kShellWindowId_AlwaysOnTopContainer.
NotificationBlocker used for hiding notifications.
BUG=269286
TEST=ash_unittests --gtest_filter=FirstRunHelperTest*
Review URL: https://codereview.chromium.org/99673003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@240436 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ash/ash.gyp | 5 | ||||
-rw-r--r-- | ash/first_run/desktop_cleaner.cc | 118 | ||||
-rw-r--r-- | ash/first_run/desktop_cleaner.h | 46 | ||||
-rw-r--r-- | ash/first_run/first_run_helper.cc | 8 | ||||
-rw-r--r-- | ash/first_run/first_run_helper.h | 17 | ||||
-rw-r--r-- | ash/first_run/first_run_helper_impl.cc | 6 | ||||
-rw-r--r-- | ash/first_run/first_run_helper_impl.h | 2 | ||||
-rw-r--r-- | ash/first_run/first_run_helper_unittest.cc | 147 | ||||
-rw-r--r-- | ash/root_window_controller.cc | 26 | ||||
-rw-r--r-- | ash/root_window_controller.h | 3 | ||||
-rw-r--r-- | ash/wm/stacking_controller.cc | 10 | ||||
-rw-r--r-- | chrome/browser/chromeos/first_run/first_run_controller.cc | 7 | ||||
-rw-r--r-- | chrome/browser/chromeos/first_run/first_run_controller.h | 11 |
13 files changed, 382 insertions, 24 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp index 089ea15..f3fcb55 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -137,6 +137,8 @@ 'drag_drop/drag_image_view.cc', 'drag_drop/drag_image_view.h', 'event_rewriter_delegate.h', + 'first_run/desktop_cleaner.cc', + 'first_run/desktop_cleaner.h', 'first_run/first_run_helper.cc', 'first_run/first_run_helper.h', 'first_run/first_run_helper_impl.cc', @@ -909,6 +911,9 @@ 'dependencies': [ '../chromeos/chromeos.gyp:power_manager_proto', ], + 'sources': [ + 'first_run/first_run_helper_unittest.cc', + ], }], ['OS=="linux" and component=="shared_library" and linux_use_tcmalloc==1', { 'dependencies': [ diff --git a/ash/first_run/desktop_cleaner.cc b/ash/first_run/desktop_cleaner.cc new file mode 100644 index 0000000..cf0ffa6 --- /dev/null +++ b/ash/first_run/desktop_cleaner.cc @@ -0,0 +1,118 @@ +// Copyright 2013 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 "ash/first_run/desktop_cleaner.h" + +#include "ash/shell.h" +#include "ash/shell_window_ids.h" +#include "ui/aura/root_window.h" +#include "ui/aura/window_observer.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification_blocker.h" + +namespace ash { +namespace internal { + +namespace { + +const int kContainerIdsToHide[] = { + kShellWindowId_DefaultContainer, + kShellWindowId_AlwaysOnTopContainer, + kShellWindowId_PanelContainer, + // TODO(dzhioev): uncomment this when issue with BrowserView::CanActivate + // will be fixed. + // kShellWindowId_SystemModalContainer +}; + +} // namespace + +class ContainerHider : public aura::WindowObserver, + public ui::ImplicitAnimationObserver { + public: + explicit ContainerHider(aura::Window* container) + : container_was_hidden_(!container->IsVisible()), + container_(container) { + if (container_was_hidden_) + return; + ui::Layer* layer = container_->layer(); + ui::ScopedLayerAnimationSettings animation_settings(layer->GetAnimator()); + animation_settings.AddObserver(this); + layer->SetOpacity(0.0); + } + + virtual ~ContainerHider() { + if (container_was_hidden_ || !container_) + return; + if (!WasAnimationCompletedForProperty(ui::LayerAnimationElement::OPACITY)) { + // We are in the middle of animation. + StopObservingImplicitAnimations(); + } else { + container_->Show(); + } + ui::Layer* layer = container_->layer(); + ui::ScopedLayerAnimationSettings animation_settings(layer->GetAnimator()); + layer->SetOpacity(1.0); + } + + private: + // Overriden from ui::ImplicitAnimationObserver. + virtual void OnImplicitAnimationsCompleted() OVERRIDE { + container_->Hide(); + } + + // Overriden from aura::WindowObserver. + virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { + DCHECK(window == container_); + container_ = NULL; + } + + const bool container_was_hidden_; + aura::Window* container_; + + DISALLOW_COPY_AND_ASSIGN(ContainerHider); +}; + +class NotificationBlocker : public message_center::NotificationBlocker { + public: + NotificationBlocker() + : message_center::NotificationBlocker( + message_center::MessageCenter::Get()) { + NotifyBlockingStateChanged(); + } + + virtual ~NotificationBlocker() {}; + + private: + // Overriden from message_center::NotificationBlocker. + virtual bool ShouldShowNotificationAsPopup( + const message_center::NotifierId& notifier_id) const OVERRIDE { + return false; + } + + DISALLOW_COPY_AND_ASSIGN(NotificationBlocker); +}; + +DesktopCleaner::DesktopCleaner() { + // TODO(dzhioev): Add support for secondary displays. + aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow(); + for (size_t i = 0; i < arraysize(kContainerIdsToHide); ++i) { + aura::Window* container = + Shell::GetContainer(root_window, kContainerIdsToHide[i]); + container_hiders_.push_back(make_linked_ptr(new ContainerHider(container))); + } + notification_blocker_.reset(new NotificationBlocker()); +} + +DesktopCleaner::~DesktopCleaner() {} + +// static +std::vector<int> DesktopCleaner::GetContainersToHideForTest() { + return std::vector<int>(kContainerIdsToHide, + kContainerIdsToHide + arraysize(kContainerIdsToHide)); +} + +} // namespace internal +} // namespace ash + diff --git a/ash/first_run/desktop_cleaner.h b/ash/first_run/desktop_cleaner.h new file mode 100644 index 0000000..c3077b4 --- /dev/null +++ b/ash/first_run/desktop_cleaner.h @@ -0,0 +1,46 @@ +// Copyright 2013 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 ASH_FIRST_RUN_DESKTOP_CLEANER_ +#define ASH_FIRST_RUN_DESKTOP_CLEANER_ + +#include <vector> + +#include "ash/ash_export.h" +#include "base/basictypes.h" +#include "base/memory/linked_ptr.h" +#include "base/memory/scoped_ptr.h" + +namespace ash { + +namespace test { +class FirstRunHelperTest; +} + +namespace internal { + +class ContainerHider; +class NotificationBlocker; + +// Class used to "clean" ash desktop, i.e. hide all windows and notifications. +class ASH_EXPORT DesktopCleaner { + public: + DesktopCleaner(); + ~DesktopCleaner(); + + private: + // Returns the list of containers that DesctopCleaner hides. + static std::vector<int> GetContainersToHideForTest(); + + std::vector<linked_ptr<ContainerHider> > container_hiders_; + scoped_ptr<NotificationBlocker> notification_blocker_; + + friend class ash::test::FirstRunHelperTest; + DISALLOW_COPY_AND_ASSIGN(DesktopCleaner); +}; + +} // namespace internal +} // namespace ash + +#endif // ASH_FIRST_RUN_DESKTOP_CLEANER_ diff --git a/ash/first_run/first_run_helper.cc b/ash/first_run/first_run_helper.cc index 684bb39..aab0f10 100644 --- a/ash/first_run/first_run_helper.cc +++ b/ash/first_run/first_run_helper.cc @@ -9,5 +9,13 @@ namespace ash { FirstRunHelper::FirstRunHelper() {} FirstRunHelper::~FirstRunHelper() {} +void FirstRunHelper::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void FirstRunHelper::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + } // namespace chromeos diff --git a/ash/first_run/first_run_helper.h b/ash/first_run/first_run_helper.h index b10721c..42bc697 100644 --- a/ash/first_run/first_run_helper.h +++ b/ash/first_run/first_run_helper.h @@ -7,6 +7,7 @@ #include "ash/ash_export.h" #include "base/basictypes.h" +#include "base/observer_list.h" namespace gfx { class Rect; @@ -23,9 +24,20 @@ namespace ash { // All returned coordinates are in screen coordinate system. class ASH_EXPORT FirstRunHelper { public: + class Observer { + public: + // Called when first-run UI was cancelled. + virtual void OnCancelled() = 0; + virtual ~Observer() {} + }; + + public: FirstRunHelper(); virtual ~FirstRunHelper(); + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + // Returns widget to place tutorial UI into it. virtual views::Widget* GetOverlayWidget() = 0; @@ -58,7 +70,12 @@ class ASH_EXPORT FirstRunHelper { // bubble before calling this method. virtual gfx::Rect GetHelpButtonBounds() = 0; + protected: + ObserverList<Observer>& observers() { return observers_; } + private: + ObserverList<Observer> observers_; + DISALLOW_COPY_AND_ASSIGN(FirstRunHelper); }; diff --git a/ash/first_run/first_run_helper_impl.cc b/ash/first_run/first_run_helper_impl.cc index 44de973..9efb0db 100644 --- a/ash/first_run/first_run_helper_impl.cc +++ b/ash/first_run/first_run_helper_impl.cc @@ -42,6 +42,8 @@ FirstRunHelperImpl::FirstRunHelperImpl() FirstRunHelperImpl::~FirstRunHelperImpl() { Shell::GetInstance()->overlay_filter()->Deactivate(); + if (IsTrayBubbleOpened()) + CloseTrayBubble(); widget_->Close(); } @@ -78,11 +80,11 @@ gfx::Rect FirstRunHelperImpl::GetAppListBounds() { } void FirstRunHelperImpl::Cancel() { - NOTIMPLEMENTED(); + FOR_EACH_OBSERVER(Observer, observers(), OnCancelled()); } bool FirstRunHelperImpl::IsCancelingKeyEvent(ui::KeyEvent* event) { - return false; + return event->key_code() == ui::VKEY_ESCAPE; } aura::Window* FirstRunHelperImpl::GetWindow() { diff --git a/ash/first_run/first_run_helper_impl.h b/ash/first_run/first_run_helper_impl.h index 9d3625a..e788f6a 100644 --- a/ash/first_run/first_run_helper_impl.h +++ b/ash/first_run/first_run_helper_impl.h @@ -6,6 +6,7 @@ #define ASH_FIRST_RUN_FIRST_RUN_HELPER_IMPL_H_ #include "ash/first_run/first_run_helper.h" +#include "ash/first_run/desktop_cleaner.h" #include "ash/wm/overlay_event_filter.h" #include "base/compiler_specific.h" @@ -39,6 +40,7 @@ class FirstRunHelperImpl : public FirstRunHelper, private: views::Widget* widget_; + internal::DesktopCleaner cleaner_; DISALLOW_COPY_AND_ASSIGN(FirstRunHelperImpl); }; diff --git a/ash/first_run/first_run_helper_unittest.cc b/ash/first_run/first_run_helper_unittest.cc new file mode 100644 index 0000000..4bac723 --- /dev/null +++ b/ash/first_run/first_run_helper_unittest.cc @@ -0,0 +1,147 @@ +// Copyright 2013 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 "ash/first_run/first_run_helper.h" + +#include "ash/first_run/desktop_cleaner.h" +#include "ash/shell.h" +#include "ash/shell_window_ids.h" +#include "ash/test/ash_test_base.h" +#include "ui/aura/test/event_generator.h" +#include "ui/events/event_handler.h" +#include "ui/views/window/dialog_delegate.h" + +namespace ash { +namespace test { + +namespace { + +class TestModalDialogDelegate : public views::DialogDelegateView { + public: + TestModalDialogDelegate() {} + virtual ~TestModalDialogDelegate() {} + + // Overridden from views::WidgetDelegate: + virtual ui::ModalType GetModalType() const OVERRIDE { + return ui::MODAL_TYPE_SYSTEM; + } + + private: + DISALLOW_COPY_AND_ASSIGN(TestModalDialogDelegate); +}; + +class CountingEventHandler : public ui::EventHandler { + public: + // Handler resets |*mouse_events_registered_| during construction and updates + // it after each registered event. + explicit CountingEventHandler(int* mouse_events_registered) + : mouse_events_registered_(mouse_events_registered) { + *mouse_events_registered = 0; + } + + virtual ~CountingEventHandler() {} + + private: + // ui::EventHandler overrides. + virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { + ++*mouse_events_registered_; + } + + int* mouse_events_registered_; + + DISALLOW_COPY_AND_ASSIGN(CountingEventHandler); +}; + +} // namespace + +class FirstRunHelperTest : public AshTestBase, + public FirstRunHelper::Observer { + public: + FirstRunHelperTest() : cancelled_times_(0) {} + + virtual ~FirstRunHelperTest() {} + + virtual void SetUp() OVERRIDE { + AshTestBase::SetUp(); + CheckContainersAreVisible(); + helper_.reset(ash::Shell::GetInstance()->CreateFirstRunHelper()); + helper_->AddObserver(this); + helper_->GetOverlayWidget()->Show(); + } + + virtual void TearDown() OVERRIDE { + EXPECT_TRUE(helper_.get()); + helper_.reset(); + CheckContainersAreVisible(); + AshTestBase::TearDown(); + } + + void CheckContainersAreVisible() const { + aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow(); + std::vector<int> containers_to_check = + internal::DesktopCleaner::GetContainersToHideForTest(); + for (size_t i = 0; i < containers_to_check.size(); ++i) { + aura::Window* container = + Shell::GetContainer(root_window, containers_to_check[i]); + EXPECT_TRUE(container->IsVisible()); + } + } + + void CheckContainersAreHidden() const { + aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow(); + std::vector<int> containers_to_check = + internal::DesktopCleaner::GetContainersToHideForTest(); + for (size_t i = 0; i < containers_to_check.size(); ++i) { + aura::Window* container = + Shell::GetContainer(root_window, containers_to_check[i]); + EXPECT_TRUE(!container->IsVisible()); + } + } + + FirstRunHelper* helper() { return helper_.get(); } + + int cancelled_times() const { return cancelled_times_; } + + private: + // FirstRunHelper::Observer overrides. + virtual void OnCancelled() OVERRIDE { + ++cancelled_times_; + } + + scoped_ptr<FirstRunHelper> helper_; + int cancelled_times_; + + DISALLOW_COPY_AND_ASSIGN(FirstRunHelperTest); +}; + +// This test creates helper, checks that containers are hidden and then +// destructs helper. +TEST_F(FirstRunHelperTest, ContainersAreHidden) { + CheckContainersAreHidden(); +} + +// Tests that helper correctly handles Escape key press. +TEST_F(FirstRunHelperTest, Cancel) { + GetEventGenerator().PressKey(ui::VKEY_ESCAPE, 0); + EXPECT_EQ(cancelled_times(), 1); +} + +// Tests that modal window doesn't block events for overlay window. +TEST_F(FirstRunHelperTest, ModalWindowDoesNotBlock) { + views::Widget* modal_dialog = views::DialogDelegate::CreateDialogWidget( + new TestModalDialogDelegate(), CurrentContext(), NULL); + modal_dialog->Show(); + // TODO(dzhioev): modal window should not steal focus from overlay window. + aura::Window* overlay_window = helper()->GetOverlayWidget()->GetNativeView(); + overlay_window->Focus(); + EXPECT_TRUE(overlay_window->HasFocus()); + int mouse_events; + overlay_window->SetEventFilter(new CountingEventHandler(&mouse_events)); + GetEventGenerator().PressLeftButton(); + GetEventGenerator().ReleaseLeftButton(); + EXPECT_EQ(mouse_events, 2); +} + +} // namespace test +} // namespace ash diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc index 4775acc..0ab912a 100644 --- a/ash/root_window_controller.cc +++ b/ash/root_window_controller.cc @@ -252,6 +252,15 @@ RootWindowController* RootWindowController::ForTargetRootWindow() { return internal::GetRootWindowController(Shell::GetTargetRootWindow()); } +// static +aura::Window* RootWindowController::GetContainerForWindow( + aura::Window* window) { + aura::Window* container = window->parent(); + while (container && container->type() != aura::client::WINDOW_TYPE_UNKNOWN) + container = container->parent(); + return container; +} + RootWindowController::~RootWindowController() { Shutdown(); root_window_.reset(); @@ -306,22 +315,23 @@ void RootWindowController::Shutdown() { SystemModalContainerLayoutManager* RootWindowController::GetSystemModalLayoutManager(aura::Window* window) { - aura::Window* container = NULL; + aura::Window* modal_container = NULL; if (window) { - if (window->parent() && - window->parent()->id() >= kShellWindowId_LockScreenContainer) { - container = GetContainer(kShellWindowId_LockSystemModalContainer); + aura::Window* window_container = GetContainerForWindow(window); + if (window_container && + window_container->id() >= kShellWindowId_LockScreenContainer) { + modal_container = GetContainer(kShellWindowId_LockSystemModalContainer); } else { - container = GetContainer(kShellWindowId_SystemModalContainer); + modal_container = GetContainer(kShellWindowId_SystemModalContainer); } } else { int modal_window_id = Shell::GetInstance()->session_state_delegate() ->IsUserSessionBlocked() ? kShellWindowId_LockSystemModalContainer : kShellWindowId_SystemModalContainer; - container = GetContainer(modal_window_id); + modal_container = GetContainer(modal_window_id); } - return container ? static_cast<SystemModalContainerLayoutManager*>( - container->layout_manager()) : NULL; + return modal_container ? static_cast<SystemModalContainerLayoutManager*>( + modal_container->layout_manager()) : NULL; } aura::Window* RootWindowController::GetContainer(int container_id) { diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h index 6e2d545..e71b1ad 100644 --- a/ash/root_window_controller.h +++ b/ash/root_window_controller.h @@ -102,6 +102,9 @@ class ASH_EXPORT RootWindowController : public ShellObserver { // Returns the RootWindowController of the target root window. static internal::RootWindowController* ForTargetRootWindow(); + // Returns container which contains a given |window|. + static aura::Window* GetContainerForWindow(aura::Window* window); + virtual ~RootWindowController(); aura::Window* root_window() { return dispatcher()->window(); } diff --git a/ash/wm/stacking_controller.cc b/ash/wm/stacking_controller.cc index bd4a654..915eed4 100644 --- a/ash/wm/stacking_controller.cc +++ b/ash/wm/stacking_controller.cc @@ -33,13 +33,6 @@ aura::Window* GetContainerById(aura::Window* root, int id) { return Shell::GetContainer(root, id); } -aura::Window* GetContainerForWindow(aura::Window* window) { - aura::Window* container = window->parent(); - while (container && container->type() != aura::client::WINDOW_TYPE_UNKNOWN) - container = container->parent(); - return container; -} - bool IsSystemModal(aura::Window* window) { return window->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM; } @@ -86,7 +79,8 @@ aura::Window* StackingController::GetDefaultParent(aura::Window* context, if (IsSystemModal(window)) return GetSystemModalContainer(target_root, window); else if (HasTransientParentWindow(window)) - return GetContainerForWindow(window->transient_parent()); + return internal::RootWindowController::GetContainerForWindow( + window->transient_parent()); return GetAlwaysOnTopController(target_root)->GetContainer(window); case aura::client::WINDOW_TYPE_CONTROL: return GetContainerById( diff --git a/chrome/browser/chromeos/first_run/first_run_controller.cc b/chrome/browser/chromeos/first_run/first_run_controller.cc index 62e7457..14f0ad8 100644 --- a/chrome/browser/chromeos/first_run/first_run_controller.cc +++ b/chrome/browser/chromeos/first_run/first_run_controller.cc @@ -4,7 +4,6 @@ #include "chrome/browser/chromeos/first_run/first_run_controller.h" -#include "ash/first_run/first_run_helper.h" #include "ash/shell.h" #include "base/logging.h" #include "base/message_loop/message_loop.h" @@ -62,6 +61,7 @@ void FirstRunController::Init() { user_profile_ = user_manager->GetProfileByUser(user_manager->GetActiveUser()); shell_helper_.reset(ash::Shell::GetInstance()->CreateFirstRunHelper()); + shell_helper_->AddObserver(this); FirstRunView* view = new FirstRunView(); view->Init(user_profile_); @@ -79,6 +79,7 @@ void FirstRunController::Finalize() { if (actor_) actor_->set_delegate(NULL); actor_ = NULL; + shell_helper_->RemoveObserver(this); shell_helper_.reset(); } @@ -113,6 +114,10 @@ void FirstRunController::OnActorDestroyed() { "FirstRunActor destroyed before FirstRunController::Finalize."; } +void FirstRunController::OnCancelled() { + Stop(); +} + void FirstRunController::RegisterSteps() { steps_.push_back(make_linked_ptr( new first_run::AppListStep(shell_helper_.get(), actor_))); diff --git a/chrome/browser/chromeos/first_run/first_run_controller.h b/chrome/browser/chromeos/first_run/first_run_controller.h index 989bb76..a0a0e39 100644 --- a/chrome/browser/chromeos/first_run/first_run_controller.h +++ b/chrome/browser/chromeos/first_run/first_run_controller.h @@ -8,6 +8,7 @@ #include <string> #include <vector> +#include "ash/first_run/first_run_helper.h" #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/memory/linked_ptr.h" @@ -16,10 +17,6 @@ class Profile; -namespace ash { -class FirstRunHelper; -} - namespace chromeos { namespace first_run { @@ -29,7 +26,8 @@ class Step; // FirstRunController creates and manages first-run tutorial. // Object manages its lifetime and deletes itself after completion of the // tutorial. -class FirstRunController : public FirstRunActor::Delegate { +class FirstRunController : public FirstRunActor::Delegate, + public ash::FirstRunHelper::Observer { typedef std::vector<linked_ptr<first_run::Step> > Steps; public: @@ -53,6 +51,9 @@ class FirstRunController : public FirstRunActor::Delegate { virtual void OnCloseButtonClicked() OVERRIDE; virtual void OnActorDestroyed() OVERRIDE; + // Overriden from ash::FirstRunHelper::Observer. + virtual void OnCancelled() OVERRIDE; + void RegisterSteps(); void ShowNextStep(); void AdvanceStep(); |