1// Copyright 2013 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 "chrome/browser/ui/views/message_center/web_notification_tray.h"
6
7#include <set>
8
9#include "ash/root_window_controller.h"
10#include "ash/system/status_area_widget.h"
11#include "ash/system/tray/system_tray_item.h"
12#include "base/strings/stringprintf.h"
13#include "base/strings/utf_string_conversions.h"
14#include "chrome/browser/browser_process.h"
15#include "chrome/browser/notifications/message_center_notification_manager.h"
16#include "chrome/browser/notifications/notification.h"
17#include "chrome/browser/notifications/notification_delegate.h"
18#include "chrome/browser/notifications/notification_ui_manager.h"
19#include "chrome/browser/ui/browser.h"
20#include "chrome/test/base/in_process_browser_test.h"
21#include "content/public/test/test_utils.h"
22#include "ui/message_center/message_center_style.h"
23#include "ui/message_center/message_center_tray.h"
24#include "ui/message_center/notification_list.h"
25#include "ui/message_center/notification_types.h"
26#include "ui/message_center/views/message_center_bubble.h"
27#include "ui/message_center/views/message_popup_collection.h"
28#include "ui/views/controls/label.h"
29#include "ui/views/layout/fill_layout.h"
30#include "ui/views/view.h"
31#include "ui/views/widget/widget.h"
32
33namespace message_center {
34
35namespace {
36
37class WebNotificationTrayTest : public InProcessBrowserTest {
38 public:
39  WebNotificationTrayTest() {}
40  virtual ~WebNotificationTrayTest() {}
41
42  virtual void TearDownOnMainThread() OVERRIDE {
43    message_center::MessageCenter::Get()->RemoveAllNotifications(false);
44  }
45
46 protected:
47  class TestNotificationDelegate : public ::NotificationDelegate {
48   public:
49    explicit TestNotificationDelegate(std::string id) : id_(id) {}
50    virtual void Display() OVERRIDE {}
51    virtual void Error() OVERRIDE {}
52    virtual void Close(bool by_user) OVERRIDE {}
53    virtual void Click() OVERRIDE {}
54    virtual std::string id() const OVERRIDE { return id_; }
55    virtual content::WebContents* GetWebContents() const OVERRIDE {
56      return NULL;
57    }
58
59   private:
60    virtual ~TestNotificationDelegate() {}
61
62    std::string id_;
63  };
64
65  void AddNotification(const std::string& id, const std::string& replace_id) {
66    ::Notification notification(GURL("chrome-extension://abbccedd"),
67                                GURL(),
68                                base::ASCIIToUTF16("Test Web Notification"),
69                                base::ASCIIToUTF16(
70                                    "Notification message body."),
71                                blink::WebTextDirectionDefault,
72                                base::string16(),
73                                base::ASCIIToUTF16(replace_id),
74                                new TestNotificationDelegate(id));
75
76    g_browser_process->notification_ui_manager()->Add(
77     notification, browser()->profile());
78  }
79
80  void UpdateNotification(const std::string& replace_id,
81                          const std::string& new_id) {
82    ::Notification notification(GURL("chrome-extension://abbccedd"),
83                                GURL(""),
84                                base::ASCIIToUTF16("Updated Web Notification"),
85                                base::ASCIIToUTF16("Updated message body."),
86                                blink::WebTextDirectionDefault,
87                                base::string16(),
88                                base::ASCIIToUTF16(replace_id),
89                                new TestNotificationDelegate(new_id));
90
91    g_browser_process->notification_ui_manager()->Add(
92     notification, browser()->profile());
93  }
94
95  void RemoveNotification(const std::string& id) {
96    g_browser_process->notification_ui_manager()->CancelById(id);
97  }
98
99  bool HasNotification(message_center::MessageCenter* message_center,
100                       const std::string& id) {
101    return message_center->FindVisibleNotificationById(id) != NULL;
102  }
103
104 private:
105  DISALLOW_COPY_AND_ASSIGN(WebNotificationTrayTest);
106};
107
108}  // namespace
109
110
111// TODO(dewittj): More exhaustive testing.
112IN_PROC_BROWSER_TEST_F(WebNotificationTrayTest, WebNotifications) {
113  message_center::MessageCenter* message_center =
114      message_center::MessageCenter::Get();
115
116  // Add a notification.
117  AddNotification("test_id1", "replace_id1");
118  EXPECT_EQ(1u, message_center->NotificationCount());
119  EXPECT_TRUE(HasNotification(message_center, "test_id1"));
120  EXPECT_FALSE(HasNotification(message_center, "test_id2"));
121  AddNotification("test_id2", "replace_id2");
122  AddNotification("test_id2", "replace_id2");
123  EXPECT_EQ(2u, message_center->NotificationCount());
124  EXPECT_TRUE(HasNotification(message_center, "test_id1"));
125
126  // Ensure that updating a notification does not affect the count.
127  UpdateNotification("replace_id2", "test_id3");
128  UpdateNotification("replace_id2", "test_id3");
129  EXPECT_EQ(2u, message_center->NotificationCount());
130  EXPECT_FALSE(HasNotification(message_center, "test_id2"));
131
132  // Ensure that Removing the first notification removes it from the tray.
133  RemoveNotification("test_id1");
134  EXPECT_FALSE(HasNotification(message_center, "test_id1"));
135  EXPECT_EQ(1u, message_center->NotificationCount());
136
137  // Remove the remaining notification.
138  RemoveNotification("test_id3");
139  EXPECT_EQ(0u, message_center->NotificationCount());
140  EXPECT_FALSE(HasNotification(message_center, "test_id1"));
141}
142
143IN_PROC_BROWSER_TEST_F(WebNotificationTrayTest, WebNotificationPopupBubble) {
144  scoped_ptr<WebNotificationTray> tray(new WebNotificationTray(NULL));
145  tray->message_center();
146
147  // Adding a notification should show the popup bubble.
148  AddNotification("test_id1", "replace_id1");
149  EXPECT_TRUE(tray->message_center_tray_->popups_visible());
150
151  // Updating a notification should not hide the popup bubble.
152  AddNotification("test_id2", "replace_id2");
153  UpdateNotification("replace_id2", "test_id3");
154  EXPECT_TRUE(tray->message_center_tray_->popups_visible());
155
156  // Removing the first notification should not hide the popup bubble.
157  RemoveNotification("test_id1");
158  EXPECT_TRUE(tray->message_center_tray_->popups_visible());
159
160  // Removing the visible notification should hide the popup bubble.
161  RemoveNotification("test_id3");
162  EXPECT_FALSE(tray->message_center_tray_->popups_visible());
163}
164
165using message_center::NotificationList;
166
167// Flaky, see http://crbug.com/222500 .
168IN_PROC_BROWSER_TEST_F(WebNotificationTrayTest,
169                       DISABLED_ManyMessageCenterNotifications) {
170  scoped_ptr<WebNotificationTray> tray(new WebNotificationTray(NULL));
171  message_center::MessageCenter* message_center = tray->message_center();
172
173  // Add the max visible notifications +1, ensure the correct visible number.
174  size_t notifications_to_add = kMaxVisibleMessageCenterNotifications + 1;
175  for (size_t i = 0; i < notifications_to_add; ++i) {
176    std::string id = base::StringPrintf("test_id%d", static_cast<int>(i));
177    std::string replace_id =
178        base::StringPrintf("replace_id%d", static_cast<int>(i));
179    AddNotification(id, replace_id);
180  }
181  bool shown = tray->message_center_tray_->ShowMessageCenterBubble();
182  EXPECT_TRUE(shown);
183  content::RunAllPendingInMessageLoop();
184  EXPECT_TRUE(tray->message_center_delegate_ != NULL);
185  EXPECT_EQ(notifications_to_add, message_center->NotificationCount());
186  EXPECT_EQ(kMaxVisibleMessageCenterNotifications,
187            tray->message_center_delegate_->NumMessageViewsForTest());
188}
189
190IN_PROC_BROWSER_TEST_F(WebNotificationTrayTest, ManyPopupNotifications) {
191  scoped_ptr<WebNotificationTray> tray(new WebNotificationTray(NULL));
192  message_center::MessageCenter* message_center = tray->message_center();
193
194  // Add the max visible popup notifications +1, ensure the correct num visible.
195  size_t notifications_to_add = kMaxVisiblePopupNotifications + 1;
196  for (size_t i = 0; i < notifications_to_add; ++i) {
197    std::string id = base::StringPrintf("test_id%d", static_cast<int>(i));
198    std::string replace_id =
199        base::StringPrintf("replace_id%d", static_cast<int>(i));
200    AddNotification(id, replace_id);
201  }
202  // Hide and reshow the bubble so that it is updated immediately, not delayed.
203  tray->message_center_tray_->HidePopupBubble();
204  tray->message_center_tray_->ShowPopupBubble();
205  EXPECT_TRUE(tray->message_center_tray_->popups_visible());
206  EXPECT_EQ(notifications_to_add, message_center->NotificationCount());
207  NotificationList::PopupNotifications popups =
208      message_center->GetPopupNotifications();
209  EXPECT_EQ(kMaxVisiblePopupNotifications, popups.size());
210}
211
212IN_PROC_BROWSER_TEST_F(WebNotificationTrayTest,
213                       ManuallyCloseMessageCenter) {
214  NotificationUIManager* manager = g_browser_process->notification_ui_manager();
215  MessageCenterNotificationManager* mc_manager =
216      static_cast<MessageCenterNotificationManager*>(manager);
217
218  WebNotificationTray* tray =
219      static_cast<WebNotificationTray*>(mc_manager->tray_.get());
220  ASSERT_TRUE(NULL != tray);
221
222  message_center::MessageCenter* message_center = tray->message_center();
223
224  bool shown = tray->message_center_tray_->ShowMessageCenterBubble();
225  EXPECT_TRUE(shown);
226  EXPECT_TRUE(message_center->IsMessageCenterVisible());
227
228  mc_manager->EnsureMessageCenterClosed();
229
230  EXPECT_FALSE(message_center->IsMessageCenterVisible());
231  if (NULL != tray->message_center_delegate_)
232    EXPECT_TRUE(tray->message_center_delegate_->GetWidget()->IsClosed());
233}
234
235#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
236#define MAYBE_StatusIconBehavior DISABLED_StatusIconBehavior
237#else
238#define MAYBE_StatusIconBehavior StatusIconBehavior
239#endif
240IN_PROC_BROWSER_TEST_F(WebNotificationTrayTest, MAYBE_StatusIconBehavior) {
241  scoped_ptr<WebNotificationTray> tray(new WebNotificationTray(NULL));
242
243  EXPECT_TRUE(tray->status_icon_ == NULL);
244  tray->OnMessageCenterTrayChanged();
245  base::RunLoop().RunUntilIdle();
246  EXPECT_TRUE(tray->status_icon_ == NULL);
247  AddNotification("test_id", "replace_id");
248  base::RunLoop().RunUntilIdle();
249  EXPECT_TRUE(tray->status_icon_ != NULL);
250  RemoveNotification("test_id");
251  base::RunLoop().RunUntilIdle();
252  EXPECT_TRUE(tray->status_icon_ == NULL);
253}
254}  // namespace message_center
255