unified_message_center_view_unittest.cc 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921
  1. // Copyright 2018 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/unified_message_center_view.h"
  5. #include "ash/constants/ash_features.h"
  6. #include "ash/constants/ash_pref_names.h"
  7. #include "ash/session/session_controller_impl.h"
  8. #include "ash/shell.h"
  9. #include "ash/system/message_center/ash_message_center_lock_screen_controller.h"
  10. #include "ash/system/message_center/message_center_constants.h"
  11. #include "ash/system/message_center/message_center_scroll_bar.h"
  12. #include "ash/system/message_center/stacked_notification_bar.h"
  13. #include "ash/system/tray/tray_constants.h"
  14. #include "ash/system/unified/unified_system_tray_controller.h"
  15. #include "ash/system/unified/unified_system_tray_model.h"
  16. #include "ash/test/ash_test_base.h"
  17. #include "base/memory/scoped_refptr.h"
  18. #include "base/run_loop.h"
  19. #include "base/strings/string_number_conversions.h"
  20. #include "base/strings/utf_string_conversions.h"
  21. #include "base/test/scoped_feature_list.h"
  22. #include "chromeos/constants/chromeos_features.h"
  23. #include "components/prefs/pref_service.h"
  24. #include "ui/compositor/layer.h"
  25. #include "ui/compositor/layer_animator.h"
  26. #include "ui/compositor/scoped_animation_duration_scale_mode.h"
  27. #include "ui/message_center/message_center.h"
  28. #include "ui/message_center/views/message_view.h"
  29. #include "ui/views/controls/scroll_view.h"
  30. #include "ui/views/widget/widget.h"
  31. using message_center::MessageCenter;
  32. using message_center::MessageView;
  33. using message_center::Notification;
  34. namespace ash {
  35. namespace {
  36. constexpr int kDefaultMaxHeight = 500;
  37. class TestUnifiedMessageCenterView : public UnifiedMessageCenterView {
  38. public:
  39. explicit TestUnifiedMessageCenterView(UnifiedSystemTrayModel* model)
  40. : UnifiedMessageCenterView(nullptr /*parent*/,
  41. model,
  42. nullptr /*bubble*/) {}
  43. TestUnifiedMessageCenterView(const TestUnifiedMessageCenterView&) = delete;
  44. TestUnifiedMessageCenterView& operator=(const TestUnifiedMessageCenterView&) =
  45. delete;
  46. ~TestUnifiedMessageCenterView() override = default;
  47. };
  48. } // namespace
  49. class UnifiedMessageCenterViewTest : public AshTestBase,
  50. public views::ViewObserver,
  51. public testing::WithParamInterface<bool> {
  52. public:
  53. UnifiedMessageCenterViewTest() = default;
  54. UnifiedMessageCenterViewTest(const UnifiedMessageCenterViewTest&) = delete;
  55. UnifiedMessageCenterViewTest& operator=(const UnifiedMessageCenterViewTest&) =
  56. delete;
  57. ~UnifiedMessageCenterViewTest() override = default;
  58. // AshTestBase:
  59. void SetUp() override {
  60. scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
  61. if (IsNotificationsRefreshEnabled()) {
  62. scoped_feature_list_->InitWithFeatures(
  63. /*enabled_features=*/{features::kNotificationsRefresh,
  64. chromeos::features::kDarkLightMode},
  65. /*disabled_features=*/{});
  66. } else {
  67. scoped_feature_list_->InitWithFeatures(
  68. /*enabled_features=*/{},
  69. /*disabled_features=*/{features::kNotificationsRefresh,
  70. chromeos::features::kDarkLightMode});
  71. }
  72. AshTestBase::SetUp();
  73. model_ = base::MakeRefCounted<UnifiedSystemTrayModel>(nullptr);
  74. }
  75. bool IsNotificationsRefreshEnabled() const { return GetParam(); }
  76. void TearDown() override {
  77. base::RunLoop().RunUntilIdle();
  78. message_center_view_.reset();
  79. model_.reset();
  80. AshTestBase::TearDown();
  81. }
  82. // views::ViewObserver:
  83. void OnViewPreferredSizeChanged(views::View* view) override {
  84. if (view->GetPreferredSize() == view->size())
  85. return;
  86. view->SetBoundsRect(view->GetVisible() ? gfx::Rect(view->GetPreferredSize())
  87. : gfx::Rect());
  88. view->Layout();
  89. ++size_changed_count_;
  90. }
  91. protected:
  92. std::string AddNotification(bool pinned) {
  93. std::string id = base::NumberToString(id_++);
  94. message_center::RichNotificationData data;
  95. data.pinned = pinned;
  96. MessageCenter::Get()->AddNotification(std::make_unique<Notification>(
  97. message_center::NOTIFICATION_TYPE_SIMPLE, id, u"test title",
  98. u"test message", ui::ImageModel(),
  99. std::u16string() /* display_source */, GURL(),
  100. message_center::NotifierId(), data,
  101. new message_center::NotificationDelegate()));
  102. return id;
  103. }
  104. // Adds more than enough notifications to make the message center scrollable.
  105. std::vector<std::string> AddManyNotifications() {
  106. std::vector<std::string> ids;
  107. for (int i = 0; i < 10; ++i)
  108. ids.push_back(AddNotification(false));
  109. return ids;
  110. }
  111. std::unique_ptr<TestUnifiedMessageCenterView> CreateMessageCenterViewImpl(
  112. int max_height) {
  113. auto message_center_view =
  114. std::make_unique<TestUnifiedMessageCenterView>(model_.get());
  115. message_center_view->Init();
  116. message_center_view->AddObserver(this);
  117. message_center_view->SetMaxHeight(max_height);
  118. message_center_view->SetAvailableHeight(max_height);
  119. OnViewPreferredSizeChanged(message_center_view.get());
  120. size_changed_count_ = 0;
  121. return message_center_view;
  122. }
  123. virtual void CreateMessageCenterView(int max_height = kDefaultMaxHeight) {
  124. message_center_view_ = CreateMessageCenterViewImpl(max_height);
  125. }
  126. void AnimateMessageListToValue(float value) {
  127. GetMessageListView()->animation_->SetCurrentValue(value);
  128. GetMessageListView()->AnimationProgressed(
  129. GetMessageListView()->animation_.get());
  130. }
  131. void AnimateMessageListToMiddle() { AnimateMessageListToValue(0.5); }
  132. void AnimateMessageListToEnd() {
  133. FinishMessageListSlideOutAnimations();
  134. GetMessageListView()->animation_->End();
  135. }
  136. void AnimateMessageListUntilIdle() {
  137. while (GetMessageListView()->animation_->is_animating()) {
  138. GetMessageListView()->animation_->End();
  139. }
  140. }
  141. void FinishMessageListSlideOutAnimations() { base::RunLoop().RunUntilIdle(); }
  142. gfx::Rect GetMessageViewVisibleBounds(size_t index) {
  143. gfx::Rect bounds = GetMessageListView()->children()[index]->bounds();
  144. bounds -= GetScroller()->GetVisibleRect().OffsetFromOrigin();
  145. bounds += GetScroller()->bounds().OffsetFromOrigin();
  146. return bounds;
  147. }
  148. UnifiedMessageListView* GetMessageListView() {
  149. return message_center_view()->message_list_view_;
  150. }
  151. gfx::LinearAnimation* GetMessageCenterAnimation() {
  152. return message_center_view()->animation_.get();
  153. }
  154. views::ScrollView* GetScroller() { return message_center_view()->scroller_; }
  155. views::ScrollBar* GetScrollBar() {
  156. return message_center_view()->scroll_bar_;
  157. }
  158. views::View* GetScrollerContents() {
  159. return message_center_view()->scroller_->contents();
  160. }
  161. StackedNotificationBar* GetNotificationBar() {
  162. return message_center_view()->notification_bar_;
  163. }
  164. views::View* GetNotificationBarIconsContainer() {
  165. return message_center_view()
  166. ->notification_bar_->notification_icons_container_;
  167. }
  168. views::View* GetNotificationBarLabel() {
  169. return message_center_view()->notification_bar_->count_label_;
  170. }
  171. views::View* GetNotificationBarClearAllButton() {
  172. return message_center_view()->notification_bar_->clear_all_button_;
  173. }
  174. views::View* GetNotificationBarExpandAllButton() {
  175. return message_center_view()->notification_bar_->expand_all_button_;
  176. }
  177. message_center::MessageView* ToggleFocusToMessageView(size_t index,
  178. bool reverse) {
  179. auto* focus_manager = message_center_view()->GetFocusManager();
  180. if (!focus_manager)
  181. return nullptr;
  182. message_center::MessageView* focused_message_view = nullptr;
  183. const size_t max_focus_toggles =
  184. GetMessageListView()->children().size() * 5;
  185. for (size_t i = 0; i < max_focus_toggles; ++i) {
  186. focus_manager->AdvanceFocus(reverse);
  187. auto* focused_view = focus_manager->GetFocusedView();
  188. // The MessageView is wrapped in container view in the MessageList.
  189. if (focused_view->parent() == GetMessageListView()->children()[index]) {
  190. focused_message_view =
  191. static_cast<message_center::MessageView*>(focused_view);
  192. break;
  193. }
  194. }
  195. return focused_message_view;
  196. }
  197. void RelayoutMessageCenterViewForTest() {
  198. // Outside of tests, any changes to bubble's size as well as scrolling
  199. // through notification list will trigger TrayBubbleView's BoxLayout to
  200. // relayout, and then this view will relayout. In test, we don't have
  201. // TrayBubbleView as the parent, so we need to explicitly call Layout()
  202. // in some circumstances.
  203. message_center_view_->Layout();
  204. }
  205. virtual TestUnifiedMessageCenterView* message_center_view() {
  206. return message_center_view_.get();
  207. }
  208. int size_changed_count() const { return size_changed_count_; }
  209. UnifiedSystemTrayModel* model() { return model_.get(); }
  210. private:
  211. int id_ = 0;
  212. int size_changed_count_ = 0;
  213. scoped_refptr<UnifiedSystemTrayModel> model_;
  214. std::unique_ptr<TestUnifiedMessageCenterView> message_center_view_;
  215. std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
  216. };
  217. class UnifiedMessageCenterViewInWidgetTest
  218. : public UnifiedMessageCenterViewTest {
  219. public:
  220. UnifiedMessageCenterViewInWidgetTest() = default;
  221. UnifiedMessageCenterViewInWidgetTest(
  222. const UnifiedMessageCenterViewInWidgetTest&) = delete;
  223. UnifiedMessageCenterViewInWidgetTest& operator=(
  224. const UnifiedMessageCenterViewInWidgetTest&) = delete;
  225. ~UnifiedMessageCenterViewInWidgetTest() override = default;
  226. void TearDown() override {
  227. widget_.reset();
  228. UnifiedMessageCenterViewTest::TearDown();
  229. }
  230. protected:
  231. void CreateMessageCenterView(int max_height = kDefaultMaxHeight) override {
  232. widget_ = CreateTestWidget();
  233. message_center_ = widget_->GetRootView()->AddChildView(
  234. CreateMessageCenterViewImpl(max_height));
  235. }
  236. TestUnifiedMessageCenterView* message_center_view() override {
  237. return message_center_;
  238. }
  239. views::Widget* widget() { return widget_.get(); }
  240. private:
  241. std::unique_ptr<views::Widget> widget_;
  242. TestUnifiedMessageCenterView* message_center_ = nullptr;
  243. };
  244. INSTANTIATE_TEST_SUITE_P(All,
  245. UnifiedMessageCenterViewTest,
  246. testing::Bool() /* IsNotificationsRefreshEnabled() */);
  247. // Flaky: https://crbug.com/1293165
  248. TEST_P(UnifiedMessageCenterViewTest, DISABLED_AddAndRemoveNotification) {
  249. CreateMessageCenterView();
  250. EXPECT_FALSE(message_center_view()->GetVisible());
  251. auto id0 = AddNotification(false /* pinned */);
  252. EXPECT_TRUE(message_center_view()->GetVisible());
  253. // The notification first slides out of the list.
  254. MessageCenter::Get()->RemoveNotification(id0, true /* by_user */);
  255. AnimateMessageListToEnd();
  256. // After all the last notifiation slides out, the message center and list
  257. // should collapse.
  258. auto* collapse_animation = GetMessageCenterAnimation();
  259. collapse_animation->SetCurrentValue(0.5);
  260. message_center_view()->AnimationProgressed(collapse_animation);
  261. EXPECT_TRUE(message_center_view()->GetVisible());
  262. // The message center is now hidden after all animations complete.
  263. collapse_animation->End();
  264. AnimateMessageListToEnd();
  265. EXPECT_FALSE(message_center_view()->GetVisible());
  266. }
  267. TEST_P(UnifiedMessageCenterViewTest, RemoveNotificationAtTail) {
  268. // No special scroll behavior with the Notifications Refresh anymore.
  269. if (IsNotificationsRefreshEnabled())
  270. return;
  271. // Show message center with multiple notifications.
  272. AddManyNotifications();
  273. CreateMessageCenterView();
  274. EXPECT_TRUE(message_center_view()->GetVisible());
  275. // The message center should autoscroll to the bottom of the list after adding
  276. // a new notification.
  277. auto id_to_remove = AddNotification(false /* pinned */);
  278. RelayoutMessageCenterViewForTest();
  279. int scroll_position = GetScroller()->GetVisibleRect().y();
  280. EXPECT_EQ(GetMessageListView()->height() - GetScroller()->height(),
  281. scroll_position);
  282. // Get the height of last notification and then remove it.
  283. int removed_notification_height =
  284. GetMessageViewVisibleBounds(GetMessageListView()->children().size() - 1)
  285. .height();
  286. MessageCenter::Get()->RemoveNotification(id_to_remove, true /* by_user */);
  287. scroll_position = GetScroller()->GetVisibleRect().y();
  288. // The scroll position should be reduced by the height of the removed
  289. // notification after collapsing.
  290. AnimateMessageListToEnd();
  291. RelayoutMessageCenterViewForTest();
  292. EXPECT_EQ(scroll_position - removed_notification_height -
  293. kUnifiedNotificationSeparatorThickness,
  294. GetScroller()->GetVisibleRect().y());
  295. // Check that the list is still scrolled to the bottom.
  296. EXPECT_EQ(GetMessageListView()->height() - GetScroller()->height(),
  297. GetScroller()->GetVisibleRect().y());
  298. }
  299. TEST_P(UnifiedMessageCenterViewTest, ContentsRelayout) {
  300. std::vector<std::string> ids = AddManyNotifications();
  301. CreateMessageCenterView();
  302. EXPECT_TRUE(message_center_view()->GetVisible());
  303. // MessageCenterView is maxed out.
  304. EXPECT_GT(GetMessageListView()->bounds().height(),
  305. message_center_view()->bounds().height());
  306. const int previous_contents_height = GetScrollerContents()->height();
  307. const int previous_list_height = GetMessageListView()->height();
  308. MessageCenter::Get()->RemoveNotification(ids.back(), true /* by_user */);
  309. AnimateMessageListToEnd();
  310. RelayoutMessageCenterViewForTest();
  311. EXPECT_TRUE(message_center_view()->GetVisible());
  312. EXPECT_GT(previous_contents_height, GetScrollerContents()->height());
  313. EXPECT_GT(previous_list_height, GetMessageListView()->height());
  314. }
  315. TEST_P(UnifiedMessageCenterViewTest, InsufficientHeight) {
  316. CreateMessageCenterView();
  317. AddNotification(false /* pinned */);
  318. EXPECT_TRUE(message_center_view()->GetVisible());
  319. message_center_view()->SetAvailableHeight(kUnifiedNotificationMinimumHeight -
  320. 1);
  321. EXPECT_FALSE(message_center_view()->GetVisible());
  322. message_center_view()->SetAvailableHeight(kUnifiedNotificationMinimumHeight);
  323. EXPECT_TRUE(message_center_view()->GetVisible());
  324. }
  325. TEST_P(UnifiedMessageCenterViewTest, NotVisibleWhenLocked) {
  326. // Disable the lock screen notification if the feature is enable.
  327. PrefService* user_prefs =
  328. Shell::Get()->session_controller()->GetLastActiveUserPrefService();
  329. user_prefs->SetString(prefs::kMessageCenterLockScreenMode,
  330. prefs::kMessageCenterLockScreenModeHide);
  331. ASSERT_FALSE(AshMessageCenterLockScreenController::IsEnabled());
  332. AddNotification(false /* pinned */);
  333. AddNotification(false /* pinned */);
  334. BlockUserSession(BLOCKED_BY_LOCK_SCREEN);
  335. CreateMessageCenterView();
  336. EXPECT_FALSE(message_center_view()->GetVisible());
  337. }
  338. TEST_P(UnifiedMessageCenterViewTest, VisibleWhenLocked) {
  339. // This test is only valid if the lock screen feature is enabled.
  340. // TODO(yoshiki): Clean up after the feature is launched crbug.com/913764.
  341. if (!features::IsLockScreenNotificationsEnabled())
  342. return;
  343. // Enables the lock screen notification if the feature is disabled.
  344. PrefService* user_prefs =
  345. Shell::Get()->session_controller()->GetLastActiveUserPrefService();
  346. user_prefs->SetString(prefs::kMessageCenterLockScreenMode,
  347. prefs::kMessageCenterLockScreenModeShow);
  348. ASSERT_TRUE(AshMessageCenterLockScreenController::IsEnabled());
  349. AddNotification(false /* pinned */);
  350. AddNotification(false /* pinned */);
  351. BlockUserSession(BLOCKED_BY_LOCK_SCREEN);
  352. CreateMessageCenterView();
  353. EXPECT_TRUE(message_center_view()->GetVisible());
  354. }
  355. TEST_P(UnifiedMessageCenterViewTest, ClearAllPressed) {
  356. AddNotification(false /* pinned */);
  357. AddNotification(false /* pinned */);
  358. CreateMessageCenterView();
  359. EXPECT_TRUE(message_center_view()->GetVisible());
  360. EXPECT_TRUE(GetNotificationBar()->GetVisible());
  361. // When Clear All button is pressed, all notifications are removed and the
  362. // view becomes invisible.
  363. message_center_view()->ClearAllNotifications();
  364. AnimateMessageListUntilIdle();
  365. EXPECT_FALSE(message_center_view()->GetVisible());
  366. }
  367. TEST_P(UnifiedMessageCenterViewTest, InitialPosition) {
  368. AddNotification(false /* pinned */);
  369. AddNotification(false /* pinned */);
  370. CreateMessageCenterView();
  371. EXPECT_TRUE(message_center_view()->GetVisible());
  372. // MessageCenterView is not maxed out.
  373. EXPECT_LT(GetMessageListView()->bounds().height(),
  374. message_center_view()->bounds().height());
  375. }
  376. TEST_P(UnifiedMessageCenterViewTest, InitialPositionMaxOut) {
  377. AddManyNotifications();
  378. CreateMessageCenterView();
  379. EXPECT_TRUE(message_center_view()->GetVisible());
  380. // MessageCenterView is maxed out.
  381. EXPECT_GT(GetMessageListView()->bounds().height(),
  382. message_center_view()->bounds().height());
  383. }
  384. TEST_P(UnifiedMessageCenterViewTest, InitialPositionWithLargeNotification) {
  385. AddNotification(false /* pinned */);
  386. AddNotification(false /* pinned */);
  387. CreateMessageCenterView(60 /* max_height */);
  388. EXPECT_TRUE(message_center_view()->GetVisible());
  389. // MessageCenterView is shorter than the notification.
  390. gfx::Rect message_view_bounds = GetMessageViewVisibleBounds(1);
  391. EXPECT_LT(message_center_view()->bounds().height(),
  392. message_view_bounds.height());
  393. // Top of the second notification aligns with the top of MessageCenterView.
  394. if (!IsNotificationsRefreshEnabled())
  395. EXPECT_EQ(kStackedNotificationBarHeight, message_view_bounds.y());
  396. }
  397. TEST_P(UnifiedMessageCenterViewTest, ScrollPositionWhenResized) {
  398. // We keep the scroll position at the top after the notifications refresh.
  399. if (IsNotificationsRefreshEnabled())
  400. return;
  401. AddManyNotifications();
  402. CreateMessageCenterView();
  403. EXPECT_TRUE(message_center_view()->GetVisible());
  404. // MessageCenterView is maxed out.
  405. EXPECT_GT(GetMessageListView()->bounds().height(),
  406. message_center_view()->bounds().height());
  407. gfx::Rect previous_visible_rect = GetScroller()->GetVisibleRect();
  408. gfx::Size new_size = message_center_view()->size();
  409. new_size.set_height(250);
  410. message_center_view()->SetPreferredSize(new_size);
  411. OnViewPreferredSizeChanged(message_center_view());
  412. EXPECT_EQ(previous_visible_rect.bottom(),
  413. GetScroller()->GetVisibleRect().bottom());
  414. GetScroller()->ScrollToPosition(GetScrollBar(), 200);
  415. message_center_view()->OnMessageCenterScrolled();
  416. previous_visible_rect = GetScroller()->GetVisibleRect();
  417. new_size.set_height(300);
  418. message_center_view()->SetPreferredSize(new_size);
  419. OnViewPreferredSizeChanged(message_center_view());
  420. EXPECT_EQ(previous_visible_rect.bottom(),
  421. GetScroller()->GetVisibleRect().bottom());
  422. }
  423. // Tests basic layout of the StackingNotificationBar.
  424. TEST_P(UnifiedMessageCenterViewTest, StackingCounterLabelLayout) {
  425. AddManyNotifications();
  426. // MessageCenterView is maxed out.
  427. CreateMessageCenterView();
  428. EXPECT_GT(GetMessageListView()->bounds().height(),
  429. message_center_view()->bounds().height());
  430. EXPECT_TRUE(GetNotificationBar()->GetVisible());
  431. if (!features::IsNotificationsRefreshEnabled()) {
  432. EXPECT_EQ(0, GetNotificationBar()->bounds().y());
  433. EXPECT_EQ(GetNotificationBar()->bounds().bottom(),
  434. GetScroller()->bounds().y());
  435. } else {
  436. EXPECT_EQ(kMessageCenterPadding, GetScroller()->bounds().y());
  437. EXPECT_EQ(GetNotificationBar()->bounds().y(),
  438. GetScroller()->bounds().bottom());
  439. }
  440. EXPECT_TRUE(GetNotificationBarLabel()->GetVisible());
  441. EXPECT_TRUE(GetNotificationBarClearAllButton()->GetVisible());
  442. }
  443. // Tests that the NotificationBarLabel is invisible when scrolled to the top.
  444. TEST_P(UnifiedMessageCenterViewTest, StackingCounterLabelInvisible) {
  445. AddManyNotifications();
  446. CreateMessageCenterView();
  447. // Scroll to the top, the counter label should be invisible. After
  448. // NotificationsRefresh, scrolling to the bottom should make the counter
  449. // invisible.
  450. GetScroller()->ScrollToPosition(GetScrollBar(),
  451. features::IsNotificationsRefreshEnabled()
  452. ? GetScrollBar()->bounds().bottom()
  453. : 0);
  454. message_center_view()->OnMessageCenterScrolled();
  455. EXPECT_FALSE(GetNotificationBarLabel()->GetVisible());
  456. // ClearAll label should always be visible.
  457. EXPECT_TRUE(GetNotificationBarClearAllButton()->GetVisible());
  458. }
  459. // Tests that the NotificationBarLabel is visible when scrolling down.
  460. TEST_P(UnifiedMessageCenterViewTest, StackingCounterLabelVisible) {
  461. AddManyNotifications();
  462. CreateMessageCenterView();
  463. // Scrolling past 5 notifications should make the counter label visible.
  464. const int scroll_amount = (GetMessageViewVisibleBounds(0).height() * 5) + 1;
  465. GetScroller()->ScrollToPosition(
  466. GetScrollBar(),
  467. features::IsNotificationsRefreshEnabled() ? 0 : scroll_amount);
  468. message_center_view()->OnMessageCenterScrolled();
  469. EXPECT_TRUE(GetNotificationBarLabel()->GetVisible());
  470. // ClearAll label should always be visible.
  471. EXPECT_TRUE(GetNotificationBarClearAllButton()->GetVisible());
  472. }
  473. // Tests that the +n notifications label hides after being shown.
  474. TEST_P(UnifiedMessageCenterViewTest, StackingCounterLabelHidesAfterShown) {
  475. AddManyNotifications();
  476. CreateMessageCenterView();
  477. // Scroll to the top, making the counter label invisible. In
  478. // NotificationsRefresh we must scroll to the bottom instead.
  479. auto bottom_position = GetScrollBar()->bounds().bottom();
  480. GetScroller()->ScrollToPosition(
  481. GetScrollBar(),
  482. features::IsNotificationsRefreshEnabled() ? bottom_position : 0);
  483. message_center_view()->OnMessageCenterScrolled();
  484. EXPECT_FALSE(GetNotificationBarLabel()->GetVisible());
  485. // Scrolling past 5 notifications should make the counter label visible.
  486. const int scroll_amount = (GetMessageViewVisibleBounds(0).height() * 5) + 1;
  487. GetScroller()->ScrollToPosition(GetScrollBar(),
  488. features::IsNotificationsRefreshEnabled()
  489. ? bottom_position - scroll_amount
  490. : scroll_amount);
  491. message_center_view()->OnMessageCenterScrolled();
  492. ASSERT_TRUE(GetNotificationBarLabel()->GetVisible());
  493. // Scrolling back to the top (bottom in NotificationsRefresh) should make the
  494. // counter label invisible again.
  495. GetScroller()->ScrollToPosition(GetScrollBar(),
  496. features::IsNotificationsRefreshEnabled()
  497. ? GetScrollBar()->bounds().bottom()
  498. : 0);
  499. message_center_view()->OnMessageCenterScrolled();
  500. EXPECT_FALSE(GetNotificationBarLabel()->GetVisible());
  501. // ClearAll label should always be visible.
  502. EXPECT_TRUE(GetNotificationBarClearAllButton()->GetVisible());
  503. }
  504. // Tests that there are never more than 3 stacked icons in the
  505. // StackedNotificationBar. Also verifies that only one animation happens at a
  506. // time (this prevents the user from over-scrolling and showing multiple
  507. // animations when they scroll very quickly). Before, users could scroll fast
  508. // and have a large amount of icons, instead of keeping it to 3.
  509. TEST_P(UnifiedMessageCenterViewTest, StackingIconsNeverMoreThanThree) {
  510. for (int i = 0; i < 20; ++i)
  511. AddNotification(false);
  512. CreateMessageCenterView();
  513. auto bottom_position = GetScrollBar()->bounds().bottom();
  514. if (features::IsNotificationsRefreshEnabled()) {
  515. GetScroller()->ScrollToPosition(GetScrollBar(), bottom_position);
  516. message_center_view()->OnMessageCenterScrolled();
  517. }
  518. // Force animations to happen, so we can see if multiple animations trigger.
  519. ui::ScopedAnimationDurationScaleMode scoped_duration_modifier(
  520. ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION);
  521. // Scroll past 20 notifications, so we can scroll back up quickly.
  522. for (int i = 20; i >= 0; --i) {
  523. const int scroll_amount = (GetMessageViewVisibleBounds(0).height() * i) + 1;
  524. GetScroller()->ScrollToPosition(GetScrollBar(),
  525. features::IsNotificationsRefreshEnabled()
  526. ? bottom_position - scroll_amount
  527. : scroll_amount);
  528. message_center_view()->OnMessageCenterScrolled();
  529. auto icons_container_children =
  530. GetNotificationBarIconsContainer()->children();
  531. int animating_count = 0;
  532. for (auto* child : icons_container_children) {
  533. // Verify that no more than one icon is animating at any one time.
  534. if (child->layer()->GetAnimator()->is_animating())
  535. animating_count++;
  536. }
  537. EXPECT_GE(1, animating_count);
  538. // Verify that no more than 3 icons are added to the bar at any one time,
  539. // regardless of how fast the user scrolls. This test scrolls faster than
  540. // the icons can animate away, and animating icons should be removed prior
  541. // to starting a new animation.
  542. EXPECT_GE(3u, icons_container_children.size());
  543. }
  544. }
  545. // Flaky: crbug.com/1163575
  546. TEST_P(UnifiedMessageCenterViewTest,
  547. DISABLED_StackingCounterNotificationRemoval) {
  548. std::vector<std::string> ids = AddManyNotifications();
  549. CreateMessageCenterView();
  550. EXPECT_TRUE(message_center_view()->GetVisible());
  551. // MessageCenterView is maxed out.
  552. EXPECT_GT(GetMessageListView()->bounds().height(),
  553. message_center_view()->bounds().height());
  554. // Dismiss until there are 2 notifications. The bar should still be visible.
  555. EXPECT_TRUE(GetNotificationBar()->GetVisible());
  556. for (size_t i = 0; (i + 2) < ids.size(); ++i) {
  557. MessageCenter::Get()->RemoveNotification(ids[i], true /* by_user */);
  558. AnimateMessageListToEnd();
  559. }
  560. EXPECT_TRUE(GetNotificationBar()->GetVisible());
  561. EXPECT_FALSE(GetNotificationBarLabel()->GetVisible());
  562. EXPECT_TRUE(GetNotificationBarClearAllButton()->GetVisible());
  563. // The MessageCenterView should be tall enough to contain the bar, two
  564. // notifications.
  565. EXPECT_EQ(kStackedNotificationBarHeight + GetMessageListView()->height(),
  566. message_center_view()->height());
  567. // Dismiss until there is only 1 notification left. The bar should be
  568. // hidden after an animation.
  569. MessageCenter::Get()->RemoveNotification(ids[ids.size() - 2],
  570. true /* by_user */);
  571. EXPECT_TRUE(GetNotificationBar()->GetVisible());
  572. // The HIDE_STACKING_BAR animation starts after the notification is slid out.
  573. AnimateMessageListToEnd();
  574. auto* hide_animation = GetMessageCenterAnimation();
  575. EXPECT_TRUE(hide_animation->is_animating());
  576. EXPECT_TRUE(GetNotificationBar()->GetVisible());
  577. // Animate to middle. The bar should still be visible.
  578. AnimateMessageListToMiddle();
  579. hide_animation->SetCurrentValue(0.5);
  580. message_center_view()->AnimationProgressed(hide_animation);
  581. EXPECT_TRUE(GetNotificationBar()->GetVisible());
  582. // Animate to end. The bar should now be hidden.
  583. AnimateMessageListToEnd();
  584. hide_animation->End();
  585. EXPECT_FALSE(GetNotificationBar()->GetVisible());
  586. }
  587. TEST_P(UnifiedMessageCenterViewTest, StackingCounterLabelRelaidOutOnScroll) {
  588. // Open the message center at the top of the notification list so the stacking
  589. // bar is hidden by default.
  590. std::string id = AddNotification(false /* pinned */);
  591. int total_notifications = 30;
  592. for (int i = 0; i < total_notifications; ++i)
  593. AddNotification(false /* pinned */);
  594. model()->SetTargetNotification(id);
  595. CreateMessageCenterView();
  596. auto bottom_position =
  597. GetMessageViewVisibleBounds(total_notifications - 1).bottom();
  598. if (features::IsNotificationsRefreshEnabled()) {
  599. GetScroller()->ScrollToPosition(GetScrollBar(), bottom_position);
  600. message_center_view()->OnMessageCenterScrolled();
  601. }
  602. EXPECT_FALSE(GetNotificationBarLabel()->GetVisible());
  603. // Scroll past 6 notifications so the count label becomes visible
  604. int scroll_amount = (GetMessageViewVisibleBounds(0).height() * 6) + 1;
  605. GetScroller()->ScrollToPosition(GetScrollBar(),
  606. features::IsNotificationsRefreshEnabled()
  607. ? bottom_position - scroll_amount
  608. : scroll_amount);
  609. message_center_view()->OnMessageCenterScrolled();
  610. RelayoutMessageCenterViewForTest();
  611. EXPECT_TRUE(GetNotificationBarLabel()->GetVisible());
  612. int label_width = GetNotificationBarLabel()->bounds().width();
  613. EXPECT_GT(label_width, 0);
  614. // Scroll past 14 notifications so the label width must be expanded to
  615. // contain longer 2-digit label.
  616. scroll_amount = (GetMessageViewVisibleBounds(0).height() * 14) + 1;
  617. GetScroller()->ScrollToPosition(GetScrollBar(),
  618. features::IsNotificationsRefreshEnabled()
  619. ? bottom_position - scroll_amount
  620. : scroll_amount);
  621. message_center_view()->OnMessageCenterScrolled();
  622. RelayoutMessageCenterViewForTest();
  623. EXPECT_GT(GetNotificationBarLabel()->bounds().width(), label_width);
  624. }
  625. TEST_P(UnifiedMessageCenterViewTest, StackingCounterVisibility) {
  626. std::string id0 = AddNotification(false /* pinned */);
  627. std::string id1 = AddNotification(false /* pinned */);
  628. CreateMessageCenterView();
  629. // The bar should be visible with 2 unpinned notifications.
  630. EXPECT_TRUE(GetNotificationBar()->GetVisible());
  631. EXPECT_TRUE(GetNotificationBarClearAllButton()->GetVisible());
  632. MessageCenter::Get()->RemoveNotification(id0, true /* by_user */);
  633. AnimateMessageListToEnd();
  634. auto* hide_animation = GetMessageCenterAnimation();
  635. hide_animation->End();
  636. // The bar should be hidden with 1 notification. Note that in the new
  637. // notification UI, the bar and clear all button are always shown.
  638. if (!IsNotificationsRefreshEnabled())
  639. EXPECT_FALSE(GetNotificationBar()->GetVisible());
  640. MessageCenter::Get()->RemoveNotification(id1, true /* by_user */);
  641. AddNotification(true /* pinned */);
  642. AddNotification(true /* pinned */);
  643. // The bar should not be visible with 2 pinned notifications (none of the
  644. // notifications are hidden).
  645. if (!IsNotificationsRefreshEnabled())
  646. EXPECT_FALSE(GetNotificationBar()->GetVisible());
  647. for (size_t i = 0; i < 8; ++i)
  648. AddNotification(true /* pinned */);
  649. // The bar should be visible with 10 pinned notifications (some of the
  650. // notifications are hidden). However, clear all button should not be shown.
  651. EXPECT_TRUE(GetNotificationBar()->GetVisible());
  652. if (!IsNotificationsRefreshEnabled())
  653. EXPECT_FALSE(GetNotificationBarClearAllButton()->GetVisible());
  654. // Add 1 unpinned notifications. Clear all should now be shown.
  655. AddNotification(false /* pinned */);
  656. RelayoutMessageCenterViewForTest();
  657. EXPECT_TRUE(GetNotificationBarClearAllButton()->GetVisible());
  658. }
  659. INSTANTIATE_TEST_SUITE_P(All,
  660. UnifiedMessageCenterViewInWidgetTest,
  661. testing::Bool() /* IsNotificationsRefreshEnabled()
  662. */);
  663. // We need a widget to initialize a FocusManager.
  664. TEST_P(UnifiedMessageCenterViewInWidgetTest,
  665. FocusClearedAfterNotificationRemoval) {
  666. CreateMessageCenterView();
  667. widget()->Show();
  668. // Add notifications and focus on a child view in the last notification.
  669. AddNotification(false /* pinned */);
  670. auto id1 = AddNotification(false /* pinned */);
  671. // Toggle focus to the last notification MessageView.
  672. auto* focused_message_view = ToggleFocusToMessageView(
  673. features::IsNotificationsRefreshEnabled() ? 0 : 1 /* index */,
  674. true /* reverse */);
  675. ASSERT_TRUE(focused_message_view);
  676. EXPECT_EQ(id1, focused_message_view->notification_id());
  677. // Remove the notification and observe that the focus is cleared.
  678. MessageCenter::Get()->RemoveNotification(id1, true /* by_user */);
  679. AnimateMessageListToEnd();
  680. EXPECT_FALSE(message_center_view()->GetFocusManager()->GetFocusedView());
  681. }
  682. TEST_P(UnifiedMessageCenterViewTest, CollapseAndExpand_NonAnimated) {
  683. AddNotification(false /* pinned */);
  684. AddNotification(false /* pinned */);
  685. CreateMessageCenterView();
  686. EXPECT_TRUE(GetScroller()->GetVisible());
  687. EXPECT_TRUE(GetNotificationBarClearAllButton()->GetVisible());
  688. EXPECT_FALSE(GetNotificationBarExpandAllButton()->GetVisible());
  689. // Set to collapsed state.
  690. message_center_view()->SetCollapsed(false /* animate */);
  691. EXPECT_FALSE(GetScroller()->GetVisible());
  692. EXPECT_TRUE(GetNotificationBar()->GetVisible());
  693. EXPECT_TRUE(GetNotificationBarExpandAllButton()->GetVisible());
  694. EXPECT_FALSE(GetNotificationBarClearAllButton()->GetVisible());
  695. // Set back to expanded state.
  696. message_center_view()->SetExpanded();
  697. EXPECT_FALSE(GetNotificationBarExpandAllButton()->GetVisible());
  698. EXPECT_TRUE(GetNotificationBarClearAllButton()->GetVisible());
  699. EXPECT_TRUE(GetScroller()->GetVisible());
  700. }
  701. TEST_P(UnifiedMessageCenterViewTest, CollapseAndExpand_Animated) {
  702. AddNotification(false /* pinned */);
  703. AddNotification(false /* pinned */);
  704. CreateMessageCenterView();
  705. EXPECT_TRUE(GetScroller()->GetVisible());
  706. // Set to collapsed state with animation.
  707. message_center_view()->SetCollapsed(true /* animate */);
  708. auto* collapse_animation = GetMessageCenterAnimation();
  709. EXPECT_TRUE(collapse_animation->is_animating());
  710. // The scroller should be hidden at the half way point.
  711. collapse_animation->SetCurrentValue(0.5);
  712. message_center_view()->AnimationProgressed(collapse_animation);
  713. EXPECT_FALSE(GetScroller()->GetVisible());
  714. EXPECT_TRUE(GetNotificationBar()->GetVisible());
  715. collapse_animation->End();
  716. AnimateMessageListToEnd();
  717. EXPECT_TRUE(GetNotificationBarExpandAllButton()->GetVisible());
  718. EXPECT_FALSE(GetNotificationBarClearAllButton()->GetVisible());
  719. // Set back to expanded state.
  720. message_center_view()->SetExpanded();
  721. EXPECT_FALSE(GetNotificationBarExpandAllButton()->GetVisible());
  722. EXPECT_TRUE(GetNotificationBarClearAllButton()->GetVisible());
  723. EXPECT_TRUE(GetScroller()->GetVisible());
  724. }
  725. TEST_P(UnifiedMessageCenterViewTest, CollapseAndExpand_NoNotifications) {
  726. CreateMessageCenterView();
  727. EXPECT_FALSE(message_center_view()->GetVisible());
  728. // Setting to the collapsed state should do nothing.
  729. message_center_view()->SetCollapsed(true /* animate */);
  730. EXPECT_FALSE(message_center_view()->GetVisible());
  731. // Same with setting it back to the expanded state.
  732. message_center_view()->SetExpanded();
  733. EXPECT_FALSE(message_center_view()->GetVisible());
  734. }
  735. TEST_P(UnifiedMessageCenterViewTest, ClearAllButtonHeight) {
  736. std::string id0 = AddNotification(false /* pinned */);
  737. std::string id1 = AddNotification(false /* pinned */);
  738. CreateMessageCenterView();
  739. EXPECT_TRUE(message_center_view()->GetVisible());
  740. EXPECT_TRUE(GetNotificationBar()->GetVisible());
  741. EXPECT_TRUE(GetNotificationBarClearAllButton()->GetVisible());
  742. // Get ClearAll Button height.
  743. const int previous_button_height =
  744. GetNotificationBarClearAllButton()->height();
  745. // Remove a notification.
  746. MessageCenter::Get()->RemoveNotification(id0, true /* by_user */);
  747. // ClearAll Button height should remain the same.
  748. EXPECT_EQ(previous_button_height,
  749. GetNotificationBarClearAllButton()->height());
  750. }
  751. } // namespace ash