unified_system_tray_unittest.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493
  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/unified/unified_system_tray.h"
  5. #include "ash/accessibility/accessibility_controller_impl.h"
  6. #include "ash/constants/ash_features.h"
  7. #include "ash/ime/ime_controller_impl.h"
  8. #include "ash/public/cpp/test/shell_test_api.h"
  9. #include "ash/shelf/shelf.h"
  10. #include "ash/shelf/shelf_layout_manager.h"
  11. #include "ash/shell.h"
  12. #include "ash/system/message_center/unified_message_center_bubble.h"
  13. #include "ash/system/message_center/unified_message_center_view.h"
  14. #include "ash/system/status_area_widget.h"
  15. #include "ash/system/status_area_widget_test_helper.h"
  16. #include "ash/system/time/time_tray_item_view.h"
  17. #include "ash/system/time/time_view.h"
  18. #include "ash/system/unified/ime_mode_view.h"
  19. #include "ash/system/unified/unified_slider_bubble_controller.h"
  20. #include "ash/system/unified/unified_system_tray_bubble.h"
  21. #include "ash/system/unified/unified_system_tray_controller.h"
  22. #include "ash/system/unified/unified_system_tray_view.h"
  23. #include "ash/test/ash_test_base.h"
  24. #include "base/test/metrics/histogram_tester.h"
  25. #include "base/test/scoped_feature_list.h"
  26. #include "ui/display/display.h"
  27. #include "ui/display/screen.h"
  28. #include "ui/events/event.h"
  29. #include "ui/events/event_constants.h"
  30. #include "ui/message_center/message_center.h"
  31. namespace ash {
  32. using message_center::MessageCenter;
  33. using message_center::Notification;
  34. class UnifiedSystemTrayTest : public AshTestBase {
  35. public:
  36. UnifiedSystemTrayTest()
  37. : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
  38. UnifiedSystemTrayTest(const UnifiedSystemTrayTest&) = delete;
  39. UnifiedSystemTrayTest& operator=(const UnifiedSystemTrayTest&) = delete;
  40. ~UnifiedSystemTrayTest() override = default;
  41. void SetUp() override {
  42. feature_list_.InitAndEnableFeature(features::kCalendarView);
  43. AshTestBase::SetUp();
  44. }
  45. protected:
  46. const std::string AddNotification() {
  47. const std::string id = base::NumberToString(id_++);
  48. MessageCenter::Get()->AddNotification(
  49. std::make_unique<message_center::Notification>(
  50. message_center::NOTIFICATION_TYPE_SIMPLE, id, u"test title",
  51. u"test message", ui::ImageModel(),
  52. std::u16string() /* display_source */, GURL(),
  53. message_center::NotifierId(),
  54. message_center::RichNotificationData(),
  55. new message_center::NotificationDelegate()));
  56. return id;
  57. }
  58. void RemoveNotification(const std::string id) {
  59. MessageCenter::Get()->RemoveNotification(id, /*by_user=*/false);
  60. }
  61. bool IsSliderBubbleShown() {
  62. return GetPrimaryUnifiedSystemTray()
  63. ->slider_bubble_controller_->bubble_widget_;
  64. }
  65. bool MoreThanOneVisibleTrayItem() const {
  66. return GetPrimaryUnifiedSystemTray()->MoreThanOneVisibleTrayItem();
  67. }
  68. UnifiedSliderBubbleController::SliderType GetSliderBubbleType() {
  69. return GetPrimaryUnifiedSystemTray()
  70. ->slider_bubble_controller_->slider_type_;
  71. }
  72. UnifiedSystemTrayBubble* GetUnifiedSystemTrayBubble() {
  73. return GetPrimaryUnifiedSystemTray()->bubble_.get();
  74. }
  75. void UpdateAutoHideStateNow() {
  76. GetPrimaryShelf()->shelf_layout_manager()->UpdateAutoHideStateNow();
  77. }
  78. gfx::Rect GetBubbleViewBounds() {
  79. auto* bubble =
  80. GetPrimaryUnifiedSystemTray()->slider_bubble_controller_->bubble_view_;
  81. return bubble ? bubble->GetBoundsInScreen() : gfx::Rect();
  82. }
  83. TimeTrayItemView* time_view() {
  84. return GetPrimaryUnifiedSystemTray()->time_view_;
  85. }
  86. ImeModeView* ime_mode_view() {
  87. return GetPrimaryUnifiedSystemTray()->ime_mode_view_;
  88. }
  89. std::list<TrayItemView*> tray_items() {
  90. return GetPrimaryUnifiedSystemTray()->tray_items_;
  91. }
  92. views::View* vertical_clock_padding() {
  93. return GetPrimaryUnifiedSystemTray()->vertical_clock_padding_;
  94. }
  95. private:
  96. int id_ = 0;
  97. base::test::ScopedFeatureList feature_list_;
  98. };
  99. TEST_F(UnifiedSystemTrayTest, ShowVolumeSliderBubble) {
  100. // The volume popup is not visible initially.
  101. EXPECT_FALSE(IsSliderBubbleShown());
  102. // When set to autohide, the shelf shouldn't be shown.
  103. StatusAreaWidget* status = StatusAreaWidgetTestHelper::GetStatusAreaWidget();
  104. EXPECT_FALSE(status->ShouldShowShelf());
  105. // Simulate ARC asking to show the volume view.
  106. GetPrimaryUnifiedSystemTray()->ShowVolumeSliderBubble();
  107. // Volume view is now visible.
  108. EXPECT_TRUE(IsSliderBubbleShown());
  109. EXPECT_EQ(UnifiedSliderBubbleController::SLIDER_TYPE_VOLUME,
  110. GetSliderBubbleType());
  111. // This does not force the shelf to automatically show. Regression tests for
  112. // crbug.com/729188
  113. EXPECT_FALSE(status->ShouldShowShelf());
  114. }
  115. TEST_F(UnifiedSystemTrayTest, SliderBubbleMovesOnShelfAutohide) {
  116. // The slider button should be moved when the autohidden shelf is shown, so
  117. // as to not overlap. Regression test for crbug.com/1136564
  118. auto* shelf = GetPrimaryShelf();
  119. shelf->SetAlignment(ShelfAlignment::kBottom);
  120. shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
  121. // Create a test widget to make auto-hiding work. Auto-hidden shelf will
  122. // remain visible if no windows are shown, making it impossible to properly
  123. // test.
  124. views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
  125. params.bounds = gfx::Rect(0, 0, 200, 200);
  126. params.context = GetContext();
  127. views::Widget* widget = new views::Widget;
  128. widget->Init(std::move(params));
  129. widget->Show();
  130. // Start off the mouse nowhere near the shelf; the shelf should be hidden.
  131. display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay();
  132. auto center = display.bounds().CenterPoint();
  133. auto bottom_center = display.bounds().bottom_center();
  134. bottom_center.set_y(bottom_center.y() - 1);
  135. ui::test::EventGenerator* generator = GetEventGenerator();
  136. generator->MoveMouseTo(center);
  137. UpdateAutoHideStateNow();
  138. GetPrimaryUnifiedSystemTray()->ShowVolumeSliderBubble();
  139. gfx::Rect before_bounds = GetBubbleViewBounds();
  140. // Now move the mouse close to the edge, so that the shelf shows, and verify
  141. // that the volume slider adjusts accordingly.
  142. generator->MoveMouseTo(bottom_center);
  143. UpdateAutoHideStateNow();
  144. gfx::Rect after_bounds = GetBubbleViewBounds();
  145. EXPECT_NE(after_bounds, before_bounds);
  146. // Also verify that the shelf and slider bubble would have overlapped, but do
  147. // not now that we've moved the slider bubble.
  148. gfx::Rect shelf_bounds = shelf->GetShelfBoundsInScreen();
  149. EXPECT_TRUE(before_bounds.Intersects(shelf_bounds));
  150. EXPECT_FALSE(after_bounds.Intersects(shelf_bounds));
  151. // Move the mouse away and verify that it adjusts back to its original
  152. // position.
  153. generator->MoveMouseTo(center);
  154. UpdateAutoHideStateNow();
  155. after_bounds = GetBubbleViewBounds();
  156. EXPECT_EQ(after_bounds, before_bounds);
  157. // Now fullscreen and restore our window with autohide disabled and verify
  158. // that the bubble moves down as the shelf disappears and reappears. Disable
  159. // autohide so that the shelf is initially showing.
  160. shelf->SetAlignment(ShelfAlignment::kRight);
  161. after_bounds = GetBubbleViewBounds();
  162. EXPECT_NE(after_bounds, before_bounds);
  163. shelf->SetAlignment(ShelfAlignment::kBottom);
  164. after_bounds = GetBubbleViewBounds();
  165. EXPECT_EQ(after_bounds, before_bounds);
  166. // Adjust the alignment of the shelf, and verify that the bubble moves along
  167. // with it.
  168. shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kNever);
  169. before_bounds = GetBubbleViewBounds();
  170. widget->SetFullscreen(true);
  171. after_bounds = GetBubbleViewBounds();
  172. EXPECT_NE(after_bounds, before_bounds);
  173. widget->SetFullscreen(false);
  174. after_bounds = GetBubbleViewBounds();
  175. EXPECT_EQ(after_bounds, before_bounds);
  176. }
  177. TEST_F(UnifiedSystemTrayTest, ShowBubble_MultipleDisplays_OpenedOnSameDisplay) {
  178. // Initialize two displays with 800x700 resolution.
  179. UpdateDisplay("400+400-800x600,1220+400-800x600");
  180. auto* screen = display::Screen::GetScreen();
  181. EXPECT_EQ(2, screen->GetNumDisplays());
  182. // The tray bubble for each display should be opened on the same display.
  183. // See crbug.com/937420.
  184. for (int i = 0; i < screen->GetNumDisplays(); ++i) {
  185. auto* system_tray = GetPrimaryUnifiedSystemTray();
  186. system_tray->ShowBubble();
  187. const gfx::Rect primary_display_bounds = GetPrimaryDisplay().bounds();
  188. const gfx::Rect tray_bubble_bounds =
  189. GetPrimaryUnifiedSystemTray()->GetBubbleBoundsInScreen();
  190. EXPECT_TRUE(primary_display_bounds.Contains(tray_bubble_bounds))
  191. << "primary display bounds=" << primary_display_bounds.ToString()
  192. << ", tray bubble bounds=" << tray_bubble_bounds.ToString();
  193. SwapPrimaryDisplay();
  194. }
  195. }
  196. TEST_F(UnifiedSystemTrayTest, HorizontalImeAndTimeLabelAlignment) {
  197. ime_mode_view()->label()->SetText(u"US");
  198. ime_mode_view()->SetVisible(true);
  199. gfx::Rect time_bounds = time_view()
  200. ->time_view()
  201. ->horizontal_label_for_test()
  202. ->GetBoundsInScreen();
  203. gfx::Rect ime_bounds = ime_mode_view()->label()->GetBoundsInScreen();
  204. EXPECT_EQ(time_bounds.y(), ime_bounds.y());
  205. EXPECT_EQ(time_bounds.height(), ime_bounds.height());
  206. }
  207. TEST_F(UnifiedSystemTrayTest, VerticalClockPadding) {
  208. // Padding can only be visible if shelf is vertically aligned.
  209. GetPrimaryShelf()->SetAlignment(ShelfAlignment::kLeft);
  210. // Sets all tray items' visibility to false except TimeView.
  211. for (TrayItemView* item : tray_items()) {
  212. item->SetVisible(item == time_view());
  213. }
  214. // Only one visible tray item, padding should not be visible.
  215. EXPECT_FALSE(vertical_clock_padding()->GetVisible());
  216. // Sets another tray item visibility to true.
  217. ime_mode_view()->SetVisible(true);
  218. // Two visible tray items, padding should be visible.
  219. EXPECT_TRUE(vertical_clock_padding()->GetVisible());
  220. }
  221. TEST_F(UnifiedSystemTrayTest, VerticalClockPaddingAfterAlignmentChange) {
  222. auto* shelf = GetPrimaryShelf();
  223. // Padding can only be visible if shelf is vertically aligned.
  224. shelf->SetAlignment(ShelfAlignment::kLeft);
  225. // Ensure two tray items are visible, padding should be visible.
  226. time_view()->SetVisible(true);
  227. ime_mode_view()->SetVisible(true);
  228. EXPECT_TRUE(vertical_clock_padding()->GetVisible());
  229. // Padding should not be visible when shelf is horizontal.
  230. shelf->SetAlignment(ShelfAlignment::kBottom);
  231. EXPECT_FALSE(vertical_clock_padding()->GetVisible());
  232. }
  233. TEST_F(UnifiedSystemTrayTest, FocusMessageCenter) {
  234. auto* tray = GetPrimaryUnifiedSystemTray();
  235. tray->ShowBubble();
  236. auto* message_center_view =
  237. tray->message_center_bubble()->message_center_view();
  238. auto* focus_manager = message_center_view->GetFocusManager();
  239. AddNotification();
  240. AddNotification();
  241. message_center_view->SetVisible(true);
  242. EXPECT_FALSE(message_center_view->Contains(focus_manager->GetFocusedView()));
  243. EXPECT_FALSE(message_center_view->collapsed());
  244. auto did_focus = tray->FocusMessageCenter(false);
  245. EXPECT_TRUE(did_focus);
  246. EXPECT_TRUE(tray->IsMessageCenterBubbleShown());
  247. EXPECT_FALSE(message_center_view->collapsed());
  248. EXPECT_TRUE(message_center_view->Contains(focus_manager->GetFocusedView()));
  249. }
  250. TEST_F(UnifiedSystemTrayTest, FocusMessageCenter_MessageCenterBubbleNotShown) {
  251. auto* tray = GetPrimaryUnifiedSystemTray();
  252. tray->ShowBubble();
  253. auto* message_center_bubble = tray->message_center_bubble();
  254. EXPECT_FALSE(message_center_bubble->IsMessageCenterVisible());
  255. auto did_focus = tray->FocusMessageCenter(false);
  256. EXPECT_FALSE(did_focus);
  257. }
  258. TEST_F(UnifiedSystemTrayTest, FocusMessageCenter_VoxEnabled) {
  259. auto* tray = GetPrimaryUnifiedSystemTray();
  260. tray->ShowBubble();
  261. auto* message_center_bubble = tray->message_center_bubble();
  262. auto* message_center_view = message_center_bubble->message_center_view();
  263. AddNotification();
  264. AddNotification();
  265. message_center_view->SetVisible(true);
  266. Shell::Get()->accessibility_controller()->spoken_feedback().SetEnabled(true);
  267. EXPECT_FALSE(message_center_bubble->GetBubbleWidget()->IsActive());
  268. auto did_focus = tray->FocusMessageCenter(false);
  269. EXPECT_TRUE(did_focus);
  270. auto* focus_manager = tray->GetFocusManager();
  271. EXPECT_TRUE(tray->IsMessageCenterBubbleShown());
  272. EXPECT_TRUE(message_center_bubble->GetBubbleWidget()->IsActive());
  273. EXPECT_FALSE(message_center_view->Contains(focus_manager->GetFocusedView()));
  274. }
  275. TEST_F(UnifiedSystemTrayTest, FocusQuickSettings) {
  276. auto* tray = GetPrimaryUnifiedSystemTray();
  277. tray->ShowBubble();
  278. auto* unified_system_tray_view = tray->bubble()->unified_view();
  279. auto* focus_manager = unified_system_tray_view->GetFocusManager();
  280. EXPECT_FALSE(
  281. unified_system_tray_view->Contains(focus_manager->GetFocusedView()));
  282. auto did_focus = tray->FocusQuickSettings(false);
  283. EXPECT_TRUE(did_focus);
  284. EXPECT_TRUE(
  285. unified_system_tray_view->Contains(focus_manager->GetFocusedView()));
  286. }
  287. TEST_F(UnifiedSystemTrayTest, FocusQuickSettings_BubbleNotShown) {
  288. auto* tray = GetPrimaryUnifiedSystemTray();
  289. auto did_focus = tray->FocusQuickSettings(false);
  290. EXPECT_FALSE(did_focus);
  291. }
  292. TEST_F(UnifiedSystemTrayTest, FocusQuickSettings_VoxEnabled) {
  293. auto* tray = GetPrimaryUnifiedSystemTray();
  294. tray->ShowBubble();
  295. auto* tray_bubble_widget = tray->bubble()->GetBubbleWidget();
  296. Shell::Get()->accessibility_controller()->spoken_feedback().SetEnabled(true);
  297. EXPECT_FALSE(tray_bubble_widget->IsActive());
  298. auto did_focus = tray->FocusQuickSettings(false);
  299. EXPECT_TRUE(did_focus);
  300. auto* unified_system_tray_view = tray->bubble()->unified_view();
  301. auto* focus_manager = unified_system_tray_view->GetFocusManager();
  302. EXPECT_TRUE(tray_bubble_widget->IsActive());
  303. EXPECT_FALSE(
  304. unified_system_tray_view->Contains(focus_manager->GetFocusedView()));
  305. }
  306. TEST_F(UnifiedSystemTrayTest, TimeInQuickSettingsMetric) {
  307. base::HistogramTester histogram_tester;
  308. constexpr base::TimeDelta kTimeInQuickSettings = base::Seconds(3);
  309. auto* tray = GetPrimaryUnifiedSystemTray();
  310. // Open the tray.
  311. tray->ShowBubble();
  312. // Spend cool-down time with tray open.
  313. task_environment()->FastForwardBy(kTimeInQuickSettings);
  314. // Close and record the metric.
  315. tray->CloseBubble();
  316. // Ensure metric recorded time passed while Quick Setting was open.
  317. histogram_tester.ExpectTimeBucketCount("Ash.QuickSettings.UserJourneyTime",
  318. kTimeInQuickSettings,
  319. /*count=*/1);
  320. // Re-open the tray.
  321. tray->ShowBubble();
  322. // Metric isn't recorded when adding and removing a notification.
  323. std::string id = AddNotification();
  324. RemoveNotification(id);
  325. histogram_tester.ExpectTotalCount("Ash.QuickSettings.UserJourneyTime",
  326. /*count=*/1);
  327. // Metric is recorded after closing bubble.
  328. tray->CloseBubble();
  329. histogram_tester.ExpectTotalCount("Ash.QuickSettings.UserJourneyTime",
  330. /*count=*/2);
  331. }
  332. // Tests that pressing the TOGGLE_CALENDAR accelerator once results in the
  333. // calendar view showing.
  334. TEST_F(UnifiedSystemTrayTest, PressCalendarAccelerator) {
  335. ShellTestApi().PressAccelerator(
  336. ui::Accelerator(ui::VKEY_C, ui::EF_COMMAND_DOWN));
  337. EXPECT_TRUE(GetPrimaryUnifiedSystemTray()->IsShowingCalendarView());
  338. }
  339. // Tests that pressing the TOGGLE_CALENDAR accelerator twice results in a hidden
  340. // QuickSettings bubble.
  341. TEST_F(UnifiedSystemTrayTest, ToggleCalendarViewAccelerator) {
  342. ShellTestApi().PressAccelerator(
  343. ui::Accelerator(ui::VKEY_C, ui::EF_COMMAND_DOWN));
  344. ShellTestApi().PressAccelerator(
  345. ui::Accelerator(ui::VKEY_C, ui::EF_COMMAND_DOWN));
  346. EXPECT_FALSE(GetUnifiedSystemTrayBubble());
  347. }
  348. // Tests that showing the calendar view by the TOGGLE_CALENDAR accelerator
  349. // results in the CalendarDateCellView being focused.
  350. TEST_F(UnifiedSystemTrayTest, CalendarAcceleratorFocusesDateCell) {
  351. ShellTestApi().PressAccelerator(
  352. ui::Accelerator(ui::VKEY_C, ui::EF_COMMAND_DOWN));
  353. auto* focus_manager =
  354. GetUnifiedSystemTrayBubble()->GetBubbleWidget()->GetFocusManager();
  355. EXPECT_TRUE(focus_manager->GetFocusedView());
  356. EXPECT_STREQ(focus_manager->GetFocusedView()->GetClassName(),
  357. "CalendarDateCellView");
  358. }
  359. // Tests that CalendarView switches back to Quick Settings when screen size is
  360. // limited and the bubble requires a collapsed state.
  361. TEST_F(UnifiedSystemTrayTest, CalendarGoesToMainView) {
  362. auto* tray = GetPrimaryUnifiedSystemTray();
  363. tray->ShowBubble();
  364. // Set a limited screen size.
  365. UpdateDisplay("800x600");
  366. // Generate a notification, close and open the bubble so we can show the
  367. // collapsed message center.
  368. AddNotification();
  369. tray->CloseBubble();
  370. tray->ShowBubble();
  371. // Ensure message center is collapsed when Calendar is not being shown.
  372. auto* message_center_view =
  373. tray->message_center_bubble()->message_center_view();
  374. EXPECT_FALSE(tray->IsShowingCalendarView());
  375. EXPECT_TRUE(message_center_view->collapsed());
  376. // Ensure message center is collapsed when the Calendar is being shown.
  377. ShellTestApi().PressAccelerator(
  378. ui::Accelerator(ui::VKEY_C, ui::EF_COMMAND_DOWN));
  379. EXPECT_TRUE(tray->IsShowingCalendarView());
  380. EXPECT_TRUE(message_center_view->collapsed());
  381. // Test that Calendar is no longer shown after expanding the collapsed
  382. // message center.
  383. tray->message_center_bubble()->ExpandMessageCenter();
  384. EXPECT_FALSE(message_center_view->collapsed());
  385. EXPECT_FALSE(tray->IsShowingCalendarView());
  386. }
  387. } // namespace ash