notification_grouping_controller_unittest.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. // Copyright 2021 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. #include "ash/system/message_center/notification_grouping_controller.h"
  5. #include "ash/constants/ash_features.h"
  6. #include "ash/system/message_center/ash_message_popup_collection.h"
  7. #include "ash/system/unified/unified_system_tray.h"
  8. #include "ash/test/ash_test_base.h"
  9. #include "ash/test/layer_animation_stopped_waiter.h"
  10. #include "base/test/scoped_feature_list.h"
  11. #include "ui/compositor/scoped_animation_duration_scale_mode.h"
  12. #include "ui/message_center/public/cpp/message_center_constants.h"
  13. #include "ui/message_center/public/cpp/notifier_id.h"
  14. #include "ui/message_center/views/message_popup_view.h"
  15. using message_center::kIdSuffixForGroupContainerNotification;
  16. using message_center::MessageCenter;
  17. using message_center::Notification;
  18. namespace ash {
  19. namespace {
  20. const char kIdFormat[] = "id%ld";
  21. } // namespace
  22. class NotificationGroupingControllerTest : public AshTestBase {
  23. public:
  24. NotificationGroupingControllerTest() = default;
  25. NotificationGroupingControllerTest(
  26. const NotificationGroupingControllerTest& other) = delete;
  27. NotificationGroupingControllerTest& operator=(
  28. const NotificationGroupingControllerTest& other) = delete;
  29. ~NotificationGroupingControllerTest() override = default;
  30. void SetUp() override {
  31. scoped_feature_list_.InitAndEnableFeature(
  32. ash::features::kNotificationsRefresh);
  33. AshTestBase::SetUp();
  34. }
  35. protected:
  36. std::string AddNotificationWithOriginUrl(const GURL& origin_url) {
  37. std::string id;
  38. MessageCenter::Get()->AddNotification(MakeNotification(id, origin_url));
  39. return id;
  40. }
  41. void AnimateUntilIdle() {
  42. AshMessagePopupCollection* popup_collection =
  43. GetPrimaryUnifiedSystemTray()->GetMessagePopupCollection();
  44. while (popup_collection->animation()->is_animating()) {
  45. popup_collection->animation()->SetCurrentValue(1.0);
  46. popup_collection->animation()->End();
  47. }
  48. }
  49. message_center::MessagePopupView* GetPopupView(const std::string& id) {
  50. return GetPrimaryUnifiedSystemTray()->GetPopupViewForNotificationID(id);
  51. }
  52. // Construct a new notification for testing.
  53. std::unique_ptr<Notification> MakeNotification(std::string& id_out,
  54. const GURL& origin_url) {
  55. id_out = base::StringPrintf(kIdFormat, notifications_counter_);
  56. message_center::NotifierId notifier_id;
  57. notifier_id.profile_id = "abc@gmail.com";
  58. notifier_id.type = message_center::NotifierType::WEB_PAGE;
  59. auto notification = std::make_unique<Notification>(
  60. message_center::NOTIFICATION_TYPE_SIMPLE, id_out,
  61. u"id" + base::NumberToString16(notifications_counter_),
  62. u"message" + base::NumberToString16(notifications_counter_),
  63. ui::ImageModel(), u"src", origin_url, notifier_id,
  64. message_center::RichNotificationData(), nullptr);
  65. notifications_counter_++;
  66. return notification;
  67. }
  68. base::test::ScopedFeatureList scoped_feature_list_;
  69. size_t notifications_counter_ = 0;
  70. };
  71. TEST_F(NotificationGroupingControllerTest, BasicGrouping) {
  72. auto* message_center = MessageCenter::Get();
  73. std::string id0, id1, id2;
  74. const GURL url(u"http://test-url.com/");
  75. id0 = AddNotificationWithOriginUrl(url);
  76. id1 = AddNotificationWithOriginUrl(url);
  77. id2 = AddNotificationWithOriginUrl(url);
  78. EXPECT_TRUE(message_center->FindNotificationById(id0)->group_child());
  79. EXPECT_TRUE(message_center->FindNotificationById(id1)->group_child());
  80. EXPECT_TRUE(message_center->FindNotificationById(id2)->group_child());
  81. std::string id_parent = id0 + kIdSuffixForGroupContainerNotification;
  82. EXPECT_TRUE(message_center->FindNotificationById(id_parent)->group_parent());
  83. }
  84. TEST_F(NotificationGroupingControllerTest, BasicRemoval) {
  85. std::string id0, id1, id2;
  86. const GURL url(u"http://test-url.com");
  87. id0 = AddNotificationWithOriginUrl(url);
  88. id1 = AddNotificationWithOriginUrl(url);
  89. id2 = AddNotificationWithOriginUrl(url);
  90. std::string id_parent = id0 + kIdSuffixForGroupContainerNotification;
  91. // Group notification should stay intact if a single group notification is
  92. // removed.
  93. MessageCenter::Get()->RemoveNotification(id1, true);
  94. EXPECT_TRUE(
  95. MessageCenter::Get()->FindNotificationById(id_parent)->group_parent());
  96. // Adding and removing a non group notification should have no impact.
  97. std::string tmp = AddNotificationWithOriginUrl(GURL(u"tmp"));
  98. MessageCenter::Get()->RemoveNotification(tmp, true);
  99. EXPECT_TRUE(MessageCenter::Get()->FindNotificationById(id0)->group_child());
  100. EXPECT_TRUE(MessageCenter::Get()->FindNotificationById(id2)->group_child());
  101. EXPECT_TRUE(
  102. MessageCenter::Get()->FindNotificationById(id_parent)->group_parent());
  103. }
  104. TEST_F(NotificationGroupingControllerTest,
  105. ParentNotificationReshownWithNewChild) {
  106. auto* tray = GetPrimaryUnifiedSystemTray();
  107. std::string id0;
  108. const GURL url(u"http://test-url.com");
  109. id0 = AddNotificationWithOriginUrl(url);
  110. std::string tmp;
  111. tmp = AddNotificationWithOriginUrl(url);
  112. std::string parent_id = id0 + kIdSuffixForGroupContainerNotification;
  113. EXPECT_TRUE(GetPopupView(parent_id));
  114. // Toggle the system tray to dismiss all popups.
  115. tray->ShowBubble();
  116. tray->CloseBubble();
  117. EXPECT_FALSE(GetPopupView(parent_id));
  118. // Adding notification with a different notifier id should have no effect.
  119. AddNotificationWithOriginUrl(GURL("tmp"));
  120. EXPECT_FALSE(GetPopupView(parent_id));
  121. AddNotificationWithOriginUrl(url);
  122. // Move down or fade in animation might happen before showing the popup.
  123. AnimateUntilIdle();
  124. EXPECT_TRUE(GetPopupView(parent_id));
  125. }
  126. TEST_F(NotificationGroupingControllerTest,
  127. RemovingParentRemovesChildGroupNotifications) {
  128. std::string id0;
  129. const GURL url(u"http://test-url.com");
  130. id0 = AddNotificationWithOriginUrl(url);
  131. std::string tmp;
  132. AddNotificationWithOriginUrl(url);
  133. AddNotificationWithOriginUrl(url);
  134. MessageCenter::Get()->RemoveNotification(
  135. id0 + kIdSuffixForGroupContainerNotification, true);
  136. ASSERT_FALSE(MessageCenter::Get()->HasPopupNotifications());
  137. }
  138. TEST_F(NotificationGroupingControllerTest,
  139. RepopulatedParentNotificationRemoval) {
  140. auto* message_center = MessageCenter::Get();
  141. std::string id0, id1, id2, id3, id4;
  142. const GURL url(u"http://test-url.com");
  143. id0 = AddNotificationWithOriginUrl(url);
  144. id1 = AddNotificationWithOriginUrl(url);
  145. id2 = AddNotificationWithOriginUrl(url);
  146. id3 = AddNotificationWithOriginUrl(url);
  147. std::string parent_id = id0 + kIdSuffixForGroupContainerNotification;
  148. // Toggle the system tray to dismiss all popups.
  149. GetPrimaryUnifiedSystemTray()->ShowBubble();
  150. GetPrimaryUnifiedSystemTray()->CloseBubble();
  151. id4 = AddNotificationWithOriginUrl(url);
  152. AnimateUntilIdle();
  153. message_center->RemoveNotification(id0, true);
  154. message_center->RemoveNotification(id1, true);
  155. message_center->RemoveNotification(id2, true);
  156. message_center->RemoveNotification(id3, true);
  157. auto* last_child = MessageCenter::Get()->FindNotificationById(id4);
  158. auto* parent = MessageCenter::Get()->FindNotificationById(parent_id);
  159. EXPECT_TRUE(last_child->group_child());
  160. EXPECT_TRUE(parent->group_parent());
  161. }
  162. TEST_F(NotificationGroupingControllerTest,
  163. NotificationsGroupingOnMultipleScreens) {
  164. UpdateDisplay("800x600,800x600");
  165. auto* message_center = MessageCenter::Get();
  166. std::string id0, id1, id2;
  167. const GURL url(u"http://test-url.com/");
  168. id0 = AddNotificationWithOriginUrl(url);
  169. id1 = AddNotificationWithOriginUrl(url);
  170. id2 = AddNotificationWithOriginUrl(url);
  171. EXPECT_TRUE(message_center->FindNotificationById(id0)->group_child());
  172. EXPECT_TRUE(message_center->FindNotificationById(id1)->group_child());
  173. EXPECT_TRUE(message_center->FindNotificationById(id2)->group_child());
  174. std::string id_parent = id0 + kIdSuffixForGroupContainerNotification;
  175. EXPECT_TRUE(message_center->FindNotificationById(id_parent)->group_parent());
  176. // Make sure there is only a single popup (there would be more popups if
  177. // grouping didn't work)
  178. EXPECT_EQ(1u, message_center->GetPopupNotifications().size());
  179. }
  180. // Create a group notification while the message center bubble is
  181. // is shown.
  182. TEST_F(NotificationGroupingControllerTest,
  183. NotificationsGroupingMessageCenterBubbleShown) {
  184. GetPrimaryUnifiedSystemTray()->ShowBubble();
  185. auto* message_center = MessageCenter::Get();
  186. std::string id0, id1, id2;
  187. const GURL url(u"http://test-url.com/");
  188. id0 = AddNotificationWithOriginUrl(url);
  189. id1 = AddNotificationWithOriginUrl(url);
  190. id2 = AddNotificationWithOriginUrl(url);
  191. EXPECT_TRUE(message_center->FindNotificationById(id0)->group_child());
  192. EXPECT_TRUE(message_center->FindNotificationById(id1)->group_child());
  193. std::string id_parent = id0 + kIdSuffixForGroupContainerNotification;
  194. EXPECT_TRUE(message_center->FindNotificationById(id_parent)->group_parent());
  195. }
  196. TEST_F(NotificationGroupingControllerTest,
  197. GroupedNotificationRemovedDuringAnimation) {
  198. auto* message_center = MessageCenter::Get();
  199. std::string id0, id1;
  200. const GURL url(u"http://test-url.com/");
  201. // Enable animations.
  202. ui::ScopedAnimationDurationScaleMode duration(
  203. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  204. id0 = AddNotificationWithOriginUrl(url);
  205. id1 = AddNotificationWithOriginUrl(url);
  206. // Remove notification with `id` before the animation completes.
  207. message_center->RemoveNotification(id1, true);
  208. // Wait for the animation to end to ensure there is no crash
  209. LayerAnimationStoppedWaiter waiter;
  210. waiter.Wait(GetPopupView(id0)->message_view()->layer());
  211. }
  212. TEST_F(NotificationGroupingControllerTest,
  213. ParentNotificationRemovedDuringAnimation) {
  214. // Enable animations.
  215. ui::ScopedAnimationDurationScaleMode duration(
  216. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  217. auto* message_center = MessageCenter::Get();
  218. std::string id0, id1;
  219. const GURL url(u"http://test-url.com/");
  220. id0 = AddNotificationWithOriginUrl(url);
  221. id1 = AddNotificationWithOriginUrl(url);
  222. // Remove the first notification before the animation completes.
  223. message_center->RemoveNotification(id0, true);
  224. // Wait for the animation to end to ensure there is no crash
  225. LayerAnimationStoppedWaiter waiter;
  226. waiter.Wait(GetPopupView(id0)->message_view()->layer());
  227. // Make sure the second notification is still there.
  228. EXPECT_FALSE(message_center->FindNotificationById(id0));
  229. EXPECT_TRUE(message_center->FindNotificationById(id1));
  230. }
  231. } // namespace ash