ash_notification_view_unittest.cc 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102
  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/ash_notification_view.h"
  5. #include <string>
  6. #include "ash/constants/ash_features.h"
  7. #include "ash/public/cpp/rounded_image_view.h"
  8. #include "ash/strings/grit/ash_strings.h"
  9. #include "ash/style/icon_button.h"
  10. #include "ash/system/message_center/ash_notification_expand_button.h"
  11. #include "ash/system/message_center/message_center_style.h"
  12. #include "ash/system/message_center/metrics_utils.h"
  13. #include "ash/system/message_center/unified_message_center_bubble.h"
  14. #include "ash/system/message_center/unified_message_center_view.h"
  15. #include "ash/system/message_center/unified_message_list_view.h"
  16. #include "ash/system/unified/unified_system_tray.h"
  17. #include "ash/test/ash_test_base.h"
  18. #include "ash/test/layer_animation_stopped_waiter.h"
  19. #include "base/test/metrics/histogram_tester.h"
  20. #include "base/test/scoped_feature_list.h"
  21. #include "base/time/time.h"
  22. #include "ui/base/l10n/l10n_util.h"
  23. #include "ui/compositor/layer.h"
  24. #include "ui/compositor/layer_animator.h"
  25. #include "ui/compositor/scoped_animation_duration_scale_mode.h"
  26. #include "ui/compositor/test/test_utils.h"
  27. #include "ui/events/test/test_event.h"
  28. #include "ui/gfx/color_utils.h"
  29. #include "ui/message_center/message_center.h"
  30. #include "ui/message_center/public/cpp/notification.h"
  31. #include "ui/message_center/views/message_view.h"
  32. #include "ui/message_center/views/notification_header_view.h"
  33. #include "ui/message_center/views/notification_view.h"
  34. #include "ui/message_center/views/proportional_image_view.h"
  35. #include "ui/strings/grit/ui_strings.h"
  36. #include "ui/views/controls/button/image_button.h"
  37. #include "ui/views/controls/button/label_button.h"
  38. #include "ui/views/controls/label.h"
  39. #include "ui/views/layout/flex_layout_view.h"
  40. #include "ui/views/test/button_test_api.h"
  41. using message_center::Notification;
  42. using message_center::NotificationHeaderView;
  43. using message_center::NotificationView;
  44. namespace ash {
  45. namespace {
  46. const gfx::Image CreateTestImage(int width,
  47. int height,
  48. SkColor color = SK_ColorGREEN) {
  49. SkBitmap bitmap;
  50. bitmap.allocN32Pixels(width, height);
  51. bitmap.eraseColor(color);
  52. return gfx::Image::CreateFrom1xBitmap(bitmap);
  53. }
  54. class NotificationTestDelegate : public message_center::NotificationDelegate {
  55. public:
  56. NotificationTestDelegate() = default;
  57. NotificationTestDelegate(const NotificationTestDelegate&) = delete;
  58. NotificationTestDelegate& operator=(const NotificationTestDelegate&) = delete;
  59. void DisableNotification() override { disable_notification_called_ = true; }
  60. bool disable_notification_called() const {
  61. return disable_notification_called_;
  62. }
  63. private:
  64. ~NotificationTestDelegate() override = default;
  65. bool disable_notification_called_ = false;
  66. };
  67. } // namespace
  68. class AshNotificationViewTest : public AshTestBase, public views::ViewObserver {
  69. public:
  70. AshNotificationViewTest()
  71. : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
  72. scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
  73. scoped_feature_list_->InitAndEnableFeature(features::kNotificationsRefresh);
  74. }
  75. AshNotificationViewTest(const AshNotificationViewTest&) = delete;
  76. AshNotificationViewTest& operator=(const AshNotificationViewTest&) = delete;
  77. ~AshNotificationViewTest() override = default;
  78. // AshTestBase:
  79. void SetUp() override {
  80. AshTestBase::SetUp();
  81. delegate_ = new NotificationTestDelegate();
  82. auto notification = CreateTestNotification();
  83. notification_view_ = std::make_unique<AshNotificationView>(
  84. *notification, /*is_popup=*/false);
  85. }
  86. void TearDown() override {
  87. notification_view_.reset();
  88. AshTestBase::TearDown();
  89. }
  90. // Create a test notification that is used in the view.
  91. std::unique_ptr<Notification> CreateTestNotification(
  92. bool has_image = false,
  93. bool show_snooze_button = false,
  94. bool has_message = true,
  95. message_center::NotificationType notification_type =
  96. message_center::NOTIFICATION_TYPE_SIMPLE) {
  97. message_center::RichNotificationData data;
  98. data.settings_button_handler =
  99. message_center::SettingsButtonHandler::INLINE;
  100. data.should_show_snooze_button = show_snooze_button;
  101. std::u16string message = has_message ? u"message" : u"";
  102. std::unique_ptr<Notification> notification = std::make_unique<Notification>(
  103. notification_type, base::NumberToString(current_id_++), u"title",
  104. message, ui::ImageModel::FromImage(CreateTestImage(80, 80)),
  105. u"display source", GURL(),
  106. message_center::NotifierId(message_center::NotifierType::APPLICATION,
  107. "extension_id"),
  108. data, delegate_);
  109. notification->set_small_image(CreateTestImage(16, 16));
  110. if (has_image)
  111. notification->set_image(CreateTestImage(320, 240));
  112. message_center::MessageCenter::Get()->AddNotification(
  113. std::make_unique<message_center::Notification>(*notification));
  114. return notification;
  115. }
  116. // Create a test notification. All the notifications created by this function
  117. // will belong to the same group.
  118. std::unique_ptr<Notification> CreateTestNotificationInAGroup() {
  119. message_center::NotifierId notifier_id;
  120. notifier_id.profile_id = "abc@gmail.com";
  121. notifier_id.type = message_center::NotifierType::WEB_PAGE;
  122. std::unique_ptr<Notification> notification = std::make_unique<Notification>(
  123. message_center::NOTIFICATION_TYPE_SIMPLE,
  124. base::NumberToString(current_id_++), u"title", u"message",
  125. ui::ImageModel::FromImage(CreateTestImage(80, 80)), u"display source",
  126. GURL(u"http://test-url.com"), notifier_id,
  127. message_center::RichNotificationData(), delegate_);
  128. notification->set_small_image(CreateTestImage(16, 16));
  129. message_center::MessageCenter::Get()->AddNotification(
  130. std::make_unique<message_center::Notification>(*notification));
  131. return notification;
  132. }
  133. // Get the tested notification view from message center. This is used in
  134. // checking smoothness metrics: The check requires the use of the compositor,
  135. // which we don't have in the customed made `notification_view_`.
  136. AshNotificationView* GetNotificationViewFromMessageCenter(std::string id) {
  137. return static_cast<AshNotificationView*>(
  138. GetPrimaryUnifiedSystemTray()
  139. ->message_center_bubble()
  140. ->message_center_view()
  141. ->message_list_view()
  142. ->GetMessageViewForNotificationId(std::string(id)));
  143. }
  144. void UpdateTimestamp(base::Time timestamp) {
  145. notification_view()->title_row_->UpdateTimestamp(timestamp);
  146. }
  147. void AdvanceClock(base::TimeDelta time_delta) {
  148. // Note that AdvanceClock() is used here instead of FastForwardBy() to
  149. // prevent long run time during an ash test session.
  150. task_environment()->AdvanceClock(time_delta);
  151. task_environment()->RunUntilIdle();
  152. }
  153. // Toggle inline settings with a dummy event.
  154. void ToggleInlineSettings(AshNotificationView* view) {
  155. view->ToggleInlineSettings(ui::test::TestEvent());
  156. }
  157. // Make the given notification to become a group parent of some basic
  158. // notifications.
  159. void MakeNotificationGroupParent(AshNotificationView* view,
  160. int group_child_num) {
  161. auto* notification =
  162. message_center::MessageCenter::Get()->FindVisibleNotificationById(
  163. view->notification_id());
  164. notification->SetGroupParent();
  165. view->UpdateWithNotification(*notification);
  166. for (int i = 0; i < 1; i++) {
  167. auto group_child = CreateTestNotification();
  168. group_child->SetGroupChild();
  169. view->AddGroupNotification(*group_child.get());
  170. }
  171. }
  172. // Check that smoothness should be recorded after an animation is performed on
  173. // a particular view.
  174. void CheckSmoothnessRecorded(base::HistogramTester& histograms,
  175. views::View* view,
  176. const char* animation_histogram_name,
  177. int data_point_count = 1) {
  178. ui::Compositor* compositor = view->layer()->GetCompositor();
  179. LayerAnimationStoppedWaiter animation_waiter;
  180. animation_waiter.Wait(view->layer());
  181. // Force a frame then wait, ensuring there is one more frame presented after
  182. // animation finishes to allow animation throughput data to be passed from
  183. // cc to ui.
  184. compositor->ScheduleFullRedraw();
  185. EXPECT_TRUE(ui::WaitForNextFrameToBePresented(compositor));
  186. // Smoothness should be recorded.
  187. histograms.ExpectTotalCount(animation_histogram_name, data_point_count);
  188. }
  189. protected:
  190. AshNotificationView* GetFirstGroupedChildNotificationView(
  191. AshNotificationView* view) {
  192. if (!view->grouped_notifications_container_->children().size()) {
  193. return nullptr;
  194. }
  195. return static_cast<AshNotificationView*>(
  196. view->grouped_notifications_container_->children().front());
  197. }
  198. std::vector<views::View*> GetChildNotifications(AshNotificationView* view) {
  199. return view->grouped_notifications_container_->children();
  200. }
  201. views::View* GetMainView(AshNotificationView* view) {
  202. return view->main_view_;
  203. }
  204. views::View* GetMainRightView(AshNotificationView* view) {
  205. return view->main_right_view_;
  206. }
  207. NotificationHeaderView* GetHeaderRow(AshNotificationView* view) {
  208. return view->header_row();
  209. }
  210. views::View* GetLeftContent(AshNotificationView* view) {
  211. return view->left_content();
  212. }
  213. views::View* GetTitleRowDivider(AshNotificationView* view) {
  214. return view->title_row_->title_row_divider_;
  215. }
  216. views::Label* GetTimestampInCollapsedView(AshNotificationView* view) {
  217. return view->title_row_->timestamp_in_collapsed_view_;
  218. }
  219. const views::Label* GetTimestamp(AshNotificationView* view) {
  220. return view->header_row()->timestamp_view_for_testing();
  221. }
  222. views::Label* GetMessageLabel(AshNotificationView* view) {
  223. return view->message_label();
  224. }
  225. views::Label* GetMessageLabelInExpandedState(AshNotificationView* view) {
  226. return view->message_label_in_expanded_state_;
  227. }
  228. message_center::ProportionalImageView* GetIconView(
  229. AshNotificationView* view) const {
  230. return view->icon_view();
  231. }
  232. AshNotificationExpandButton* GetExpandButton(AshNotificationView* view) {
  233. return view->expand_button_;
  234. }
  235. views::View* GetCollapsedSummaryView(AshNotificationView* view) {
  236. return view->collapsed_summary_view_;
  237. }
  238. views::View* GetImageContainerView(AshNotificationView* view) {
  239. return view->image_container_view();
  240. }
  241. views::View* GetActionsRow(AshNotificationView* view) {
  242. return view->actions_row();
  243. }
  244. views::View* GetActionButtonsRow(AshNotificationView* view) {
  245. return view->action_buttons_row();
  246. }
  247. std::vector<views::LabelButton*> GetActionButtons(AshNotificationView* view) {
  248. return view->action_buttons();
  249. }
  250. message_center::NotificationInputContainer* GetInlineReply(
  251. AshNotificationView* view) {
  252. return view->inline_reply();
  253. }
  254. views::View* GetInlineSettingsRow(AshNotificationView* view) {
  255. return view->inline_settings_row();
  256. }
  257. views::View* GetGroupedNotificationsContainer(AshNotificationView* view) {
  258. return view->grouped_notifications_container_;
  259. }
  260. AshNotificationView* notification_view() { return notification_view_.get(); }
  261. views::View* content_row() { return notification_view_->content_row(); }
  262. RoundedImageView* app_icon_view() {
  263. return notification_view_->app_icon_view_;
  264. }
  265. views::View* title_row() { return notification_view_->title_row_; }
  266. views::Label* title_view() {
  267. return notification_view_->title_row_->title_view_;
  268. }
  269. AshNotificationExpandButton* expand_button() {
  270. return notification_view_->expand_button_;
  271. }
  272. views::LabelButton* turn_off_notifications_button() {
  273. return notification_view_->turn_off_notifications_button_;
  274. }
  275. views::LabelButton* inline_settings_cancel_button() {
  276. return notification_view_->inline_settings_cancel_button_;
  277. }
  278. IconButton* snooze_button() { return notification_view_->snooze_button_; }
  279. scoped_refptr<NotificationTestDelegate> delegate() { return delegate_; }
  280. private:
  281. std::unique_ptr<AshNotificationView> notification_view_;
  282. scoped_refptr<NotificationTestDelegate> delegate_;
  283. std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
  284. // Used to create test notification. This represents the current available
  285. // number that we can use to create the next test notification. This id will
  286. // be incremented whenever we create a new test notification.
  287. int current_id_ = 0;
  288. };
  289. TEST_F(AshNotificationViewTest, UpdateViewsOrderingTest) {
  290. EXPECT_NE(nullptr, title_row());
  291. EXPECT_NE(nullptr, GetMessageLabel(notification_view()));
  292. EXPECT_EQ(0u, GetLeftContent(notification_view())->GetIndexOf(title_row()));
  293. EXPECT_EQ(1u, GetLeftContent(notification_view())
  294. ->GetIndexOf(GetMessageLabel(notification_view())));
  295. std::unique_ptr<Notification> notification = CreateTestNotification();
  296. notification->set_title(std::u16string());
  297. notification_view()->UpdateWithNotification(*notification);
  298. EXPECT_EQ(nullptr, title_row());
  299. EXPECT_NE(nullptr, GetMessageLabel(notification_view()));
  300. EXPECT_EQ(0u, GetLeftContent(notification_view())
  301. ->GetIndexOf(GetMessageLabel(notification_view())));
  302. notification->set_title(u"title");
  303. notification_view()->UpdateWithNotification(*notification);
  304. EXPECT_NE(nullptr, title_row());
  305. EXPECT_NE(nullptr, GetMessageLabel(notification_view()));
  306. EXPECT_EQ(0u, GetLeftContent(notification_view())->GetIndexOf(title_row()));
  307. EXPECT_EQ(1u, GetLeftContent(notification_view())
  308. ->GetIndexOf(GetMessageLabel(notification_view())));
  309. }
  310. TEST_F(AshNotificationViewTest, CreateOrUpdateTitle) {
  311. EXPECT_NE(nullptr, title_row());
  312. EXPECT_NE(nullptr, title_view());
  313. EXPECT_NE(nullptr, GetTitleRowDivider(notification_view()));
  314. EXPECT_NE(nullptr, GetTimestampInCollapsedView(notification_view()));
  315. std::unique_ptr<Notification> notification = CreateTestNotification();
  316. // Every view should be null when title is empty.
  317. notification->set_title(std::u16string());
  318. notification_view()->UpdateWithNotification(*notification);
  319. EXPECT_EQ(nullptr, title_row());
  320. const std::u16string& expected_text = u"title";
  321. notification->set_title(expected_text);
  322. notification_view()->UpdateWithNotification(*notification);
  323. EXPECT_NE(nullptr, title_row());
  324. EXPECT_EQ(expected_text, title_view()->GetText());
  325. }
  326. TEST_F(AshNotificationViewTest, UpdatesTimestampOverTime) {
  327. auto notification = CreateTestNotification(/*has_image=*/true);
  328. notification_view()->UpdateWithNotification(*notification);
  329. notification_view()->SetExpanded(false);
  330. EXPECT_TRUE(GetTimestampInCollapsedView(notification_view())->GetVisible());
  331. UpdateTimestamp(base::Time::Now() + base::Hours(3) + base::Minutes(30));
  332. EXPECT_EQ(l10n_util::GetPluralStringFUTF16(
  333. IDS_MESSAGE_NOTIFICATION_DURATION_HOURS_SHORTEST_FUTURE, 3),
  334. GetTimestampInCollapsedView(notification_view())->GetText());
  335. AdvanceClock(base::Hours(3));
  336. EXPECT_EQ(l10n_util::GetPluralStringFUTF16(
  337. IDS_MESSAGE_NOTIFICATION_DURATION_MINUTES_SHORTEST_FUTURE, 30),
  338. GetTimestampInCollapsedView(notification_view())->GetText());
  339. AdvanceClock(base::Minutes(30));
  340. EXPECT_EQ(
  341. l10n_util::GetStringUTF16(IDS_MESSAGE_NOTIFICATION_NOW_STRING_SHORTEST),
  342. GetTimestampInCollapsedView(notification_view())->GetText());
  343. AdvanceClock(base::Days(2));
  344. EXPECT_EQ(l10n_util::GetPluralStringFUTF16(
  345. IDS_MESSAGE_NOTIFICATION_DURATION_DAYS_SHORTEST, 2),
  346. GetTimestampInCollapsedView(notification_view())->GetText());
  347. }
  348. TEST_F(AshNotificationViewTest, ExpandCollapseBehavior) {
  349. auto notification = CreateTestNotification(/*has_image=*/true);
  350. notification_view()->UpdateWithNotification(*notification);
  351. // Expected behavior in collapsed mode.
  352. notification_view()->SetExpanded(false);
  353. EXPECT_FALSE(GetHeaderRow(notification_view())->GetVisible());
  354. EXPECT_TRUE(GetTimestampInCollapsedView(notification_view())->GetVisible());
  355. EXPECT_TRUE(GetTitleRowDivider(notification_view())->GetVisible());
  356. EXPECT_TRUE(GetMessageLabel(notification_view())->GetVisible());
  357. EXPECT_FALSE(
  358. GetMessageLabelInExpandedState(notification_view())->GetVisible());
  359. // Expected behavior in expanded mode.
  360. notification_view()->SetExpanded(true);
  361. EXPECT_TRUE(GetHeaderRow(notification_view())->GetVisible());
  362. EXPECT_FALSE(GetTimestampInCollapsedView(notification_view())->GetVisible());
  363. EXPECT_FALSE(GetTitleRowDivider(notification_view())->GetVisible());
  364. EXPECT_FALSE(GetMessageLabel(notification_view())->GetVisible());
  365. EXPECT_TRUE(
  366. GetMessageLabelInExpandedState(notification_view())->GetVisible());
  367. }
  368. TEST_F(AshNotificationViewTest, ManuallyExpandedOrCollapsed) {
  369. // Test |manually_expanded_or_collapsed| being set when the toggle is done by
  370. // user interaction.
  371. EXPECT_FALSE(notification_view()->IsManuallyExpandedOrCollapsed());
  372. notification_view()->ToggleExpand();
  373. EXPECT_TRUE(notification_view()->IsManuallyExpandedOrCollapsed());
  374. }
  375. TEST_F(AshNotificationViewTest, GroupedNotificationStartsCollapsed) {
  376. auto notification = CreateTestNotification();
  377. notification_view()->UpdateWithNotification(*notification);
  378. MakeNotificationGroupParent(
  379. notification_view(),
  380. message_center_style::kMaxGroupedNotificationsInCollapsedState);
  381. // Grouped notification should start collapsed.
  382. EXPECT_FALSE(notification_view()->IsExpanded());
  383. EXPECT_TRUE(GetHeaderRow(notification_view())->GetVisible());
  384. EXPECT_TRUE(
  385. GetExpandButton(notification_view())->label_for_test()->GetVisible());
  386. }
  387. TEST_F(AshNotificationViewTest, GroupedNotificationCounterVisibility) {
  388. auto notification = CreateTestNotification();
  389. notification_view()->UpdateWithNotification(*notification);
  390. MakeNotificationGroupParent(
  391. notification_view(),
  392. message_center_style::kMaxGroupedNotificationsInCollapsedState + 1);
  393. EXPECT_TRUE(
  394. GetExpandButton(notification_view())->label_for_test()->GetVisible());
  395. auto* child_view = GetFirstGroupedChildNotificationView(notification_view());
  396. EXPECT_TRUE(GetCollapsedSummaryView(child_view)->GetVisible());
  397. EXPECT_FALSE(GetMainView(child_view)->GetVisible());
  398. }
  399. TEST_F(AshNotificationViewTest, GroupedNotificationExpandState) {
  400. auto notification = CreateTestNotification();
  401. notification_view()->UpdateWithNotification(*notification);
  402. MakeNotificationGroupParent(
  403. notification_view(),
  404. message_center_style::kMaxGroupedNotificationsInCollapsedState + 1);
  405. auto* child_view = GetFirstGroupedChildNotificationView(notification_view());
  406. EXPECT_TRUE(GetCollapsedSummaryView(child_view)->GetVisible());
  407. EXPECT_FALSE(GetMainView(child_view)->GetVisible());
  408. EXPECT_TRUE(GetTimestamp(notification_view())->GetVisible());
  409. // Expanding the parent notification should make the expand button counter and
  410. // timestamp invisible and the child notifications should now have the main
  411. // view visible instead of the summary.
  412. notification_view()->SetExpanded(true);
  413. EXPECT_FALSE(
  414. GetExpandButton(notification_view())->label_for_test()->GetVisible());
  415. EXPECT_FALSE(GetTimestamp(notification_view())->GetVisible());
  416. EXPECT_FALSE(GetCollapsedSummaryView(child_view)->GetVisible());
  417. EXPECT_TRUE(GetMainView(child_view)->GetVisible());
  418. }
  419. TEST_F(AshNotificationViewTest, GroupedNotificationChildIcon) {
  420. auto notification = CreateTestNotification();
  421. notification->set_icon(
  422. ui::ImageModel::FromImage(CreateTestImage(16, 16, SK_ColorBLUE)));
  423. notification->SetGroupChild();
  424. notification_view()->UpdateWithNotification(*notification.get());
  425. // Notification's icon should be used in child notification's app icon (we
  426. // check this by comparing the color of the app icon with the color of the
  427. // generated test image).
  428. EXPECT_EQ(color_utils::SkColorToRgbaString(SK_ColorBLUE),
  429. color_utils::SkColorToRgbaString(
  430. app_icon_view()->original_image().bitmap()->getColor(0, 0)));
  431. // This should not be changed after theme changed.
  432. notification_view()->OnThemeChanged();
  433. EXPECT_EQ(color_utils::SkColorToRgbaString(SK_ColorBLUE),
  434. color_utils::SkColorToRgbaString(
  435. app_icon_view()->original_image().bitmap()->getColor(0, 0)));
  436. // Reset the notification to be group parent at the end.
  437. notification->SetGroupParent();
  438. notification_view()->UpdateWithNotification(*notification.get());
  439. }
  440. TEST_F(AshNotificationViewTest,
  441. GroupedNotificationExpandCollapseStateVisibility) {
  442. auto notification = CreateTestNotification();
  443. notification_view()->UpdateWithNotification(*notification);
  444. MakeNotificationGroupParent(
  445. notification_view(),
  446. 4 * message_center_style::kMaxGroupedNotificationsInCollapsedState);
  447. // Only the first `kMaxGroupedNotificationsInCollapsedState` grouped
  448. // notifications should be visible in the collapsed state.
  449. int counter = 0;
  450. for (auto* child : GetChildNotifications(notification_view())) {
  451. if (counter <
  452. message_center_style::kMaxGroupedNotificationsInCollapsedState) {
  453. EXPECT_TRUE(child->GetVisible());
  454. } else {
  455. EXPECT_FALSE(child->GetVisible());
  456. }
  457. counter++;
  458. }
  459. // All grouped notifications should be visible once the parent is expanded.
  460. notification_view()->SetExpanded(true);
  461. for (auto* child : GetChildNotifications(notification_view())) {
  462. EXPECT_TRUE(child->GetVisible());
  463. }
  464. notification_view()->SetExpanded(false);
  465. // Going back to collapsed state only the first
  466. // `kMaxGroupedNotificationsInCollapsedState` grouped notifications should be
  467. // visible.
  468. counter = 0;
  469. for (auto* child : GetChildNotifications(notification_view())) {
  470. if (counter <
  471. message_center_style::kMaxGroupedNotificationsInCollapsedState) {
  472. EXPECT_TRUE(child->GetVisible());
  473. } else {
  474. EXPECT_FALSE(child->GetVisible());
  475. }
  476. counter++;
  477. }
  478. }
  479. TEST_F(AshNotificationViewTest, ExpandButtonVisibility) {
  480. // Expand button should be shown in any type of notification and hidden in
  481. // inline settings UI.
  482. auto notification1 = CreateTestNotification();
  483. notification_view()->UpdateWithNotification(*notification1);
  484. EXPECT_TRUE(GetExpandButton(notification_view())->GetVisible());
  485. auto notification2 = CreateTestNotification(/*has_image=*/true);
  486. notification_view()->UpdateWithNotification(*notification2);
  487. EXPECT_TRUE(GetExpandButton(notification_view())->GetVisible());
  488. ToggleInlineSettings(notification_view());
  489. // `content_row()` should be hidden, which also means expand button should be
  490. // hidden here.
  491. EXPECT_FALSE(GetExpandButton(notification_view())->GetVisible());
  492. // Toggle back.
  493. ToggleInlineSettings(notification_view());
  494. EXPECT_TRUE(content_row()->GetVisible());
  495. EXPECT_TRUE(GetExpandButton(notification_view())->GetVisible());
  496. }
  497. TEST_F(AshNotificationViewTest, WarningLevelInSummaryText) {
  498. auto notification = CreateTestNotification();
  499. notification_view()->UpdateWithNotification(*notification);
  500. // Notification with normal system warning level should have empty summary
  501. // text.
  502. EXPECT_EQ(
  503. std::u16string(),
  504. GetHeaderRow(notification_view())->summary_text_for_testing()->GetText());
  505. // Notification with warning/critical warning level should display a text in
  506. // summary text.
  507. notification->set_system_notification_warning_level(
  508. message_center::SystemNotificationWarningLevel::WARNING);
  509. notification_view()->UpdateWithNotification(*notification);
  510. EXPECT_EQ(
  511. l10n_util::GetStringUTF16(IDS_ASH_NOTIFICATION_WARNING_LABEL),
  512. GetHeaderRow(notification_view())->summary_text_for_testing()->GetText());
  513. notification->set_system_notification_warning_level(
  514. message_center::SystemNotificationWarningLevel::CRITICAL_WARNING);
  515. notification_view()->UpdateWithNotification(*notification);
  516. EXPECT_EQ(
  517. l10n_util::GetStringUTF16(IDS_ASH_NOTIFICATION_CRITICAL_WARNING_LABEL),
  518. GetHeaderRow(notification_view())->summary_text_for_testing()->GetText());
  519. }
  520. TEST_F(AshNotificationViewTest, InlineSettingsBlockAll) {
  521. auto notification = CreateTestNotification();
  522. notification_view()->UpdateWithNotification(*notification);
  523. ToggleInlineSettings(notification_view());
  524. EXPECT_TRUE(GetInlineSettingsRow(notification_view())->GetVisible());
  525. // Clicking the turn off button should disable notifications.
  526. views::test::ButtonTestApi test_api(turn_off_notifications_button());
  527. test_api.NotifyClick(ui::test::TestEvent());
  528. EXPECT_TRUE(delegate()->disable_notification_called());
  529. }
  530. TEST_F(AshNotificationViewTest, InlineSettingsCancel) {
  531. auto notification = CreateTestNotification();
  532. notification_view()->UpdateWithNotification(*notification);
  533. ToggleInlineSettings(notification_view());
  534. EXPECT_TRUE(GetInlineSettingsRow(notification_view())->GetVisible());
  535. // Clicking the cancel button should not disable notifications.
  536. views::test::ButtonTestApi test_api(inline_settings_cancel_button());
  537. test_api.NotifyClick(ui::test::TestEvent());
  538. EXPECT_FALSE(GetInlineSettingsRow(notification_view())->GetVisible());
  539. EXPECT_FALSE(delegate()->disable_notification_called());
  540. }
  541. TEST_F(AshNotificationViewTest, SnoozeButtonVisibility) {
  542. auto notification = CreateTestNotification();
  543. notification_view()->UpdateWithNotification(*notification);
  544. // Snooze button should be null if notification does not use it.
  545. EXPECT_EQ(snooze_button(), nullptr);
  546. notification =
  547. CreateTestNotification(/*has_image=*/false, /*show_snooze_button=*/true);
  548. notification_view()->UpdateWithNotification(*notification);
  549. // Snooze button should be visible if notification does use it.
  550. EXPECT_TRUE(snooze_button()->GetVisible());
  551. }
  552. TEST_F(AshNotificationViewTest, AppIconAndExpandButtonAlignment) {
  553. auto notification = CreateTestNotification();
  554. notification_view()->UpdateWithNotification(*notification);
  555. // Make sure that app icon and expand button is vertically aligned in
  556. // collapsed mode.
  557. notification_view()->SetExpanded(false);
  558. EXPECT_EQ(app_icon_view()->GetBoundsInScreen().y(),
  559. expand_button()->GetBoundsInScreen().y());
  560. // Make sure that app icon, expand button, and also header row is vertically
  561. // aligned in expanded mode.
  562. notification_view()->SetExpanded(true);
  563. EXPECT_EQ(app_icon_view()->GetBoundsInScreen().y(),
  564. expand_button()->GetBoundsInScreen().y());
  565. EXPECT_EQ(app_icon_view()->GetBoundsInScreen().y(),
  566. GetHeaderRow(notification_view())->GetBoundsInScreen().y());
  567. }
  568. TEST_F(AshNotificationViewTest, ExpandCollapseAnimationsRecordSmoothness) {
  569. // Enable animations.
  570. ui::ScopedAnimationDurationScaleMode duration(
  571. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  572. message_center::MessageCenter::Get()->RemoveAllNotifications(
  573. /*by_user=*/true, message_center::MessageCenter::RemoveType::ALL);
  574. auto notification =
  575. CreateTestNotification(/*has_image=*/true, /*show_snooze_button=*/true);
  576. GetPrimaryUnifiedSystemTray()->ShowBubble();
  577. auto* notification_view =
  578. GetNotificationViewFromMessageCenter(notification->id());
  579. // Use long message to show `message_label_in_expanded_state_`.
  580. notification->set_message(
  581. u"consectetur adipiscing elit, sed do eiusmod tempor incididunt ut "
  582. u"labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud "
  583. u"exercitation ullamco laboris nisi ut aliquip ex ea commodo "
  584. u"consequat.");
  585. message_center::MessageCenter::Get()->UpdateNotification(
  586. notification->id(), std::move(notification));
  587. EXPECT_TRUE(notification_view->IsExpanded());
  588. base::HistogramTester histograms_collapsed;
  589. notification_view->ToggleExpand();
  590. EXPECT_FALSE(notification_view->IsExpanded());
  591. // All the fade in animations of views in collapsed state should be performed
  592. // and recorded here.
  593. CheckSmoothnessRecorded(
  594. histograms_collapsed, GetTitleRowDivider(notification_view),
  595. "Ash.NotificationView.TitleRowDivider.FadeIn.AnimationSmoothness");
  596. CheckSmoothnessRecorded(
  597. histograms_collapsed, GetTimestampInCollapsedView(notification_view),
  598. "Ash.NotificationView.TimestampInTitle.FadeIn.AnimationSmoothness");
  599. CheckSmoothnessRecorded(
  600. histograms_collapsed, GetMessageLabel(notification_view),
  601. "Ash.NotificationView.MessageLabel.FadeIn.AnimationSmoothness");
  602. base::HistogramTester histograms_expanded;
  603. notification_view->ToggleExpand();
  604. EXPECT_TRUE(notification_view->IsExpanded());
  605. // All the fade in animations of views in expanded state should be performed
  606. // and recorded here.
  607. CheckSmoothnessRecorded(
  608. histograms_expanded, GetHeaderRow(notification_view),
  609. "Ash.NotificationView.HeaderRow.FadeIn.AnimationSmoothness");
  610. CheckSmoothnessRecorded(
  611. histograms_expanded, GetMessageLabelInExpandedState(notification_view),
  612. "Ash.NotificationView.ExpandedMessageLabel.FadeIn.AnimationSmoothness");
  613. CheckSmoothnessRecorded(
  614. histograms_expanded, GetImageContainerView(notification_view),
  615. "Ash.NotificationView.ImageContainerView.FadeIn.AnimationSmoothness");
  616. CheckSmoothnessRecorded(
  617. histograms_expanded, GetActionsRow(notification_view),
  618. "Ash.NotificationView.ActionsRow.FadeIn.AnimationSmoothness");
  619. }
  620. TEST_F(AshNotificationViewTest, ImageExpandCollapseAnimationsRecordSmoothness) {
  621. // Enable animations.
  622. ui::ScopedAnimationDurationScaleMode duration(
  623. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  624. message_center::MessageCenter::Get()->RemoveAllNotifications(
  625. /*by_user=*/true, message_center::MessageCenter::RemoveType::ALL);
  626. auto notification = CreateTestNotification(/*has_image=*/true,
  627. /*show_snooze_button=*/true);
  628. GetPrimaryUnifiedSystemTray()->ShowBubble();
  629. auto* notification_view =
  630. GetNotificationViewFromMessageCenter(notification->id());
  631. // When we use different images for icon view and image container view, we
  632. // fade out and scale down image container view when changing to collapsed
  633. // state. We fade in, scale and translate when changing to expanded state.
  634. EXPECT_TRUE(notification_view->IsExpanded());
  635. base::HistogramTester histograms;
  636. notification_view->ToggleExpand();
  637. EXPECT_FALSE(notification_view->IsExpanded());
  638. CheckSmoothnessRecorded(
  639. histograms, GetImageContainerView(notification_view),
  640. "Ash.NotificationView.ImageContainerView.FadeOut.AnimationSmoothness");
  641. CheckSmoothnessRecorded(histograms, GetImageContainerView(notification_view),
  642. "Ash.NotificationView.ImageContainerView."
  643. "ScaleDown.AnimationSmoothness");
  644. notification_view->ToggleExpand();
  645. EXPECT_TRUE(notification_view->IsExpanded());
  646. CheckSmoothnessRecorded(
  647. histograms, GetImageContainerView(notification_view),
  648. "Ash.NotificationView.ImageContainerView.FadeIn.AnimationSmoothness");
  649. CheckSmoothnessRecorded(histograms, GetImageContainerView(notification_view),
  650. "Ash.NotificationView.ImageContainerView."
  651. "ScaleAndTranslate.AnimationSmoothness");
  652. // Clear icon so that icon view and image container view use the same image.
  653. notification->set_icon(ui::ImageModel());
  654. message_center::MessageCenter::Get()->UpdateNotification(
  655. notification->id(), std::move(notification));
  656. EXPECT_TRUE(notification_view->IsExpanded());
  657. base::HistogramTester histograms_collapsed;
  658. notification_view->ToggleExpand();
  659. EXPECT_FALSE(notification_view->IsExpanded());
  660. // We scale and translate icon view to collapsed state.
  661. CheckSmoothnessRecorded(
  662. histograms_collapsed, GetIconView(notification_view),
  663. "Ash.NotificationView.IconView.ScaleAndTranslate.AnimationSmoothness");
  664. base::HistogramTester histograms_expanded;
  665. notification_view->ToggleExpand();
  666. EXPECT_TRUE(notification_view->IsExpanded());
  667. // We scale and translate image container view to expanded state.
  668. CheckSmoothnessRecorded(histograms_expanded,
  669. GetImageContainerView(notification_view),
  670. "Ash.NotificationView.ImageContainerView."
  671. "ScaleAndTranslate.AnimationSmoothness");
  672. }
  673. TEST_F(AshNotificationViewTest, GroupExpandCollapseAnimationsRecordSmoothness) {
  674. base::HistogramTester histograms;
  675. // Enable animations.
  676. ui::ScopedAnimationDurationScaleMode duration(
  677. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  678. message_center::MessageCenter::Get()->RemoveAllNotifications(
  679. /*by_user=*/true, message_center::MessageCenter::RemoveType::ALL);
  680. auto notification = CreateTestNotification();
  681. GetPrimaryUnifiedSystemTray()->ShowBubble();
  682. auto* notification_view =
  683. GetNotificationViewFromMessageCenter(notification->id());
  684. MakeNotificationGroupParent(
  685. notification_view,
  686. message_center_style::kMaxGroupedNotificationsInCollapsedState);
  687. EXPECT_FALSE(notification_view->IsExpanded());
  688. base::HistogramTester histograms_expanded;
  689. notification_view->ToggleExpand();
  690. EXPECT_TRUE(notification_view->IsExpanded());
  691. // All the animations of views in expanded state should be performed and
  692. // recorded here.
  693. CheckSmoothnessRecorded(
  694. histograms_expanded,
  695. GetCollapsedSummaryView(
  696. GetFirstGroupedChildNotificationView(notification_view)),
  697. "Ash.NotificationView.CollapsedSummaryView.FadeOut.AnimationSmoothness");
  698. CheckSmoothnessRecorded(
  699. histograms_expanded,
  700. GetMainView(GetFirstGroupedChildNotificationView(notification_view)),
  701. "Ash.NotificationView.MainView.FadeIn.AnimationSmoothness");
  702. CheckSmoothnessRecorded(
  703. histograms_expanded, GetExpandButton(notification_view)->label_for_test(),
  704. "Ash.NotificationView.ExpandButtonLabel.FadeOut.AnimationSmoothness");
  705. CheckSmoothnessRecorded(
  706. histograms_expanded, GetExpandButton(notification_view),
  707. "Ash.NotificationView.ExpandButton.BoundsChange.AnimationSmoothness");
  708. base::HistogramTester histograms_collapsed;
  709. notification_view->ToggleExpand();
  710. EXPECT_FALSE(notification_view->IsExpanded());
  711. // All the animations of views in collapsed state should be performed and
  712. // recorded here.
  713. CheckSmoothnessRecorded(
  714. histograms_collapsed,
  715. GetMainView(GetFirstGroupedChildNotificationView(notification_view)),
  716. "Ash.NotificationView.MainView.FadeOut.AnimationSmoothness");
  717. CheckSmoothnessRecorded(
  718. histograms_collapsed,
  719. GetCollapsedSummaryView(
  720. GetFirstGroupedChildNotificationView(notification_view)),
  721. "Ash.NotificationView.CollapsedSummaryView.FadeIn.AnimationSmoothness");
  722. CheckSmoothnessRecorded(
  723. histograms_collapsed,
  724. GetExpandButton(notification_view)->label_for_test(),
  725. "Ash.NotificationView.ExpandButtonLabel.FadeIn.AnimationSmoothness");
  726. CheckSmoothnessRecorded(
  727. histograms_collapsed,
  728. GetExpandButton(notification_view)->label_for_test(),
  729. "Ash.NotificationView.ExpandButton.BoundsChange.AnimationSmoothness");
  730. }
  731. TEST_F(AshNotificationViewTest, SingleToGroupAnimationsRecordSmoothness) {
  732. base::HistogramTester histograms;
  733. // Enable animations.
  734. ui::ScopedAnimationDurationScaleMode duration(
  735. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  736. message_center::MessageCenter::Get()->RemoveAllNotifications(
  737. /*by_user=*/true, message_center::MessageCenter::RemoveType::ALL);
  738. GetPrimaryUnifiedSystemTray()->ShowBubble();
  739. auto notification1 = CreateTestNotificationInAGroup();
  740. auto* notification_view =
  741. GetNotificationViewFromMessageCenter(notification1->id());
  742. auto notification2 = CreateTestNotificationInAGroup();
  743. CheckSmoothnessRecorded(
  744. histograms, GetLeftContent(notification_view),
  745. "Ash.NotificationView.ConvertSingleToGroup.FadeOut.AnimationSmoothness");
  746. CheckSmoothnessRecorded(
  747. histograms, GetGroupedNotificationsContainer(notification_view),
  748. "Ash.NotificationView.ConvertSingleToGroup.FadeIn.AnimationSmoothness");
  749. CheckSmoothnessRecorded(
  750. histograms, GetExpandButton(notification_view)->label_for_test(),
  751. "Ash.NotificationView.ExpandButton.ConvertSingleToGroup."
  752. "FadeIn.AnimationSmoothness");
  753. CheckSmoothnessRecorded(
  754. histograms, GetExpandButton(notification_view),
  755. "Ash.NotificationView.ExpandButton.ConvertSingleToGroup."
  756. "BoundsChange.AnimationSmoothness");
  757. }
  758. TEST_F(AshNotificationViewTest, InlineReplyAnimationsRecordSmoothness) {
  759. base::HistogramTester histograms;
  760. // Enable animations.
  761. ui::ScopedAnimationDurationScaleMode duration(
  762. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  763. message_center::MessageCenter::Get()->RemoveAllNotifications(
  764. /*by_user=*/true, message_center::MessageCenter::RemoveType::ALL);
  765. auto notification =
  766. CreateTestNotification(/*has_image=*/true, /*show_snooze_button=*/true);
  767. GetPrimaryUnifiedSystemTray()->ShowBubble();
  768. auto* notification_view =
  769. GetNotificationViewFromMessageCenter(notification->id());
  770. message_center::ButtonInfo info(u"Test button.");
  771. std::vector<message_center::ButtonInfo> buttons =
  772. std::vector<message_center::ButtonInfo>(2, info);
  773. buttons[1].placeholder = std::u16string();
  774. notification->set_buttons(buttons);
  775. message_center::MessageCenter::Get()->UpdateNotification(
  776. notification->id(), std::move(notification));
  777. // Clicking inline reply button and check animations.
  778. EXPECT_TRUE(notification_view->IsExpanded());
  779. views::test::ButtonTestApi test_api(GetActionButtons(notification_view)[1]);
  780. test_api.NotifyClick(ui::test::TestEvent());
  781. CheckSmoothnessRecorded(
  782. histograms, GetActionButtonsRow(notification_view),
  783. "Ash.NotificationView.ActionButtonsRow.FadeOut.AnimationSmoothness");
  784. CheckSmoothnessRecorded(
  785. histograms, GetInlineReply(notification_view),
  786. "Ash.NotificationView.InlineReply.FadeIn.AnimationSmoothness");
  787. // Toggle expand to close inline reply. It should fade out.
  788. notification_view->ToggleExpand();
  789. CheckSmoothnessRecorded(
  790. histograms, GetInlineReply(notification_view),
  791. "Ash.NotificationView.InlineReply.FadeOut.AnimationSmoothness");
  792. }
  793. TEST_F(AshNotificationViewTest, InlineSettingsAnimationsRecordSmoothness) {
  794. base::HistogramTester histograms;
  795. // Enable animations.
  796. ui::ScopedAnimationDurationScaleMode duration(
  797. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  798. message_center::MessageCenter::Get()->RemoveAllNotifications(
  799. /*by_user=*/true, message_center::MessageCenter::RemoveType::ALL);
  800. auto notification =
  801. CreateTestNotification(/*has_image=*/true, /*show_snooze_button=*/true);
  802. GetPrimaryUnifiedSystemTray()->ShowBubble();
  803. auto* notification_view =
  804. GetNotificationViewFromMessageCenter(notification->id());
  805. // Set to collapsed state so that header row will fade out when coming back to
  806. // main notification view.
  807. notification_view->SetExpanded(false);
  808. // Toggle inline settings to access inline settings view.
  809. ToggleInlineSettings(notification_view);
  810. // Check fade out views.
  811. CheckSmoothnessRecorded(
  812. histograms, GetLeftContent(notification_view),
  813. "Ash.NotificationView.LeftContent.FadeOut.AnimationSmoothness");
  814. CheckSmoothnessRecorded(
  815. histograms, GetExpandButton(notification_view),
  816. "Ash.NotificationView.ExpandButton.FadeOut.AnimationSmoothness");
  817. CheckSmoothnessRecorded(
  818. histograms, GetIconView(notification_view),
  819. "Ash.NotificationView.IconView.FadeOut.AnimationSmoothness");
  820. // Check fade in main right view.
  821. CheckSmoothnessRecorded(
  822. histograms, GetMainRightView(notification_view),
  823. "Ash.NotificationView.MainRightView.FadeIn.AnimationSmoothness");
  824. // Toggle inline settings again to come back.
  825. ToggleInlineSettings(notification_view);
  826. CheckSmoothnessRecorded(
  827. histograms, GetInlineSettingsRow(notification_view),
  828. "Ash.NotificationView.InlineSettingsRow.FadeOut.AnimationSmoothness");
  829. CheckSmoothnessRecorded(
  830. histograms, GetMainRightView(notification_view),
  831. "Ash.NotificationView.MainRightView.FadeIn.AnimationSmoothness",
  832. /*data_point_count=*/2);
  833. }
  834. TEST_F(AshNotificationViewTest,
  835. GroupNotificationSlideOutAnimationRecordSmoothness) {
  836. base::HistogramTester histograms;
  837. message_center::MessageCenter::Get()->RemoveAllNotifications(
  838. /*by_user=*/true, message_center::MessageCenter::RemoveType::ALL);
  839. auto notification = CreateTestNotification();
  840. GetPrimaryUnifiedSystemTray()->ShowBubble();
  841. auto* notification_view =
  842. GetNotificationViewFromMessageCenter(notification->id());
  843. MakeNotificationGroupParent(
  844. notification_view,
  845. 2 * message_center_style::kMaxGroupedNotificationsInCollapsedState);
  846. notification_view->ToggleExpand();
  847. EXPECT_TRUE(notification_view->IsExpanded());
  848. // Enable animations.
  849. ui::ScopedAnimationDurationScaleMode duration(
  850. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  851. auto* child_view = GetFirstGroupedChildNotificationView(notification_view);
  852. notification_view->RemoveGroupNotification(child_view->notification_id());
  853. base::HistogramTester histogram;
  854. // The child view should slide out before being deleted and the smoothness
  855. // should be recorded.
  856. CheckSmoothnessRecorded(
  857. histograms, child_view,
  858. "Ash.Notification.GroupNotification.SlideOut.AnimationSmoothness");
  859. }
  860. TEST_F(AshNotificationViewTest, RecordExpandButtonClickAction) {
  861. base::HistogramTester histograms;
  862. auto notification = CreateTestNotification();
  863. notification_view()->UpdateWithNotification(*notification);
  864. notification_view()->SetExpanded(false);
  865. notification_view()->ToggleExpand();
  866. histograms.ExpectBucketCount(
  867. "Ash.NotificationView.ExpandButton.ClickAction",
  868. metrics_utils::ExpandButtonClickAction::EXPAND_INDIVIDUAL, 1);
  869. notification_view()->ToggleExpand();
  870. histograms.ExpectBucketCount(
  871. "Ash.NotificationView.ExpandButton.ClickAction",
  872. metrics_utils::ExpandButtonClickAction::COLLAPSE_INDIVIDUAL, 1);
  873. notification->SetGroupParent();
  874. notification_view()->UpdateWithNotification(*notification);
  875. notification_view()->SetExpanded(false);
  876. notification_view()->ToggleExpand();
  877. histograms.ExpectBucketCount(
  878. "Ash.NotificationView.ExpandButton.ClickAction",
  879. metrics_utils::ExpandButtonClickAction::EXPAND_GROUP, 1);
  880. notification_view()->ToggleExpand();
  881. histograms.ExpectBucketCount(
  882. "Ash.NotificationView.ExpandButton.ClickAction",
  883. metrics_utils::ExpandButtonClickAction::COLLAPSE_GROUP, 1);
  884. }
  885. TEST_F(AshNotificationViewTest, OnThemeChangedWithoutMessageLabel) {
  886. EXPECT_NE(nullptr, GetMessageLabel(notification_view()));
  887. std::unique_ptr<Notification> notification = CreateTestNotification(
  888. /*has_image=*/false, /*show_snooze_button=*/false, /*has_message=*/true,
  889. message_center::NOTIFICATION_TYPE_PROGRESS);
  890. notification_view()->UpdateWithNotification(*notification);
  891. EXPECT_EQ(nullptr, GetMessageLabel(notification_view()));
  892. notification = CreateTestNotification(
  893. /*has_image=*/false, /*show_snooze_button=*/false, /*has_message=*/false);
  894. notification_view()->UpdateWithNotification(*notification);
  895. EXPECT_EQ(nullptr, GetMessageLabel(notification_view()));
  896. // Verify OnThemeChanged doesn't break with a null message_label()
  897. notification_view()->OnThemeChanged();
  898. EXPECT_EQ(nullptr, GetMessageLabel(notification_view()));
  899. }
  900. TEST_F(AshNotificationViewTest, DuplicateGroupChildRemovalWithAnimation) {
  901. message_center::MessageCenter::Get()->RemoveAllNotifications(
  902. /*by_user=*/true, message_center::MessageCenter::RemoveType::ALL);
  903. auto notification = CreateTestNotification();
  904. GetPrimaryUnifiedSystemTray()->ShowBubble();
  905. auto* notification_view =
  906. GetNotificationViewFromMessageCenter(notification->id());
  907. MakeNotificationGroupParent(
  908. notification_view,
  909. 2 * message_center_style::kMaxGroupedNotificationsInCollapsedState);
  910. notification_view->ToggleExpand();
  911. EXPECT_TRUE(notification_view->IsExpanded());
  912. // Enable animations.
  913. ui::ScopedAnimationDurationScaleMode duration(
  914. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  915. // Ensure a duplicate call to RemoveGroupNotification does not cause a crash.
  916. auto* child_view = GetFirstGroupedChildNotificationView(notification_view);
  917. notification_view->RemoveGroupNotification(child_view->notification_id());
  918. notification_view->RemoveGroupNotification(child_view->notification_id());
  919. }
  920. } // namespace ash