summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ash/system/status_area_widget.cc6
-rw-r--r--ash/system/status_area_widget.h3
-rw-r--r--ash/wm/shelf_layout_manager.cc24
-rw-r--r--ash/wm/shelf_layout_manager_unittest.cc124
4 files changed, 153 insertions, 4 deletions
diff --git a/ash/system/status_area_widget.cc b/ash/system/status_area_widget.cc
index ec610ab..9370625 100644
--- a/ash/system/status_area_widget.cc
+++ b/ash/system/status_area_widget.cc
@@ -360,6 +360,12 @@ bool StatusAreaWidget::ShouldShowLauncher() const {
web_notification_tray_->IsMouseInNotificationBubble());
}
+bool StatusAreaWidget::IsMessageBubbleShown() const {
+ return ((system_tray_ && system_tray_->IsAnyBubbleVisible()) ||
+ (web_notification_tray_ &&
+ web_notification_tray_->IsMessageCenterBubbleVisible()));
+}
+
void StatusAreaWidget::AddSystemTray(ShellDelegate* shell_delegate) {
system_tray_ = new SystemTray(this);
status_area_widget_delegate_->AddTray(system_tray_);
diff --git a/ash/system/status_area_widget.h b/ash/system/status_area_widget.h
index 4a5e600..26ff2a3 100644
--- a/ash/system/status_area_widget.h
+++ b/ash/system/status_area_widget.h
@@ -74,6 +74,9 @@ class ASH_EXPORT StatusAreaWidget : public views::Widget {
// the launcher to remain visible.
bool ShouldShowLauncher() const;
+ // True if any message bubble is shown.
+ bool IsMessageBubbleShown() const;
+
private:
void AddSystemTray(ShellDelegate* shell_delegate);
void AddWebNotificationTray();
diff --git a/ash/wm/shelf_layout_manager.cc b/ash/wm/shelf_layout_manager.cc
index 1b765b3..0264c1d 100644
--- a/ash/wm/shelf_layout_manager.cc
+++ b/ash/wm/shelf_layout_manager.cc
@@ -36,6 +36,11 @@ namespace {
// Delay before showing the launcher. This is after the mouse stops moving.
const int kAutoHideDelayMS = 200;
+// To avoid hiding the shelf when the mouse transitions from a message bubble
+// into the shelf, the hit test area is enlarged by this amount of pixels to
+// keep the shelf from hiding.
+const int kNotificationBubbleGapHeight = 6;
+
ui::Layer* GetLayer(views::Widget* widget) {
return widget->GetNativeView()->layer();
}
@@ -852,10 +857,21 @@ ShelfLayoutManager::AutoHideState ShelfLayoutManager::CalculateAutoHideState(
if (event_filter_.get() && event_filter_->in_mouse_drag())
return AUTO_HIDE_HIDDEN;
- bool mouse_over_launcher =
- launcher_widget()->GetWindowBoundsInScreen().Contains(
- gfx::Screen::GetCursorScreenPoint());
- return mouse_over_launcher ? AUTO_HIDE_SHOWN : AUTO_HIDE_HIDDEN;
+ gfx::Rect shelf_region = launcher_widget()->GetWindowBoundsInScreen();
+ if (Shell::GetInstance()->status_area_widget()->IsMessageBubbleShown() &&
+ IsVisible()) {
+ // Increase the the hit test area to prevent the shelf from disappearing
+ // when the mouse is over the bubble gap.
+ shelf_region.Inset(alignment_ == SHELF_ALIGNMENT_RIGHT ?
+ -kNotificationBubbleGapHeight : 0,
+ alignment_ == SHELF_ALIGNMENT_BOTTOM ?
+ -kNotificationBubbleGapHeight : 0,
+ alignment_ == SHELF_ALIGNMENT_LEFT ?
+ -kNotificationBubbleGapHeight : 0,
+ 0);
+ }
+ return shelf_region.Contains(gfx::Screen::GetCursorScreenPoint()) ?
+ AUTO_HIDE_SHOWN : AUTO_HIDE_HIDDEN;
}
void ShelfLayoutManager::UpdateHitTestBounds() {
diff --git a/ash/wm/shelf_layout_manager_unittest.cc b/ash/wm/shelf_layout_manager_unittest.cc
index 8b1685c..e5a8d16 100644
--- a/ash/wm/shelf_layout_manager_unittest.cc
+++ b/ash/wm/shelf_layout_manager_unittest.cc
@@ -12,9 +12,12 @@
#include "ash/shell.h"
#include "ash/shell_delegate.h"
#include "ash/shell_window_ids.h"
+#include "ash/system/status_area_widget.h"
#include "ash/system/tray/system_tray.h"
+#include "ash/system/tray/system_tray_item.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/window_util.h"
+#include "base/utf_string_conversions.h"
#include "ui/aura/client/aura_constants.h"
#include "ui/aura/env.h"
#include "ui/aura/display_manager.h"
@@ -26,6 +29,9 @@
#include "ui/compositor/layer_animator.h"
#include "ui/gfx/display.h"
#include "ui/gfx/screen.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/view.h"
#include "ui/views/widget/widget.h"
namespace ash {
@@ -68,6 +74,76 @@ class ShelfLayoutObserverTest : public ShelfLayoutManager::Observer {
DISALLOW_COPY_AND_ASSIGN(ShelfLayoutObserverTest);
};
+// Trivial item implementation that tracks its views for testing.
+class TestItem : public SystemTrayItem {
+ public:
+ TestItem()
+ : tray_view_(NULL),
+ default_view_(NULL),
+ detailed_view_(NULL),
+ notification_view_(NULL) {}
+
+ virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE {
+ tray_view_ = new views::View;
+ // Add a label so it has non-zero width.
+ tray_view_->SetLayoutManager(new views::FillLayout);
+ tray_view_->AddChildView(new views::Label(UTF8ToUTF16("Tray")));
+ return tray_view_;
+ }
+
+ virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE {
+ default_view_ = new views::View;
+ default_view_->SetLayoutManager(new views::FillLayout);
+ default_view_->AddChildView(new views::Label(UTF8ToUTF16("Default")));
+ return default_view_;
+ }
+
+ virtual views::View* CreateDetailedView(user::LoginStatus status) OVERRIDE {
+ detailed_view_ = new views::View;
+ detailed_view_->SetLayoutManager(new views::FillLayout);
+ detailed_view_->AddChildView(new views::Label(UTF8ToUTF16("Detailed")));
+ return detailed_view_;
+ }
+
+ virtual views::View* CreateNotificationView(
+ user::LoginStatus status) OVERRIDE {
+ notification_view_ = new views::View;
+ return notification_view_;
+ }
+
+ virtual void DestroyTrayView() OVERRIDE {
+ tray_view_ = NULL;
+ }
+
+ virtual void DestroyDefaultView() OVERRIDE {
+ default_view_ = NULL;
+ }
+
+ virtual void DestroyDetailedView() OVERRIDE {
+ detailed_view_ = NULL;
+ }
+
+ virtual void DestroyNotificationView() OVERRIDE {
+ notification_view_ = NULL;
+ }
+
+ virtual void UpdateAfterLoginStatusChange(
+ user::LoginStatus status) OVERRIDE {}
+
+ views::View* tray_view() const { return tray_view_; }
+ views::View* default_view() const { return default_view_; }
+ views::View* detailed_view() const { return detailed_view_; }
+ views::View* notification_view() const { return notification_view_; }
+
+ private:
+ views::View* tray_view_;
+ views::View* default_view_;
+ views::View* detailed_view_;
+ views::View* notification_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestItem);
+};
+
} // namespace
class ShelfLayoutManagerTest : public ash::test::AshTestBase {
@@ -808,5 +884,53 @@ TEST_F(ShelfLayoutManagerTest, Dimming) {
EXPECT_FALSE(Shell::GetInstance()->launcher()->GetDimsShelf());
}
+// Make sure that the shelf will not hide if the mouse is between a bubble and
+// the shelf.
+TEST_F(ShelfLayoutManagerTest, BubbleEnlargesShelfMouseHitArea) {
+ ShelfLayoutManager* shelf = GetShelfLayoutManager();
+ StatusAreaWidget* status_area = Shell::GetInstance()->status_area_widget();
+ SystemTray* tray = Shell::GetInstance()->system_tray();
+
+ shelf->LayoutShelf();
+ aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
+
+ // Make two iterations - first without a message bubble which should make
+ // the shelf disappear and then with a message bubble which should keep it
+ // visible.
+ for (int i = 0; i < 2; i++) {
+ // Make sure the shelf is visible and position the mouse over it. Then
+ // allow auto hide.
+ shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
+ EXPECT_FALSE(status_area->IsMessageBubbleShown());
+ gfx::Point center =
+ shelf->status()->GetWindowBoundsInScreen().CenterPoint();
+ generator.MoveMouseTo(center.x(), center.y());
+ shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
+ EXPECT_TRUE(shelf->IsVisible());
+ if (!i) {
+ // In our first iteration we make sure there is no bubble.
+ tray->CloseBubbleForTest();
+ EXPECT_FALSE(status_area->IsMessageBubbleShown());
+ } else {
+ // In our second iteration we show a bubble.
+ TestItem *item = new TestItem;
+ tray->AddTrayItem(item);
+ tray->ShowNotificationView(item);
+ EXPECT_TRUE(status_area->IsMessageBubbleShown());
+ }
+ // Move the pointer over the edge of the shelf.
+ generator.MoveMouseTo(center.x(),
+ shelf->status()->GetWindowBoundsInScreen().y() - 5);
+ shelf->UpdateVisibilityState();
+ if (i) {
+ EXPECT_TRUE(shelf->IsVisible());
+ EXPECT_TRUE(status_area->IsMessageBubbleShown());
+ } else {
+ EXPECT_FALSE(shelf->IsVisible());
+ EXPECT_FALSE(status_area->IsMessageBubbleShown());
+ }
+ }
+}
+
} // namespace internal
} // namespace ash