web_notification_tray_unittest.cc revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ash/system/web_notification/web_notification_tray.h"
6
7#include <vector>
8
9#include "ash/display/display_manager.h"
10#include "ash/root_window_controller.h"
11#include "ash/shelf/shelf_layout_manager.h"
12#include "ash/shelf/shelf_widget.h"
13#include "ash/shell.h"
14#include "ash/system/status_area_widget.h"
15#include "ash/system/tray/system_tray.h"
16#include "ash/system/tray/system_tray_item.h"
17#include "ash/system/tray/test_system_tray_delegate.h"
18#include "ash/test/ash_test_base.h"
19#include "ash/wm/window_properties.h"
20#include "base/strings/stringprintf.h"
21#include "base/strings/utf_string_conversions.h"
22#include "ui/aura/client/aura_constants.h"
23#include "ui/aura/test/event_generator.h"
24#include "ui/aura/window.h"
25#include "ui/gfx/display.h"
26#include "ui/gfx/screen.h"
27#include "ui/message_center/message_center_style.h"
28#include "ui/message_center/message_center_tray.h"
29#include "ui/message_center/message_center_util.h"
30#include "ui/message_center/notification_list.h"
31#include "ui/message_center/notification_types.h"
32#include "ui/message_center/views/message_center_bubble.h"
33#include "ui/message_center/views/message_popup_collection.h"
34#include "ui/views/controls/label.h"
35#include "ui/views/layout/fill_layout.h"
36#include "ui/views/view.h"
37#include "ui/views/widget/widget.h"
38
39namespace ash {
40
41namespace {
42
43WebNotificationTray* GetTray() {
44  return Shell::GetPrimaryRootWindowController()->shelf()->
45      status_area_widget()->web_notification_tray();
46}
47
48WebNotificationTray* GetSecondaryTray() {
49  internal::RootWindowController* primary_controller =
50      Shell::GetPrimaryRootWindowController();
51  Shell::RootWindowControllerList controllers =
52      Shell::GetAllRootWindowControllers();
53  for (size_t i = 0; i < controllers.size(); ++i) {
54    if (controllers[i] != primary_controller) {
55      return controllers[i]->shelf()->
56          status_area_widget()->web_notification_tray();
57    }
58  }
59
60  return NULL;
61}
62
63message_center::MessageCenter* GetMessageCenter() {
64  return GetTray()->message_center();
65}
66
67SystemTray* GetSystemTray() {
68  return Shell::GetPrimaryRootWindowController()->shelf()->
69      status_area_widget()->system_tray();
70}
71
72// Trivial item implementation for testing PopupAndSystemTray test case.
73class TestItem : public SystemTrayItem {
74 public:
75  TestItem() : SystemTrayItem(GetSystemTray()) {}
76
77  virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE {
78    views::View* default_view = new views::View;
79    default_view->SetLayoutManager(new views::FillLayout);
80    default_view->AddChildView(new views::Label(UTF8ToUTF16("Default")));
81    return default_view;
82  }
83
84  virtual views::View* CreateNotificationView(
85      user::LoginStatus status) OVERRIDE {
86    return new views::View;
87  }
88
89 private:
90  DISALLOW_COPY_AND_ASSIGN(TestItem);
91};
92
93}  // namespace
94
95class WebNotificationTrayTest : public test::AshTestBase {
96 public:
97  WebNotificationTrayTest() {}
98  virtual ~WebNotificationTrayTest() {}
99
100  virtual void TearDown() OVERRIDE {
101    GetMessageCenter()->RemoveAllNotifications(false);
102    test::AshTestBase::TearDown();
103  }
104
105 protected:
106  void AddNotification(const std::string& id) {
107    scoped_ptr<message_center::Notification> notification;
108    notification.reset(new message_center::Notification(
109        message_center::NOTIFICATION_TYPE_SIMPLE,
110        id,
111        ASCIIToUTF16("Test Web Notification"),
112        ASCIIToUTF16("Notification message body."),
113        gfx::Image(),
114        ASCIIToUTF16("www.test.org"),
115        message_center::NotifierId(),
116        message_center::RichNotificationData(),
117        NULL /* delegate */));
118    GetMessageCenter()->AddNotification(notification.Pass());
119  }
120
121  void UpdateNotification(const std::string& old_id,
122                          const std::string& new_id) {
123    scoped_ptr<message_center::Notification> notification;
124    notification.reset(new message_center::Notification(
125        message_center::NOTIFICATION_TYPE_SIMPLE,
126        new_id,
127        ASCIIToUTF16("Updated Web Notification"),
128        ASCIIToUTF16("Updated message body."),
129        gfx::Image(),
130        ASCIIToUTF16("www.test.org"),
131        message_center::NotifierId(),
132        message_center::RichNotificationData(),
133        NULL /* delegate */));
134    GetMessageCenter()->UpdateNotification(old_id, notification.Pass());
135  }
136
137  void RemoveNotification(const std::string& id) {
138    GetMessageCenter()->RemoveNotification(id, false);
139  }
140
141  views::Widget* GetWidget() {
142    return GetTray()->GetWidget();
143  }
144
145  gfx::Rect GetPopupWorkArea() {
146    return GetPopupWorkAreaForTray(GetTray());
147  }
148
149  gfx::Rect GetPopupWorkAreaForTray(WebNotificationTray* tray) {
150    return tray->popup_collection_->work_area_;
151  }
152
153  bool IsPopupVisible() {
154    return GetTray()->IsPopupVisible();
155  }
156
157 private:
158  DISALLOW_COPY_AND_ASSIGN(WebNotificationTrayTest);
159};
160
161TEST_F(WebNotificationTrayTest, WebNotifications) {
162  // TODO(mukai): move this test case to ui/message_center.
163  ASSERT_TRUE(GetWidget());
164
165  // Add a notification.
166  AddNotification("test_id1");
167  EXPECT_EQ(1u, GetMessageCenter()->NotificationCount());
168  EXPECT_TRUE(GetMessageCenter()->HasNotification("test_id1"));
169  AddNotification("test_id2");
170  AddNotification("test_id2");
171  EXPECT_EQ(2u, GetMessageCenter()->NotificationCount());
172  EXPECT_TRUE(GetMessageCenter()->HasNotification("test_id2"));
173
174  // Ensure that updating a notification does not affect the count.
175  UpdateNotification("test_id2", "test_id3");
176  UpdateNotification("test_id3", "test_id3");
177  EXPECT_EQ(2u, GetMessageCenter()->NotificationCount());
178  EXPECT_FALSE(GetMessageCenter()->HasNotification("test_id2"));
179
180  // Ensure that Removing the first notification removes it from the tray.
181  RemoveNotification("test_id1");
182  EXPECT_FALSE(GetMessageCenter()->HasNotification("test_id1"));
183  EXPECT_EQ(1u, GetMessageCenter()->NotificationCount());
184
185  // Remove the remianing notification.
186  RemoveNotification("test_id3");
187  EXPECT_EQ(0u, GetMessageCenter()->NotificationCount());
188  EXPECT_FALSE(GetMessageCenter()->HasNotification("test_id3"));
189}
190
191TEST_F(WebNotificationTrayTest, WebNotificationPopupBubble) {
192  // TODO(mukai): move this test case to ui/message_center.
193  ASSERT_TRUE(GetWidget());
194
195  // Adding a notification should show the popup bubble.
196  AddNotification("test_id1");
197  EXPECT_TRUE(GetTray()->IsPopupVisible());
198
199  // Updating a notification should not hide the popup bubble.
200  AddNotification("test_id2");
201  UpdateNotification("test_id2", "test_id3");
202  EXPECT_TRUE(GetTray()->IsPopupVisible());
203
204  // Removing the first notification should not hide the popup bubble.
205  RemoveNotification("test_id1");
206  EXPECT_TRUE(GetTray()->IsPopupVisible());
207
208  // Removing the visible notification should hide the popup bubble.
209  RemoveNotification("test_id3");
210  EXPECT_FALSE(GetTray()->IsPopupVisible());
211}
212
213using message_center::NotificationList;
214
215
216// Flakily fails. http://crbug.com/229791
217TEST_F(WebNotificationTrayTest, DISABLED_ManyMessageCenterNotifications) {
218  // Add the max visible notifications +1, ensure the correct visible number.
219  size_t notifications_to_add =
220      message_center::kMaxVisibleMessageCenterNotifications + 1;
221  for (size_t i = 0; i < notifications_to_add; ++i) {
222    std::string id = base::StringPrintf("test_id%d", static_cast<int>(i));
223    AddNotification(id);
224  }
225  bool shown = GetTray()->message_center_tray_->ShowMessageCenterBubble();
226  EXPECT_TRUE(shown);
227  RunAllPendingInMessageLoop();
228  EXPECT_TRUE(GetTray()->message_center_bubble() != NULL);
229  EXPECT_EQ(notifications_to_add,
230            GetMessageCenter()->NotificationCount());
231  EXPECT_EQ(message_center::kMaxVisibleMessageCenterNotifications,
232            GetTray()->GetMessageCenterBubbleForTest()->
233                NumMessageViewsForTest());
234}
235
236// Flakily times out. http://crbug.com/229792
237TEST_F(WebNotificationTrayTest, DISABLED_ManyPopupNotifications) {
238  // Add the max visible popup notifications +1, ensure the correct num visible.
239  size_t notifications_to_add =
240      message_center::kMaxVisiblePopupNotifications + 1;
241  for (size_t i = 0; i < notifications_to_add; ++i) {
242    std::string id = base::StringPrintf("test_id%d", static_cast<int>(i));
243    AddNotification(id);
244  }
245  GetTray()->ShowPopups();
246  EXPECT_TRUE(GetTray()->IsPopupVisible());
247  EXPECT_EQ(notifications_to_add,
248            GetMessageCenter()->NotificationCount());
249  NotificationList::PopupNotifications popups =
250      GetMessageCenter()->GetPopupNotifications();
251  EXPECT_EQ(message_center::kMaxVisiblePopupNotifications, popups.size());
252}
253
254#if defined(OS_CHROMEOS)
255// Display notification is ChromeOS only.
256#define MAYBE_PopupShownOnBothDisplays PopupShownOnBothDisplays
257#define MAYBE_PopupAndSystemTrayMultiDisplay PopupAndSystemTrayMultiDisplay
258#else
259#define MAYBE_PopupShownOnBothDisplays DISABLED_PopupShownOnBothDisplays
260#define MAYBE_PopupAndSystemTrayMultiDisplay \
261  DISABLED_PopupAndSystemTrayMultiDisplay
262#endif
263
264// Verifies if the notification appears on both displays when extended mode.
265TEST_F(WebNotificationTrayTest, MAYBE_PopupShownOnBothDisplays) {
266  if (!SupportsMultipleDisplays())
267    return;
268
269  // Enables to appear the notification for display changes.
270  test::TestSystemTrayDelegate* tray_delegate =
271      static_cast<test::TestSystemTrayDelegate*>(
272          Shell::GetInstance()->system_tray_delegate());
273  tray_delegate->set_should_show_display_notification(true);
274
275  UpdateDisplay("400x400,200x200");
276  // UpdateDisplay() creates the display notifications, so popup is visible.
277  EXPECT_TRUE(GetTray()->IsPopupVisible());
278  WebNotificationTray* secondary_tray = GetSecondaryTray();
279  ASSERT_TRUE(secondary_tray);
280  EXPECT_TRUE(secondary_tray->IsPopupVisible());
281
282  // Transition to mirroring and then back to extended display, which recreates
283  // root window controller and shelf with having notifications. This code
284  // verifies it doesn't cause crash and popups are still visible. See
285  // http://crbug.com/263664
286  internal::DisplayManager* display_manager =
287      Shell::GetInstance()->display_manager();
288
289  display_manager->SetSoftwareMirroring(true);
290  UpdateDisplay("400x400,200x200");
291  EXPECT_TRUE(GetTray()->IsPopupVisible());
292  EXPECT_FALSE(GetSecondaryTray());
293
294  display_manager->SetSoftwareMirroring(false);
295  UpdateDisplay("400x400,200x200");
296  EXPECT_TRUE(GetTray()->IsPopupVisible());
297  secondary_tray = GetSecondaryTray();
298  ASSERT_TRUE(secondary_tray);
299  EXPECT_TRUE(secondary_tray->IsPopupVisible());
300}
301
302#if defined(OS_CHROMEOS)
303// PopupAndSystemTray may fail in platforms other than ChromeOS because the
304// RootWindow's bound can be bigger than gfx::Display's work area so that
305// openingsystem tray doesn't affect at all the work area of popups.
306#define MAYBE_PopupAndSystemTray PopupAndSystemTray
307#define MAYBE_PopupAndAutoHideShelf PopupAndAutoHideShelf
308#define MAYBE_PopupAndFullscreen PopupAndFullscreen
309#else
310#define MAYBE_PopupAndSystemTray DISABLED_PopupAndSystemTray
311#define MAYBE_PopupAndAutoHideShelf DISABLED_PopupAndAutoHideShelf
312#define MAYBE_PopupAndFullscreen DISABLED_PopupAndFullscreen
313#endif
314
315TEST_F(WebNotificationTrayTest, MAYBE_PopupAndSystemTray) {
316  TestItem* test_item = new TestItem;
317  GetSystemTray()->AddTrayItem(test_item);
318
319  AddNotification("test_id");
320  EXPECT_TRUE(GetTray()->IsPopupVisible());
321  gfx::Rect work_area = GetPopupWorkArea();
322
323  // System tray is created, the popup's work area should be narrowed but still
324  // visible.
325  GetSystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW);
326  EXPECT_TRUE(GetTray()->IsPopupVisible());
327  gfx::Rect work_area_with_tray = GetPopupWorkArea();
328  EXPECT_GT(work_area.size().GetArea(), work_area_with_tray.size().GetArea());
329
330  // System tray notification is also created, the popup's work area is narrowed
331  // even more, but still visible.
332  GetSystemTray()->ShowNotificationView(test_item);
333  EXPECT_TRUE(GetTray()->IsPopupVisible());
334  gfx::Rect work_area_with_tray_notificaiton = GetPopupWorkArea();
335  EXPECT_GT(work_area.size().GetArea(),
336            work_area_with_tray_notificaiton.size().GetArea());
337  EXPECT_GT(work_area_with_tray.size().GetArea(),
338            work_area_with_tray_notificaiton.size().GetArea());
339
340  // Close system tray, only system tray notifications.
341  GetSystemTray()->ClickedOutsideBubble();
342  EXPECT_TRUE(GetTray()->IsPopupVisible());
343  gfx::Rect work_area_with_notification = GetPopupWorkArea();
344  EXPECT_GT(work_area.size().GetArea(),
345            work_area_with_notification.size().GetArea());
346  EXPECT_LT(work_area_with_tray_notificaiton.size().GetArea(),
347            work_area_with_notification.size().GetArea());
348
349  // Close the system tray notifications.
350  GetSystemTray()->HideNotificationView(test_item);
351  EXPECT_TRUE(GetTray()->IsPopupVisible());
352  EXPECT_EQ(work_area.ToString(), GetPopupWorkArea().ToString());
353}
354
355TEST_F(WebNotificationTrayTest, MAYBE_PopupAndAutoHideShelf) {
356  AddNotification("test_id");
357  EXPECT_TRUE(GetTray()->IsPopupVisible());
358  gfx::Rect work_area = GetPopupWorkArea();
359
360  // Shelf's auto-hide state won't be HIDDEN unless window exists.
361  scoped_ptr<aura::Window> window(
362      CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 3, 4)));
363  internal::ShelfLayoutManager* shelf =
364      Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
365  shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
366
367  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
368  gfx::Rect work_area_auto_hidden = GetPopupWorkArea();
369  EXPECT_LT(work_area.size().GetArea(), work_area_auto_hidden.size().GetArea());
370
371  // Close the window, which shows the shelf.
372  window.reset();
373  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
374  gfx::Rect work_area_auto_shown = GetPopupWorkArea();
375  EXPECT_EQ(work_area.ToString(), work_area_auto_shown.ToString());
376
377  // Create the system tray during auto-hide.
378  window.reset(CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 3, 4)));
379  TestItem* test_item = new TestItem;
380  GetSystemTray()->AddTrayItem(test_item);
381  GetSystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW);
382
383  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
384  EXPECT_TRUE(GetTray()->IsPopupVisible());
385  gfx::Rect work_area_with_tray = GetPopupWorkArea();
386  EXPECT_GT(work_area_auto_shown.size().GetArea(),
387            work_area_with_tray.size().GetArea());
388
389  // Create tray notification.
390  GetSystemTray()->ShowNotificationView(test_item);
391  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
392  gfx::Rect work_area_with_tray_notification = GetPopupWorkArea();
393  EXPECT_GT(work_area_with_tray.size().GetArea(),
394            work_area_with_tray_notification.size().GetArea());
395
396  // Close the system tray.
397  GetSystemTray()->ClickedOutsideBubble();
398  shelf->UpdateAutoHideState();
399  RunAllPendingInMessageLoop();
400  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
401  gfx::Rect work_area_hidden_with_tray_notification = GetPopupWorkArea();
402  EXPECT_LT(work_area_with_tray_notification.size().GetArea(),
403            work_area_hidden_with_tray_notification.size().GetArea());
404  EXPECT_GT(work_area_auto_hidden.size().GetArea(),
405            work_area_hidden_with_tray_notification.size().GetArea());
406
407  // Close the window again, which shows the shelf.
408  window.reset();
409  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
410  gfx::Rect work_area_shown_with_tray_notification = GetPopupWorkArea();
411  EXPECT_GT(work_area_hidden_with_tray_notification.size().GetArea(),
412            work_area_shown_with_tray_notification.size().GetArea());
413  EXPECT_GT(work_area_auto_shown.size().GetArea(),
414            work_area_shown_with_tray_notification.size().GetArea());
415}
416
417TEST_F(WebNotificationTrayTest, MAYBE_PopupAndFullscreen) {
418  AddNotification("test_id");
419  EXPECT_TRUE(IsPopupVisible());
420  gfx::Rect work_area = GetPopupWorkArea();
421
422  // Checks the work area for normal auto-hidden state.
423  scoped_ptr<aura::Window> window(
424      CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 3, 4)));
425  internal::ShelfLayoutManager* shelf =
426      Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager();
427  shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS);
428  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
429  gfx::Rect work_area_auto_hidden = GetPopupWorkArea();
430  shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER);
431
432  // Make the window to use immersive mode.
433  window->SetProperty(internal::kFullscreenUsesMinimalChromeKey, true);
434  window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN);
435  RunAllPendingInMessageLoop();
436
437  // The work area for auto-hidden status of fullscreen is a bit larger
438  // since it doesn't even have the 3-pixel width.
439  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
440  gfx::Rect work_area_fullscreen_hidden = GetPopupWorkArea();
441  EXPECT_EQ(work_area_auto_hidden.ToString(),
442            work_area_fullscreen_hidden.ToString());
443
444  // Move the mouse cursor at the bottom, which shows the shelf.
445  aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow());
446  gfx::Point bottom_right =
447      Shell::GetScreen()->GetPrimaryDisplay().bounds().bottom_right();
448  bottom_right.Offset(-1, -1);
449  generator.MoveMouseTo(bottom_right);
450  shelf->UpdateAutoHideStateNow();
451  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state());
452  EXPECT_EQ(work_area.ToString(), GetPopupWorkArea().ToString());
453
454  generator.MoveMouseTo(work_area.CenterPoint());
455  shelf->UpdateAutoHideStateNow();
456  EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state());
457  EXPECT_EQ(work_area_auto_hidden.ToString(), GetPopupWorkArea().ToString());
458}
459
460TEST_F(WebNotificationTrayTest, MAYBE_PopupAndSystemTrayMultiDisplay) {
461  UpdateDisplay("800x600,600x400");
462
463  AddNotification("test_id");
464  gfx::Rect work_area = GetPopupWorkArea();
465  gfx::Rect work_area_second = GetPopupWorkAreaForTray(GetSecondaryTray());
466
467  // System tray is created on the primary display. The popups in the secondary
468  // tray aren't affected.
469  GetSystemTray()->ShowDefaultView(BUBBLE_CREATE_NEW);
470  EXPECT_GT(work_area.size().GetArea(), GetPopupWorkArea().size().GetArea());
471  EXPECT_EQ(work_area_second.ToString(),
472            GetPopupWorkAreaForTray(GetSecondaryTray()).ToString());
473}
474
475}  // namespace ash
476