diff options
author | mukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-10 07:40:50 +0000 |
---|---|---|
committer | mukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-07-10 07:40:50 +0000 |
commit | a5a068d6d14a8e99e047a323485516cfa07bd5eb (patch) | |
tree | 0b65a9ab8b7d425dad553079f8b9a3639ab3eeee /ash/system | |
parent | 9bd9fc06e4d7f9ebe3594789c6bca8d8cf995dd7 (diff) | |
download | chromium_src-a5a068d6d14a8e99e047a323485516cfa07bd5eb.zip chromium_src-a5a068d6d14a8e99e047a323485516cfa07bd5eb.tar.gz chromium_src-a5a068d6d14a8e99e047a323485516cfa07bd5eb.tar.bz2 |
Separate the logic of popup alignment and workarea handling as delegate.
MessagePopupCollection contains plenty size of conditions and ifdefs
to work properly with each type of the desktop we have, and some
logic makes side effects on another desktop. This design is unhealty
and adding more conditions sounds incorrect.
Considering this, it would be better to extract platform dependent
parts as a delegate class (PopupAlignmentDelegate) and allow
subclasses to provide platform-specific features.
This design is also beneficial for win-ash, because we had
OS_CHROMEOS layout data and logic which actually means Ash.
BUG=389656
R=stevenjb@chromium.org, dimich@chromium.org
TBR=jamescook@chromium.org, harrym@chromium.org
TEST=message_center_unittests, ash_unittests, some manual checks
Review URL: https://codereview.chromium.org/369573004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@282269 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash/system')
6 files changed, 520 insertions, 190 deletions
diff --git a/ash/system/web_notification/ash_popup_alignment_delegate.cc b/ash/system/web_notification/ash_popup_alignment_delegate.cc new file mode 100644 index 0000000..82181e5 --- /dev/null +++ b/ash/system/web_notification/ash_popup_alignment_delegate.cc @@ -0,0 +1,176 @@ +// 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 "ash/system/web_notification/ash_popup_alignment_delegate.h" + +#include "ash/display/display_controller.h" +#include "ash/shelf/shelf_constants.h" +#include "ash/shelf/shelf_layout_manager.h" +#include "ash/shelf/shelf_types.h" +#include "ash/shelf/shelf_widget.h" +#include "ash/shell.h" +#include "base/i18n/rtl.h" +#include "ui/aura/window.h" +#include "ui/gfx/display.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/screen.h" +#include "ui/message_center/message_center_style.h" +#include "ui/message_center/views/message_popup_collection.h" + +namespace ash { + +namespace { + +const int kToastMarginX = 3; + +// If there should be no margin for the first item, this value needs to be +// substracted to flush the message to the shelf (the width of the border + +// shadow). +const int kNoToastMarginBorderAndShadowOffset = 2; + +} + +AshPopupAlignmentDelegate::AshPopupAlignmentDelegate() + : display_id_(gfx::Display::kInvalidDisplayID), + screen_(NULL), + root_window_(NULL), + shelf_(NULL), + system_tray_height_(0) { +} + +AshPopupAlignmentDelegate::~AshPopupAlignmentDelegate() { + if (screen_) + screen_->RemoveObserver(this); + Shell::GetInstance()->RemoveShellObserver(this); + if (shelf_) + shelf_->RemoveObserver(this); +} + +void AshPopupAlignmentDelegate::StartObserving(gfx::Screen* screen, + const gfx::Display& display) { + screen_ = screen; + display_id_ = display.id(); + UpdateShelf(); + screen->AddObserver(this); + Shell::GetInstance()->AddShellObserver(this); + if (system_tray_height_ > 0) + OnAutoHideStateChanged(shelf_->auto_hide_state()); +} + +void AshPopupAlignmentDelegate::SetSystemTrayHeight(int height) { + system_tray_height_ = height; + + // If the shelf is shown during auto-hide state, the distance from the edge + // should be reduced by the height of shelf's shown height. + if (shelf_ && shelf_->visibility_state() == SHELF_AUTO_HIDE && + shelf_->auto_hide_state() == SHELF_AUTO_HIDE_SHOWN) { + system_tray_height_ -= kShelfSize - ShelfLayoutManager::kAutoHideSize; + } + + if (system_tray_height_ > 0) + system_tray_height_ += message_center::kMarginBetweenItems; + else + system_tray_height_ = 0; + + if (!shelf_) + return; + + DoUpdateIfPossible(); +} + +int AshPopupAlignmentDelegate::GetToastOriginX( + const gfx::Rect& toast_bounds) const { + // In Ash, RTL UI language mirrors the whole ash layout, so the toast + // widgets should be at the bottom-left instead of bottom right. + if (base::i18n::IsRTL()) + return work_area_.x() + kToastMarginX; + + if (IsFromLeft()) + return work_area_.x() + kToastMarginX; + return work_area_.right() - kToastMarginX - toast_bounds.width(); +} + +int AshPopupAlignmentDelegate::GetBaseLine() const { + return IsTopDown() + ? work_area_.y() + kNoToastMarginBorderAndShadowOffset + + system_tray_height_ + : work_area_.bottom() - kNoToastMarginBorderAndShadowOffset - + system_tray_height_; +} + +int AshPopupAlignmentDelegate::GetWorkAreaBottom() const { + return work_area_.bottom() - system_tray_height_; +} + +bool AshPopupAlignmentDelegate::IsTopDown() const { + return GetAlignment() == SHELF_ALIGNMENT_TOP; +} + +bool AshPopupAlignmentDelegate::IsFromLeft() const { + return GetAlignment() == SHELF_ALIGNMENT_LEFT; +} + +void AshPopupAlignmentDelegate::RecomputeAlignment( + const gfx::Display& display) { + // Nothing needs to be done. +} + +ShelfAlignment AshPopupAlignmentDelegate::GetAlignment() const { + return shelf_ ? shelf_->GetAlignment() : SHELF_ALIGNMENT_BOTTOM; +} + +void AshPopupAlignmentDelegate::UpdateShelf() { + if (shelf_) + return; + + aura::Window* root_window = ash::Shell::GetInstance()->display_controller()-> + GetRootWindowForDisplayId(display_id_); + shelf_ = ShelfLayoutManager::ForShelf(root_window); + if (shelf_) + shelf_->AddObserver(this); +} + +void AshPopupAlignmentDelegate::OnDisplayWorkAreaInsetsChanged() { + UpdateShelf(); + + work_area_ = Shell::GetScreen()->GetDisplayNearestWindow( + shelf_->shelf_widget()->GetNativeView()).work_area(); +} + +void AshPopupAlignmentDelegate::OnAutoHideStateChanged( + ShelfAutoHideState new_state) { + work_area_ = Shell::GetScreen()->GetDisplayNearestWindow( + shelf_->shelf_widget()->GetNativeView()).work_area(); + int width = 0; + if ((shelf_->visibility_state() == SHELF_AUTO_HIDE) && + new_state == SHELF_AUTO_HIDE_SHOWN) { + // Since the work_area is already reduced by kAutoHideSize, the inset width + // should be just the difference. + width = kShelfSize - ShelfLayoutManager::kAutoHideSize; + } + work_area_.Inset(shelf_->SelectValueForShelfAlignment( + gfx::Insets(0, 0, width, 0), + gfx::Insets(0, width, 0, 0), + gfx::Insets(0, 0, 0, width), + gfx::Insets(width, 0, 0, 0))); + + DoUpdateIfPossible(); +} + +void AshPopupAlignmentDelegate::OnDisplayAdded( + const gfx::Display& new_display) { +} + +void AshPopupAlignmentDelegate::OnDisplayRemoved( + const gfx::Display& old_display) { +} + +void AshPopupAlignmentDelegate::OnDisplayMetricsChanged( + const gfx::Display& display, + uint32_t metrics) { + if (display.id() == display_id_ && shelf_) + OnAutoHideStateChanged(shelf_->auto_hide_state()); +} + +} // namespace ash diff --git a/ash/system/web_notification/ash_popup_alignment_delegate.h b/ash/system/web_notification/ash_popup_alignment_delegate.h new file mode 100644 index 0000000..1a03e2d --- /dev/null +++ b/ash/system/web_notification/ash_popup_alignment_delegate.h @@ -0,0 +1,93 @@ +// 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 ASH_SYSTEM_WEB_NOTIFICATION_ASH_POPUP_ALIGNMENT_DELEGATE_H_ +#define ASH_SYSTEM_WEB_NOTIFICATION_ASH_POPUP_ALIGNMENT_DELEGATE_H_ + +#include "ash/ash_export.h" +#include "ash/shelf/shelf_layout_manager_observer.h" +#include "ash/shelf/shelf_types.h" +#include "ash/shell_observer.h" +#include "base/macros.h" +#include "ui/gfx/display_observer.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/message_center/views/popup_alignment_delegate.h" + +namespace aura { +class Window; +} + +namespace gfx { +class Screen; +} + +namespace ash { + +class AshPopupAlignmentDelegateTest; +class ShelfLayoutManager; +class WebNotificationTrayTest; + +// The PopupAlignmentDelegate subclass for Ash. It needs to handle alignment of +// the shelf and its autohide state. +class ASH_EXPORT AshPopupAlignmentDelegate + : public message_center::PopupAlignmentDelegate, + public ShelfLayoutManagerObserver, + public ShellObserver, + public gfx::DisplayObserver { + public: + AshPopupAlignmentDelegate(); + virtual ~AshPopupAlignmentDelegate(); + + // Start observing the system. + void StartObserving(gfx::Screen* screen, const gfx::Display& display); + + // Sets the current height of the system tray so that the notification toasts + // can avoid it. + void SetSystemTrayHeight(int height); + + // Overridden from message_center::PopupAlignmentDelegate: + virtual int GetToastOriginX(const gfx::Rect& toast_bounds) const OVERRIDE; + virtual int GetBaseLine() const OVERRIDE; + virtual int GetWorkAreaBottom() const OVERRIDE; + virtual bool IsTopDown() const OVERRIDE; + virtual bool IsFromLeft() const OVERRIDE; + virtual void RecomputeAlignment(const gfx::Display& display) OVERRIDE; + + private: + friend class AshPopupAlignmentDelegateTest; + friend class WebNotificationTrayTest; + + // Get the current alignment of the shelf. + ShelfAlignment GetAlignment() const; + + // Update |shelf_| and start watching when it's first set. This should not + // be done in the constructor because the shelf might not be initialized at + // that point. + void UpdateShelf(); + + // Overridden from ShellObserver: + virtual void OnDisplayWorkAreaInsetsChanged() OVERRIDE; + + // Overridden from ShelfLayoutManagerObserver: + virtual void OnAutoHideStateChanged(ShelfAutoHideState new_state) OVERRIDE; + + // Overridden from gfx::DisplayObserver: + virtual void OnDisplayAdded(const gfx::Display& new_display) OVERRIDE; + virtual void OnDisplayRemoved(const gfx::Display& old_display) OVERRIDE; + virtual void OnDisplayMetricsChanged(const gfx::Display& display, + uint32_t metrics) OVERRIDE; + + int64_t display_id_; + gfx::Screen* screen_; + gfx::Rect work_area_; + aura::Window* root_window_; + ShelfLayoutManager* shelf_; + int system_tray_height_; + + DISALLOW_COPY_AND_ASSIGN(AshPopupAlignmentDelegate); +}; + +} // namespace ash + +#endif // ASH_SYSTEM_WEB_NOTIFICATION_ASH_POPUP_ALIGNMENT_DELEGATE_H_ diff --git a/ash/system/web_notification/ash_popup_alignment_delegate_unittest.cc b/ash/system/web_notification/ash_popup_alignment_delegate_unittest.cc new file mode 100644 index 0000000..89659b1 --- /dev/null +++ b/ash/system/web_notification/ash_popup_alignment_delegate_unittest.cc @@ -0,0 +1,197 @@ +// 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 "ash/system/web_notification/ash_popup_alignment_delegate.h" + +#include <vector> + +#include "ash/shelf/shelf_layout_manager.h" +#include "ash/shelf/shelf_types.h" +#include "ash/shell.h" +#include "ash/shell_window_ids.h" +#include "ash/test/ash_test_base.h" +#include "ui/gfx/screen.h" +#include "ui/message_center/message_center_style.h" + +namespace ash { + +class AshPopupAlignmentDelegateTest : public test::AshTestBase { + public: + AshPopupAlignmentDelegateTest() {} + virtual ~AshPopupAlignmentDelegateTest() {} + + virtual void SetUp() { + test::AshTestBase::SetUp(); + alignment_delegate_.reset(new AshPopupAlignmentDelegate()); + alignment_delegate_->StartObserving( + Shell::GetScreen(), Shell::GetScreen()->GetPrimaryDisplay()); + } + + virtual void TearDown() { + alignment_delegate_.reset(); + test::AshTestBase::TearDown(); + } + + protected: + enum Position { + TOP_LEFT, + TOP_RIGHT, + BOTTOM_LEFT, + BOTTOM_RIGHT, + OUTSIDE + }; + + AshPopupAlignmentDelegate* alignment_delegate() { + return alignment_delegate_.get(); + } + + Position GetPositionInDisplay(const gfx::Point& point) { + const gfx::Rect& work_area = + Shell::GetScreen()->GetPrimaryDisplay().work_area(); + const gfx::Point center_point = work_area.CenterPoint(); + if (work_area.x() > point.x() || work_area.y() > point.y() || + work_area.right() < point.x() || work_area.bottom() < point.y()) { + return OUTSIDE; + } + + if (center_point.x() < point.x()) + return (center_point.y() < point.y()) ? BOTTOM_RIGHT : TOP_RIGHT; + else + return (center_point.y() < point.y()) ? BOTTOM_LEFT : TOP_LEFT; + } + + gfx::Rect GetWorkArea() { + return alignment_delegate_->work_area_; + } + + private: + scoped_ptr<AshPopupAlignmentDelegate> alignment_delegate_; +}; + +TEST_F(AshPopupAlignmentDelegateTest, ShelfAlignment) { + const gfx::Rect toast_size(0, 0, 10, 10); + UpdateDisplay("600x600"); + gfx::Point toast_point; + toast_point.set_x(alignment_delegate()->GetToastOriginX(toast_size)); + toast_point.set_y(alignment_delegate()->GetBaseLine()); + EXPECT_EQ(BOTTOM_RIGHT, GetPositionInDisplay(toast_point)); + EXPECT_FALSE(alignment_delegate()->IsTopDown()); + EXPECT_FALSE(alignment_delegate()->IsFromLeft()); + + Shell::GetInstance()->SetShelfAlignment( + SHELF_ALIGNMENT_RIGHT, + Shell::GetPrimaryRootWindow()); + toast_point.set_x(alignment_delegate()->GetToastOriginX(toast_size)); + toast_point.set_y(alignment_delegate()->GetBaseLine()); + EXPECT_EQ(BOTTOM_RIGHT, GetPositionInDisplay(toast_point)); + EXPECT_FALSE(alignment_delegate()->IsTopDown()); + EXPECT_FALSE(alignment_delegate()->IsFromLeft()); + + Shell::GetInstance()->SetShelfAlignment( + SHELF_ALIGNMENT_LEFT, + Shell::GetPrimaryRootWindow()); + toast_point.set_x(alignment_delegate()->GetToastOriginX(toast_size)); + toast_point.set_y(alignment_delegate()->GetBaseLine()); + EXPECT_EQ(BOTTOM_LEFT, GetPositionInDisplay(toast_point)); + EXPECT_FALSE(alignment_delegate()->IsTopDown()); + EXPECT_TRUE(alignment_delegate()->IsFromLeft()); + + Shell::GetInstance()->SetShelfAlignment( + SHELF_ALIGNMENT_TOP, + Shell::GetPrimaryRootWindow()); + toast_point.set_x(alignment_delegate()->GetToastOriginX(toast_size)); + toast_point.set_y(alignment_delegate()->GetBaseLine()); + EXPECT_EQ(TOP_RIGHT, GetPositionInDisplay(toast_point)); + EXPECT_TRUE(alignment_delegate()->IsTopDown()); + EXPECT_FALSE(alignment_delegate()->IsFromLeft()); +} + +TEST_F(AshPopupAlignmentDelegateTest, LockScreen) { + const gfx::Rect toast_size(0, 0, 10, 10); + + Shell::GetInstance()->SetShelfAlignment( + SHELF_ALIGNMENT_LEFT, + Shell::GetPrimaryRootWindow()); + gfx::Point toast_point; + toast_point.set_x(alignment_delegate()->GetToastOriginX(toast_size)); + toast_point.set_y(alignment_delegate()->GetBaseLine()); + EXPECT_EQ(BOTTOM_LEFT, GetPositionInDisplay(toast_point)); + EXPECT_FALSE(alignment_delegate()->IsTopDown()); + EXPECT_TRUE(alignment_delegate()->IsFromLeft()); + + BlockUserSession(BLOCKED_BY_LOCK_SCREEN); + toast_point.set_x(alignment_delegate()->GetToastOriginX(toast_size)); + toast_point.set_y(alignment_delegate()->GetBaseLine()); + EXPECT_EQ(BOTTOM_RIGHT, GetPositionInDisplay(toast_point)); + EXPECT_FALSE(alignment_delegate()->IsTopDown()); + EXPECT_FALSE(alignment_delegate()->IsFromLeft()); +} + +TEST_F(AshPopupAlignmentDelegateTest, AutoHide) { + const gfx::Rect toast_size(0, 0, 10, 10); + UpdateDisplay("600x600"); + int origin_x = alignment_delegate()->GetToastOriginX(toast_size); + int baseline = alignment_delegate()->GetBaseLine(); + + // Create a window, otherwise autohide doesn't work. + scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(0)); + Shell::GetInstance()->SetShelfAutoHideBehavior( + SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS, + Shell::GetPrimaryRootWindow()); + ShelfLayoutManager::ForShelf(Shell::GetPrimaryRootWindow())-> + UpdateAutoHideStateNow(); + EXPECT_EQ(origin_x, alignment_delegate()->GetToastOriginX(toast_size)); + EXPECT_LT(baseline, alignment_delegate()->GetBaseLine()); +} + +// Verify that docked window doesn't affect the popup alignment. +TEST_F(AshPopupAlignmentDelegateTest, DockedWindow) { + const gfx::Rect toast_size(0, 0, 10, 10); + UpdateDisplay("600x600"); + int origin_x = alignment_delegate()->GetToastOriginX(toast_size); + int baseline = alignment_delegate()->GetBaseLine(); + + scoped_ptr<aura::Window> window( + CreateTestWindowInShellWithBounds(gfx::Rect(0, 0, 50, 50))); + aura::Window* docked_container = Shell::GetContainer( + Shell::GetPrimaryRootWindow(), + kShellWindowId_DockedContainer); + docked_container->AddChild(window.get()); + + EXPECT_EQ(origin_x, alignment_delegate()->GetToastOriginX(toast_size)); + EXPECT_EQ(baseline, alignment_delegate()->GetBaseLine()); + EXPECT_FALSE(alignment_delegate()->IsTopDown()); + EXPECT_FALSE(alignment_delegate()->IsFromLeft()); +} + +TEST_F(AshPopupAlignmentDelegateTest, DisplayResize) { + const gfx::Rect toast_size(0, 0, 10, 10); + UpdateDisplay("600x600"); + int origin_x = alignment_delegate()->GetToastOriginX(toast_size); + int baseline = alignment_delegate()->GetBaseLine(); + + UpdateDisplay("800x800"); + EXPECT_LT(origin_x, alignment_delegate()->GetToastOriginX(toast_size)); + EXPECT_LT(baseline, alignment_delegate()->GetBaseLine()); + + UpdateDisplay("400x400"); + EXPECT_GT(origin_x, alignment_delegate()->GetToastOriginX(toast_size)); + EXPECT_GT(baseline, alignment_delegate()->GetBaseLine()); +} + +TEST_F(AshPopupAlignmentDelegateTest, TrayHeight) { + const gfx::Rect toast_size(0, 0, 10, 10); + UpdateDisplay("600x600"); + int origin_x = alignment_delegate()->GetToastOriginX(toast_size); + int baseline = alignment_delegate()->GetBaseLine(); + + const int kTrayHeight = 100; + alignment_delegate()->SetSystemTrayHeight(kTrayHeight); + + EXPECT_EQ(origin_x, alignment_delegate()->GetToastOriginX(toast_size)); + EXPECT_EQ(baseline - kTrayHeight - message_center::kMarginBetweenItems, + alignment_delegate()->GetBaseLine()); +} + +} // namespace ash diff --git a/ash/system/web_notification/web_notification_tray.cc b/ash/system/web_notification/web_notification_tray.cc index de999e9..554d60e 100644 --- a/ash/system/web_notification/web_notification_tray.cc +++ b/ash/system/web_notification/web_notification_tray.cc @@ -17,6 +17,7 @@ #include "ash/system/tray/tray_bubble_wrapper.h" #include "ash/system/tray/tray_constants.h" #include "ash/system/tray/tray_utils.h" +#include "ash/system/web_notification/ash_popup_alignment_delegate.h" #include "base/auto_reset.h" #include "base/i18n/number_formatting.h" #include "base/i18n/rtl.h" @@ -70,134 +71,6 @@ const SkColor kWebNotificationColorWithUnread = SK_ColorWHITE; } -// Observes the change of work area (including temporary change by auto-hide) -// and notifies MessagePopupCollection. -class WorkAreaObserver : public ShelfLayoutManagerObserver, - public ShellObserver { - public: - WorkAreaObserver(); - virtual ~WorkAreaObserver(); - - void SetSystemTrayHeight(int height); - - // Starts observing |shelf| and shell and sends the change to |collection|. - void StartObserving(message_center::MessagePopupCollection* collection, - aura::Window* root_window); - - // Stops the observing session. - void StopObserving(); - - // Overridden from ShellObserver: - virtual void OnDisplayWorkAreaInsetsChanged() OVERRIDE; - - // Overridden from ShelfLayoutManagerObserver: - virtual void OnAutoHideStateChanged(ShelfAutoHideState new_state) OVERRIDE; - - private: - // Updates |shelf_| from |root_window_|. - void UpdateShelf(); - - message_center::MessagePopupCollection* collection_; - aura::Window* root_window_; - ShelfLayoutManager* shelf_; - int system_tray_height_; - - DISALLOW_COPY_AND_ASSIGN(WorkAreaObserver); -}; - -WorkAreaObserver::WorkAreaObserver() - : collection_(NULL), - root_window_(NULL), - shelf_(NULL), - system_tray_height_(0) { -} - -WorkAreaObserver::~WorkAreaObserver() { - StopObserving(); -} - -void WorkAreaObserver::SetSystemTrayHeight(int height) { - system_tray_height_ = height; - - // If the shelf is shown during auto-hide state, the distance from the edge - // should be reduced by the height of shelf's shown height. - if (shelf_ && shelf_->visibility_state() == SHELF_AUTO_HIDE && - shelf_->auto_hide_state() == SHELF_AUTO_HIDE_SHOWN) { - system_tray_height_ -= kShelfSize - ShelfLayoutManager::kAutoHideSize; - } - - if (system_tray_height_ > 0) - system_tray_height_ += message_center::kMarginBetweenItems; - - if (!shelf_) - return; - - OnAutoHideStateChanged(shelf_->auto_hide_state()); -} - -void WorkAreaObserver::StartObserving( - message_center::MessagePopupCollection* collection, - aura::Window* root_window) { - DCHECK(collection); - collection_ = collection; - root_window_ = root_window; - UpdateShelf(); - Shell::GetInstance()->AddShellObserver(this); - if (system_tray_height_ > 0) - OnAutoHideStateChanged(shelf_->auto_hide_state()); -} - -void WorkAreaObserver::StopObserving() { - Shell::GetInstance()->RemoveShellObserver(this); - if (shelf_) - shelf_->RemoveObserver(this); - collection_ = NULL; - shelf_ = NULL; -} - -void WorkAreaObserver::OnDisplayWorkAreaInsetsChanged() { - UpdateShelf(); - - collection_->OnDisplayMetricsChanged( - Shell::GetScreen()->GetDisplayNearestWindow( - shelf_->shelf_widget()->GetNativeView()), - gfx::DisplayObserver::DISPLAY_METRIC_WORK_AREA); -} - -void WorkAreaObserver::OnAutoHideStateChanged(ShelfAutoHideState new_state) { - gfx::Display display = Shell::GetScreen()->GetDisplayNearestWindow( - shelf_->shelf_widget()->GetNativeView()); - gfx::Rect work_area = display.work_area(); - int width = 0; - if ((shelf_->visibility_state() == SHELF_AUTO_HIDE) && - new_state == SHELF_AUTO_HIDE_SHOWN) { - // Since the work_area is already reduced by kAutoHideSize, the inset width - // should be just the difference. - width = kShelfSize - ShelfLayoutManager::kAutoHideSize; - } - work_area.Inset(shelf_->SelectValueForShelfAlignment( - gfx::Insets(0, 0, width, 0), - gfx::Insets(0, width, 0, 0), - gfx::Insets(0, 0, 0, width), - gfx::Insets(width, 0, 0, 0))); - if (system_tray_height_ > 0) { - work_area.set_height( - std::max(0, work_area.height() - system_tray_height_)); - if (shelf_->GetAlignment() == SHELF_ALIGNMENT_TOP) - work_area.set_y(work_area.y() + system_tray_height_); - } - collection_->SetDisplayInfo(work_area, display.bounds()); -} - -void WorkAreaObserver::UpdateShelf() { - if (shelf_) - return; - - shelf_ = ShelfLayoutManager::ForShelf(root_window_); - if (shelf_) - shelf_->AddObserver(this); -} - // Class to initialize and manage the WebNotificationBubble and // TrayBubbleWrapper instances for a bubble. class WebNotificationBubbleWrapper { @@ -308,25 +181,25 @@ WebNotificationTray::WebNotificationTray(StatusAreaWidget* status_area_widget) message_center_tray_.reset(new message_center::MessageCenterTray( this, message_center::MessageCenter::Get())); + popup_alignment_delegate_.reset(new AshPopupAlignmentDelegate()); popup_collection_.reset(new message_center::MessagePopupCollection( ash::Shell::GetContainer( status_area_widget->GetNativeView()->GetRootWindow(), kShellWindowId_StatusContainer), message_center(), message_center_tray_.get(), - true)); - work_area_observer_.reset(new WorkAreaObserver()); - work_area_observer_->StartObserving( - popup_collection_.get(), - status_area_widget->GetNativeView()->GetRootWindow()); + popup_alignment_delegate_.get())); + const gfx::Display& display = Shell::GetScreen()->GetDisplayNearestWindow( + status_area_widget->GetNativeView()); + popup_alignment_delegate_->StartObserving(Shell::GetScreen(), display); OnMessageCenterTrayChanged(); } WebNotificationTray::~WebNotificationTray() { // Release any child views that might have back pointers before ~View(). message_center_bubble_.reset(); + popup_alignment_delegate_.reset(); popup_collection_.reset(); - work_area_observer_.reset(); } // Public methods. @@ -398,7 +271,7 @@ void WebNotificationTray::HideMessageCenter() { } void WebNotificationTray::SetSystemTrayHeight(int height) { - work_area_observer_->SetSystemTrayHeight(height); + popup_alignment_delegate_->SetSystemTrayHeight(height); } bool WebNotificationTray::ShowPopups() { diff --git a/ash/system/web_notification/web_notification_tray.h b/ash/system/web_notification/web_notification_tray.h index 887a91d..d552191 100644 --- a/ash/system/web_notification/web_notification_tray.h +++ b/ash/system/web_notification/web_notification_tray.h @@ -41,7 +41,7 @@ namespace ash { class StatusAreaWidget; class WebNotificationBubbleWrapper; class WebNotificationButton; -class WorkAreaObserver; +class AshPopupAlignmentDelegate; class ASH_EXPORT WebNotificationTray : public TrayBackgroundView, @@ -175,8 +175,7 @@ class ASH_EXPORT WebNotificationTray // flickers of the shelf from hidden to shown. See: crbug.com/181213 bool should_block_shelf_auto_hide_; - // Observes the work area for |popup_collection_| and notifies to it. - scoped_ptr<WorkAreaObserver> work_area_observer_; + scoped_ptr<AshPopupAlignmentDelegate> popup_alignment_delegate_; DISALLOW_COPY_AND_ASSIGN(WebNotificationTray); }; diff --git a/ash/system/web_notification/web_notification_tray_unittest.cc b/ash/system/web_notification/web_notification_tray_unittest.cc index ff7666c..886e829 100644 --- a/ash/system/web_notification/web_notification_tray_unittest.cc +++ b/ash/system/web_notification/web_notification_tray_unittest.cc @@ -14,6 +14,7 @@ #include "ash/system/status_area_widget.h" #include "ash/system/tray/system_tray.h" #include "ash/system/tray/system_tray_item.h" +#include "ash/system/web_notification/ash_popup_alignment_delegate.h" #include "ash/test/ash_test_base.h" #include "ash/test/status_area_widget_test_helper.h" #include "ash/test/test_system_tray_delegate.h" @@ -134,12 +135,12 @@ class WebNotificationTrayTest : public test::AshTestBase { return GetTray()->GetWidget(); } - gfx::Rect GetPopupWorkArea() { - return GetPopupWorkAreaForTray(GetTray()); + int GetPopupWorkAreaBottom() { + return GetPopupWorkAreaBottomForTray(GetTray()); } - gfx::Rect GetPopupWorkAreaForTray(WebNotificationTray* tray) { - return tray->popup_collection_->work_area_; + int GetPopupWorkAreaBottomForTray(WebNotificationTray* tray) { + return tray->popup_alignment_delegate_->GetWorkAreaBottom(); } bool IsPopupVisible() { @@ -319,44 +320,40 @@ TEST_F(WebNotificationTrayTest, MAYBE_PopupAndSystemTray) { AddNotification("test_id"); EXPECT_TRUE(GetTray()->IsPopupVisible()); - gfx::Rect work_area = GetPopupWorkArea(); + int bottom = GetPopupWorkAreaBottom(); // System tray is created, the popup's work area should be narrowed but still // visible. GetSystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW); EXPECT_TRUE(GetTray()->IsPopupVisible()); - gfx::Rect work_area_with_tray = GetPopupWorkArea(); - EXPECT_GT(work_area.size().GetArea(), work_area_with_tray.size().GetArea()); + int bottom_with_tray = GetPopupWorkAreaBottom(); + EXPECT_GT(bottom, bottom_with_tray); // System tray notification is also created, the popup's work area is narrowed // even more, but still visible. GetSystemTray()->ShowNotificationView(test_item); EXPECT_TRUE(GetTray()->IsPopupVisible()); - gfx::Rect work_area_with_tray_notification = GetPopupWorkArea(); - EXPECT_GT(work_area.size().GetArea(), - work_area_with_tray_notification.size().GetArea()); - EXPECT_GT(work_area_with_tray.size().GetArea(), - work_area_with_tray_notification.size().GetArea()); + int bottom_with_tray_notification = GetPopupWorkAreaBottom(); + EXPECT_GT(bottom, bottom_with_tray_notification); + EXPECT_GT(bottom_with_tray, bottom_with_tray_notification); // Close system tray, only system tray notifications. GetSystemTray()->ClickedOutsideBubble(); EXPECT_TRUE(GetTray()->IsPopupVisible()); - gfx::Rect work_area_with_notification = GetPopupWorkArea(); - EXPECT_GT(work_area.size().GetArea(), - work_area_with_notification.size().GetArea()); - EXPECT_LT(work_area_with_tray_notification.size().GetArea(), - work_area_with_notification.size().GetArea()); + int bottom_with_notification = GetPopupWorkAreaBottom(); + EXPECT_GT(bottom, bottom_with_notification); + EXPECT_LT(bottom_with_tray_notification, bottom_with_notification); // Close the system tray notifications. GetSystemTray()->HideNotificationView(test_item); EXPECT_TRUE(GetTray()->IsPopupVisible()); - EXPECT_EQ(work_area.ToString(), GetPopupWorkArea().ToString()); + EXPECT_EQ(bottom, GetPopupWorkAreaBottom()); } TEST_F(WebNotificationTrayTest, MAYBE_PopupAndAutoHideShelf) { AddNotification("test_id"); EXPECT_TRUE(GetTray()->IsPopupVisible()); - gfx::Rect work_area = GetPopupWorkArea(); + int bottom = GetPopupWorkAreaBottom(); // Shelf's auto-hide state won't be HIDDEN unless window exists. scoped_ptr<aura::Window> window( @@ -366,14 +363,14 @@ TEST_F(WebNotificationTrayTest, MAYBE_PopupAndAutoHideShelf) { shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); - gfx::Rect work_area_auto_hidden = GetPopupWorkArea(); - EXPECT_LT(work_area.size().GetArea(), work_area_auto_hidden.size().GetArea()); + int bottom_auto_hidden = GetPopupWorkAreaBottom(); + EXPECT_LT(bottom, bottom_auto_hidden); // Close the window, which shows the shelf. window.reset(); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); - gfx::Rect work_area_auto_shown = GetPopupWorkArea(); - EXPECT_EQ(work_area.ToString(), work_area_auto_shown.ToString()); + int bottom_auto_shown = GetPopupWorkAreaBottom(); + EXPECT_EQ(bottom, bottom_auto_shown); // Create the system tray during auto-hide. window.reset(CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 3, 4))); @@ -383,42 +380,38 @@ TEST_F(WebNotificationTrayTest, MAYBE_PopupAndAutoHideShelf) { EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); EXPECT_TRUE(GetTray()->IsPopupVisible()); - gfx::Rect work_area_with_tray = GetPopupWorkArea(); - EXPECT_GT(work_area_auto_shown.size().GetArea(), - work_area_with_tray.size().GetArea()); + int bottom_with_tray = GetPopupWorkAreaBottom(); + EXPECT_GT(bottom_auto_shown, bottom_with_tray); // Create tray notification. GetSystemTray()->ShowNotificationView(test_item); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); - gfx::Rect work_area_with_tray_notification = GetPopupWorkArea(); - EXPECT_GT(work_area_with_tray.size().GetArea(), - work_area_with_tray_notification.size().GetArea()); + int bottom_with_tray_notification = GetPopupWorkAreaBottom(); + EXPECT_GT(bottom_with_tray, bottom_with_tray_notification); // Close the system tray. GetSystemTray()->ClickedOutsideBubble(); shelf->UpdateAutoHideState(); RunAllPendingInMessageLoop(); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); - gfx::Rect work_area_hidden_with_tray_notification = GetPopupWorkArea(); - EXPECT_LT(work_area_with_tray_notification.size().GetArea(), - work_area_hidden_with_tray_notification.size().GetArea()); - EXPECT_GT(work_area_auto_hidden.size().GetArea(), - work_area_hidden_with_tray_notification.size().GetArea()); + int bottom_hidden_with_tray_notification = GetPopupWorkAreaBottom(); + EXPECT_LT(bottom_with_tray_notification, + bottom_hidden_with_tray_notification); + EXPECT_GT(bottom_auto_hidden, bottom_hidden_with_tray_notification); // Close the window again, which shows the shelf. window.reset(); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); - gfx::Rect work_area_shown_with_tray_notification = GetPopupWorkArea(); - EXPECT_GT(work_area_hidden_with_tray_notification.size().GetArea(), - work_area_shown_with_tray_notification.size().GetArea()); - EXPECT_GT(work_area_auto_shown.size().GetArea(), - work_area_shown_with_tray_notification.size().GetArea()); + int bottom_shown_with_tray_notification = GetPopupWorkAreaBottom(); + EXPECT_GT(bottom_hidden_with_tray_notification, + bottom_shown_with_tray_notification); + EXPECT_GT(bottom_auto_shown, bottom_shown_with_tray_notification); } TEST_F(WebNotificationTrayTest, MAYBE_PopupAndFullscreen) { AddNotification("test_id"); EXPECT_TRUE(IsPopupVisible()); - gfx::Rect work_area = GetPopupWorkArea(); + int bottom = GetPopupWorkAreaBottom(); // Checks the work area for normal auto-hidden state. scoped_ptr<aura::Window> window( @@ -427,7 +420,7 @@ TEST_F(WebNotificationTrayTest, MAYBE_PopupAndFullscreen) { Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager(); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); - gfx::Rect work_area_auto_hidden = GetPopupWorkArea(); + int bottom_auto_hidden = GetPopupWorkAreaBottom(); shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); // Put |window| into fullscreen without forcing the shelf to hide. Currently, @@ -440,9 +433,8 @@ TEST_F(WebNotificationTrayTest, MAYBE_PopupAndFullscreen) { // The work area for auto-hidden status of fullscreen is a bit larger // since it doesn't even have the 3-pixel width. EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); - gfx::Rect work_area_fullscreen_hidden = GetPopupWorkArea(); - EXPECT_EQ(work_area_auto_hidden.ToString(), - work_area_fullscreen_hidden.ToString()); + int bottom_fullscreen_hidden = GetPopupWorkAreaBottom(); + EXPECT_EQ(bottom_auto_hidden, bottom_fullscreen_hidden); // Move the mouse cursor at the bottom, which shows the shelf. aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); @@ -452,27 +444,27 @@ TEST_F(WebNotificationTrayTest, MAYBE_PopupAndFullscreen) { generator.MoveMouseTo(bottom_right); shelf->UpdateAutoHideStateNow(); EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); - EXPECT_EQ(work_area.ToString(), GetPopupWorkArea().ToString()); + EXPECT_EQ(bottom, GetPopupWorkAreaBottom()); - generator.MoveMouseTo(work_area.CenterPoint()); + generator.MoveMouseTo( + Shell::GetScreen()->GetPrimaryDisplay().bounds().CenterPoint()); shelf->UpdateAutoHideStateNow(); EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); - EXPECT_EQ(work_area_auto_hidden.ToString(), GetPopupWorkArea().ToString()); + EXPECT_EQ(bottom_auto_hidden, GetPopupWorkAreaBottom()); } TEST_F(WebNotificationTrayTest, MAYBE_PopupAndSystemTrayMultiDisplay) { UpdateDisplay("800x600,600x400"); AddNotification("test_id"); - gfx::Rect work_area = GetPopupWorkArea(); - gfx::Rect work_area_second = GetPopupWorkAreaForTray(GetSecondaryTray()); + int bottom = GetPopupWorkAreaBottom(); + int bottom_second = GetPopupWorkAreaBottomForTray(GetSecondaryTray()); // System tray is created on the primary display. The popups in the secondary // tray aren't affected. GetSystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW); - EXPECT_GT(work_area.size().GetArea(), GetPopupWorkArea().size().GetArea()); - EXPECT_EQ(work_area_second.ToString(), - GetPopupWorkAreaForTray(GetSecondaryTray()).ToString()); + EXPECT_GT(bottom, GetPopupWorkAreaBottom()); + EXPECT_EQ(bottom_second, GetPopupWorkAreaBottomForTray(GetSecondaryTray())); } } // namespace ash |