unified_message_center_bubble_unittest.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. // Copyright 2019 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_bubble.h"
  5. #include <memory>
  6. #include "ash/constants/ash_features.h"
  7. #include "ash/constants/ash_pref_names.h"
  8. #include "ash/session/session_controller_impl.h"
  9. #include "ash/shell.h"
  10. #include "ash/system/message_center/unified_message_center_view.h"
  11. #include "ash/system/tray/tray_constants.h"
  12. #include "ash/system/unified/unified_system_tray.h"
  13. #include "ash/system/unified/unified_system_tray_bubble.h"
  14. #include "ash/system/unified/unified_system_tray_controller.h"
  15. #include "ash/system/unified/unified_system_tray_view.h"
  16. #include "ash/test/ash_test_base.h"
  17. #include "ash/wm/tablet_mode/tablet_mode_controller.h"
  18. #include "base/strings/stringprintf.h"
  19. #include "base/test/scoped_feature_list.h"
  20. #include "components/prefs/pref_service.h"
  21. #include "ui/events/keycodes/keyboard_codes_posix.h"
  22. #include "ui/message_center/message_center.h"
  23. using message_center::MessageCenter;
  24. using message_center::Notification;
  25. #include <iostream>
  26. namespace ash {
  27. class UnifiedMessageCenterBubbleTest
  28. : public AshTestBase,
  29. public testing::WithParamInterface<bool> {
  30. public:
  31. UnifiedMessageCenterBubbleTest() = default;
  32. UnifiedMessageCenterBubbleTest(const UnifiedMessageCenterBubbleTest&) =
  33. delete;
  34. UnifiedMessageCenterBubbleTest& operator=(
  35. const UnifiedMessageCenterBubbleTest&) = delete;
  36. ~UnifiedMessageCenterBubbleTest() override = default;
  37. // AshTestBase:
  38. void SetUp() override {
  39. scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
  40. scoped_feature_list_->InitWithFeatureState(features::kNotificationsRefresh,
  41. IsNotificationsRefreshEnabled());
  42. AshTestBase::SetUp();
  43. }
  44. bool IsNotificationsRefreshEnabled() const { return GetParam(); }
  45. protected:
  46. std::string AddWebNotification() {
  47. std::string id = base::NumberToString(id_++);
  48. MessageCenter::Get()->AddNotification(std::make_unique<Notification>(
  49. message_center::NOTIFICATION_TYPE_SIMPLE, id, u"title", u"message",
  50. ui::ImageModel(), std::u16string(), GURL(),
  51. message_center::NotifierId(GURL(u"example.com"), u"webpagetitle"),
  52. message_center::RichNotificationData(), /*delegate=*/nullptr));
  53. return id;
  54. }
  55. std::string AddNotification() {
  56. std::string id = base::NumberToString(id_++);
  57. MessageCenter::Get()->AddNotification(std::make_unique<Notification>(
  58. message_center::NOTIFICATION_TYPE_SIMPLE, id, u"test title",
  59. u"test message", ui::ImageModel(), std::u16string(), GURL(),
  60. message_center::NotifierId(), message_center::RichNotificationData(),
  61. new message_center::NotificationDelegate()));
  62. return id;
  63. }
  64. void RemoveAllNotifications() {
  65. message_center::MessageCenter::Get()->RemoveAllNotifications(
  66. /*by_user=*/true, MessageCenter::RemoveType::ALL);
  67. GetMessageCenterBubble()
  68. ->message_center_view()
  69. ->message_list_view()
  70. ->ResetBounds();
  71. }
  72. UnifiedMessageCenterBubble* GetMessageCenterBubble() {
  73. return GetPrimaryUnifiedSystemTray()->message_center_bubble();
  74. }
  75. UnifiedSystemTrayBubble* GetSystemTrayBubble() {
  76. return GetPrimaryUnifiedSystemTray()->bubble();
  77. }
  78. int MessageCenterSeparationHeight() {
  79. gfx::Rect message_bubble_bounds =
  80. GetMessageCenterBubble()->GetBubbleView()->GetBoundsInScreen();
  81. gfx::Rect tray_bounds =
  82. GetSystemTrayBubble()->GetBubbleView()->GetBoundsInScreen();
  83. return message_bubble_bounds.y() + message_bubble_bounds.height() -
  84. tray_bounds.y();
  85. }
  86. bool IsMessageCenterCollapsed() {
  87. return GetMessageCenterBubble()->message_center_view()->collapsed();
  88. }
  89. bool IsQuickSettingsCollapsed() {
  90. return !GetSystemTrayBubble()
  91. ->unified_system_tray_controller()
  92. ->IsExpanded();
  93. }
  94. // Helper functions for focus cycle testing.
  95. void DoTab() { PressAndReleaseKey(ui::KeyboardCode::VKEY_TAB, ui::EF_NONE); }
  96. void DoShiftTab() {
  97. PressAndReleaseKey(ui::KeyboardCode::VKEY_TAB, ui::EF_SHIFT_DOWN);
  98. }
  99. void DoAltShiftN() {
  100. PressAndReleaseKey(ui::KeyboardCode::VKEY_N,
  101. ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN);
  102. }
  103. void DoEsc() { PressAndReleaseKey(ui::KeyboardCode::VKEY_ESCAPE); }
  104. void ToggleExpanded() {
  105. GetSystemTrayBubble()->unified_system_tray_controller()->ToggleExpanded();
  106. }
  107. void WaitForAnimation() {
  108. // Some animations do not complete without checking is_animating();
  109. do {
  110. base::RunLoop().RunUntilIdle();
  111. } while (
  112. GetSystemTrayBubble() &&
  113. GetSystemTrayBubble()->unified_system_tray_controller() &&
  114. GetSystemTrayBubble()->unified_system_tray_controller()->animation_ &&
  115. GetSystemTrayBubble()
  116. ->unified_system_tray_controller()
  117. ->animation_->is_animating());
  118. }
  119. views::View* GetFirstMessageCenterFocusable() {
  120. return GetMessageCenterBubble()
  121. ->message_center_view()
  122. ->GetFirstFocusableChild();
  123. }
  124. views::View* GetLastMessageCenterFocusable() {
  125. return GetMessageCenterBubble()
  126. ->message_center_view()
  127. ->GetLastFocusableChild();
  128. }
  129. views::View* GetFirstQuickSettingsFocusable() {
  130. return GetSystemTrayBubble()->unified_view()->GetFirstFocusableChild();
  131. }
  132. views::View* GetLastQuickSettingsFocusable() {
  133. return GetSystemTrayBubble()->unified_view()->GetLastFocusableChild();
  134. }
  135. private:
  136. int id_ = 0;
  137. std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
  138. };
  139. INSTANTIATE_TEST_SUITE_P(All,
  140. UnifiedMessageCenterBubbleTest,
  141. testing::Bool() /* IsNotificationsRefreshEnabled() */);
  142. TEST_P(UnifiedMessageCenterBubbleTest, PositionedAboveSystemTray) {
  143. const int total_notifications = 5;
  144. GetPrimaryUnifiedSystemTray()->ShowBubble();
  145. AddNotification();
  146. const int reference_separation = MessageCenterSeparationHeight();
  147. // The message center should be positioned a constant distance above
  148. // the tray as it grows in size.
  149. for (int i = 0; i < total_notifications; i++) {
  150. AddNotification();
  151. EXPECT_EQ(reference_separation, MessageCenterSeparationHeight());
  152. }
  153. // When the system tray is collapsing, message view should stay at a constant
  154. // height above it.
  155. for (double i = 1.0; i >= 0; i -= 0.1) {
  156. GetSystemTrayBubble()->unified_view()->SetExpandedAmount(i);
  157. EXPECT_EQ(reference_separation, MessageCenterSeparationHeight());
  158. }
  159. // When the system tray is collapsing, message view should stay at a constant
  160. // height above it.
  161. for (double i = 0.0; i <= 1.0; i += 0.1) {
  162. GetSystemTrayBubble()->unified_view()->SetExpandedAmount(i);
  163. EXPECT_EQ(reference_separation, MessageCenterSeparationHeight());
  164. }
  165. }
  166. TEST_P(UnifiedMessageCenterBubbleTest, FocusCycle) {
  167. GetPrimaryUnifiedSystemTray()->ShowBubble();
  168. AddNotification();
  169. AddNotification();
  170. views::Widget* quick_settings_widget =
  171. GetSystemTrayBubble()->GetBubbleWidget();
  172. views::Widget* message_center_widget =
  173. GetMessageCenterBubble()->GetBubbleWidget();
  174. // First tab should focus the first element in the quick settings bubble.
  175. DoTab();
  176. EXPECT_TRUE(quick_settings_widget->IsActive());
  177. EXPECT_FALSE(message_center_widget->IsActive());
  178. EXPECT_EQ(quick_settings_widget->GetFocusManager()->GetFocusedView(),
  179. GetFirstQuickSettingsFocusable());
  180. // Keep tabbing until we reach the last focusable element in the quick
  181. // settings bubble.
  182. while (quick_settings_widget->GetFocusManager()->GetFocusedView() !=
  183. GetLastQuickSettingsFocusable()) {
  184. DoTab();
  185. }
  186. // Tab at the last element in the quick settings bubble should move focus to
  187. // the first element in the message center.
  188. DoTab();
  189. EXPECT_TRUE(message_center_widget->IsActive());
  190. EXPECT_FALSE(quick_settings_widget->IsActive());
  191. EXPECT_EQ(message_center_widget->GetFocusManager()->GetFocusedView(),
  192. GetFirstMessageCenterFocusable());
  193. // Keep tabbing until we reach the last focusable element in the message
  194. // center bubble.
  195. while (message_center_widget->GetFocusManager()->GetFocusedView() !=
  196. GetLastMessageCenterFocusable()) {
  197. DoTab();
  198. }
  199. // Tab at the last element in the message center bubble should move focus to
  200. // the first element in the quick settings bubble.
  201. DoTab();
  202. EXPECT_TRUE(quick_settings_widget->IsActive());
  203. EXPECT_FALSE(message_center_widget->IsActive());
  204. EXPECT_EQ(quick_settings_widget->GetFocusManager()->GetFocusedView(),
  205. GetFirstQuickSettingsFocusable());
  206. }
  207. TEST_P(UnifiedMessageCenterBubbleTest, CollapseState) {
  208. AddNotification();
  209. AddNotification();
  210. GetPrimaryUnifiedSystemTray()->ShowBubble();
  211. int small_display_height =
  212. GetSystemTrayBubble()->unified_view()->GetCollapsedSystemTrayHeight() +
  213. (2 * kMessageCenterCollapseThreshold);
  214. int large_display_height =
  215. GetSystemTrayBubble()->unified_view()->GetExpandedSystemTrayHeight() +
  216. (4 * kMessageCenterCollapseThreshold);
  217. GetPrimaryUnifiedSystemTray()->CloseBubble();
  218. // Clear pref to test behavior when expanded pref is not set.
  219. PrefService* prefs =
  220. Shell::Get()->session_controller()->GetLastActiveUserPrefService();
  221. prefs->ClearPref(prefs::kSystemTrayExpanded);
  222. // Message center should open in expanded state when screen height is
  223. // limited.
  224. UpdateDisplay(base::StringPrintf("1000x%d", small_display_height));
  225. GetPrimaryUnifiedSystemTray()->ShowBubble();
  226. WaitForAnimation();
  227. EXPECT_TRUE(IsQuickSettingsCollapsed());
  228. EXPECT_FALSE(IsMessageCenterCollapsed());
  229. // Message center should be collapsed when quick settings is expanded
  230. // with limited screen height.
  231. ToggleExpanded();
  232. WaitForAnimation();
  233. EXPECT_TRUE(IsMessageCenterCollapsed());
  234. ToggleExpanded();
  235. WaitForAnimation();
  236. EXPECT_FALSE(IsMessageCenterCollapsed());
  237. GetPrimaryUnifiedSystemTray()->CloseBubble();
  238. UpdateDisplay(base::StringPrintf("1000x%d", large_display_height));
  239. GetPrimaryUnifiedSystemTray()->ShowBubble();
  240. EXPECT_FALSE(IsMessageCenterCollapsed());
  241. ToggleExpanded();
  242. WaitForAnimation();
  243. EXPECT_FALSE(IsMessageCenterCollapsed());
  244. ToggleExpanded();
  245. WaitForAnimation();
  246. EXPECT_FALSE(IsMessageCenterCollapsed());
  247. }
  248. TEST_P(UnifiedMessageCenterBubbleTest, FocusCycleWithNoNotifications) {
  249. GetPrimaryUnifiedSystemTray()->ShowBubble();
  250. views::Widget* quick_settings_widget =
  251. GetSystemTrayBubble()->GetBubbleWidget();
  252. views::Widget* message_center_widget =
  253. GetMessageCenterBubble()->GetBubbleWidget();
  254. // First tab should focus the first element in the quick settings bubble.
  255. DoTab();
  256. EXPECT_TRUE(quick_settings_widget->IsActive());
  257. EXPECT_FALSE(message_center_widget->IsActive());
  258. EXPECT_EQ(quick_settings_widget->GetFocusManager()->GetFocusedView(),
  259. GetFirstQuickSettingsFocusable());
  260. // Keep tabbing until we reach the last focusable element in the quick
  261. // settings bubble.
  262. while (quick_settings_widget->GetFocusManager()->GetFocusedView() !=
  263. GetLastQuickSettingsFocusable()) {
  264. DoTab();
  265. }
  266. // Tab at the last element in the quick settings bubble should move focus to
  267. // the first element in the quick settings bubble.
  268. DoTab();
  269. EXPECT_TRUE(quick_settings_widget->IsActive());
  270. EXPECT_FALSE(message_center_widget->IsActive());
  271. EXPECT_EQ(quick_settings_widget->GetFocusManager()->GetFocusedView(),
  272. GetFirstQuickSettingsFocusable());
  273. }
  274. TEST_P(UnifiedMessageCenterBubbleTest, BubbleBounds) {
  275. std::vector<std::string> displays = {"0+0-1200x800", "0+0-1280x1080",
  276. "0+0-1600x1440"};
  277. for (auto display : displays) {
  278. // Set display size where the message center is not collapsed.
  279. UpdateDisplay(display);
  280. // Ensure message center is not collapsed.
  281. GetPrimaryUnifiedSystemTray()->ShowBubble();
  282. ASSERT_FALSE(GetMessageCenterBubble()->IsMessageCenterCollapsed());
  283. // Add enough notifications so that the scroll bar is visible.
  284. while (
  285. !GetMessageCenterBubble()->message_center_view()->IsScrollBarVisible())
  286. AddNotification();
  287. // The message center bubble should be positioned above the system tray
  288. // bubble.
  289. GetPrimaryUnifiedSystemTray()->ShowBubble();
  290. EXPECT_LT(GetMessageCenterBubble()->GetBoundsInScreen().bottom(),
  291. GetSystemTrayBubble()->GetBoundsInScreen().y());
  292. GetPrimaryUnifiedSystemTray()->CloseBubble();
  293. // Go into overview mode, check bounds again.
  294. EnterOverview();
  295. GetPrimaryUnifiedSystemTray()->ShowBubble();
  296. EXPECT_LT(GetMessageCenterBubble()->GetBoundsInScreen().bottom(),
  297. GetSystemTrayBubble()->GetBoundsInScreen().y());
  298. GetPrimaryUnifiedSystemTray()->CloseBubble();
  299. ExitOverview();
  300. // Go into tablet mode, check bounds again.
  301. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  302. GetPrimaryUnifiedSystemTray()->ShowBubble();
  303. EXPECT_LT(GetMessageCenterBubble()->GetBoundsInScreen().bottom(),
  304. GetSystemTrayBubble()->GetBoundsInScreen().y());
  305. GetPrimaryUnifiedSystemTray()->CloseBubble();
  306. // Go into overview mode inside tablet mode, check bounds again.
  307. EnterOverview();
  308. GetPrimaryUnifiedSystemTray()->ShowBubble();
  309. EXPECT_LT(GetMessageCenterBubble()->GetBoundsInScreen().bottom(),
  310. GetSystemTrayBubble()->GetBoundsInScreen().y());
  311. GetPrimaryUnifiedSystemTray()->CloseBubble();
  312. }
  313. }
  314. TEST_P(UnifiedMessageCenterBubbleTest, HandleAccelerators) {
  315. auto id = AddWebNotification();
  316. WaitForAnimation();
  317. // Open and focus message center.
  318. DoAltShiftN();
  319. WaitForAnimation();
  320. EXPECT_TRUE(GetMessageCenterBubble()->IsMessageCenterVisible());
  321. EXPECT_EQ(
  322. 1u,
  323. message_center::MessageCenter::Get()->GetVisibleNotifications().size());
  324. views::Widget* quick_settings_widget =
  325. GetSystemTrayBubble()->GetBubbleWidget();
  326. views::Widget* message_center_widget =
  327. GetMessageCenterBubble()->GetBubbleWidget();
  328. EXPECT_FALSE(quick_settings_widget->IsActive());
  329. EXPECT_TRUE(message_center_widget->GetFocusManager()->GetFocusedView());
  330. RemoveAllNotifications();
  331. WaitForAnimation();
  332. EXPECT_EQ(
  333. 0u,
  334. message_center::MessageCenter::Get()->GetVisibleNotifications().size());
  335. EXPECT_FALSE(quick_settings_widget->IsActive());
  336. EXPECT_FALSE(message_center_widget->GetFocusManager()->GetFocusedView());
  337. EXPECT_EQ(nullptr, GetFirstMessageCenterFocusable());
  338. EXPECT_EQ(nullptr,
  339. message_center_widget->GetFocusManager()->GetFocusedView());
  340. // Press Esc to close system tray.
  341. DoEsc();
  342. WaitForAnimation();
  343. EXPECT_EQ(nullptr,
  344. GetPrimaryUnifiedSystemTray()->GetFocusManager()->GetFocusedView());
  345. }
  346. } // namespace ash