immersive_fullscreen_controller_unittest.cc 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164
  1. // Copyright 2013 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 "chromeos/ui/frame/immersive/immersive_fullscreen_controller.h"
  5. #include "ash/frame/header_view.h"
  6. #include "ash/frame/non_client_frame_view_ash.h"
  7. #include "ash/public/cpp/shelf_config.h"
  8. #include "ash/public/cpp/shelf_types.h"
  9. #include "ash/root_window_controller.h"
  10. #include "ash/shelf/shelf.h"
  11. #include "ash/shelf/shelf_widget.h"
  12. #include "ash/shell.h"
  13. #include "ash/test/ash_test_base.h"
  14. #include "ash/wm/splitview/split_view_controller.h"
  15. #include "ash/wm/tablet_mode/tablet_mode_controller.h"
  16. #include "ash/wm/window_state.h"
  17. #include "base/test/scoped_feature_list.h"
  18. #include "chromeos/ui/frame/immersive/immersive_fullscreen_controller_delegate.h"
  19. #include "chromeos/ui/frame/immersive/immersive_fullscreen_controller_test_api.h"
  20. #include "ui/aura/client/aura_constants.h"
  21. #include "ui/aura/client/cursor_client.h"
  22. #include "ui/aura/env.h"
  23. #include "ui/aura/test/test_window_delegate.h"
  24. #include "ui/aura/window.h"
  25. #include "ui/aura/window_event_dispatcher.h"
  26. #include "ui/display/display_layout.h"
  27. #include "ui/display/manager/display_manager.h"
  28. #include "ui/display/test/display_manager_test_api.h"
  29. #include "ui/events/event_utils.h"
  30. #include "ui/events/test/event_generator.h"
  31. #include "ui/events/test/test_event_handler.h"
  32. #include "ui/gfx/animation/slide_animation.h"
  33. #include "ui/views/bubble/bubble_dialog_delegate_view.h"
  34. #include "ui/views/controls/native/native_view_host.h"
  35. #include "ui/views/view.h"
  36. #include "ui/views/widget/widget.h"
  37. namespace ash {
  38. namespace {
  39. using ::chromeos::ImmersiveFullscreenController;
  40. using ::chromeos::ImmersiveFullscreenControllerDelegate;
  41. using ::chromeos::ImmersiveFullscreenControllerTestApi;
  42. using ::chromeos::ImmersiveRevealedLock;
  43. class TestBubbleDialogDelegate : public views::BubbleDialogDelegateView {
  44. public:
  45. explicit TestBubbleDialogDelegate(views::View* anchor)
  46. : BubbleDialogDelegateView(anchor, views::BubbleBorder::NONE) {}
  47. TestBubbleDialogDelegate(const TestBubbleDialogDelegate&) = delete;
  48. TestBubbleDialogDelegate& operator=(const TestBubbleDialogDelegate&) = delete;
  49. ~TestBubbleDialogDelegate() override = default;
  50. };
  51. class MockImmersiveFullscreenControllerDelegate
  52. : public ImmersiveFullscreenControllerDelegate {
  53. public:
  54. MockImmersiveFullscreenControllerDelegate(views::View* top_container_view)
  55. : top_container_view_(top_container_view),
  56. enabled_(false),
  57. visible_fraction_(1) {}
  58. MockImmersiveFullscreenControllerDelegate(
  59. const MockImmersiveFullscreenControllerDelegate&) = delete;
  60. MockImmersiveFullscreenControllerDelegate& operator=(
  61. const MockImmersiveFullscreenControllerDelegate&) = delete;
  62. ~MockImmersiveFullscreenControllerDelegate() override = default;
  63. // ImmersiveFullscreenControllerDelegate overrides:
  64. void OnImmersiveRevealStarted() override {
  65. enabled_ = true;
  66. visible_fraction_ = 0;
  67. }
  68. void OnImmersiveRevealEnded() override { visible_fraction_ = 0; }
  69. void OnImmersiveFullscreenEntered() override {}
  70. void OnImmersiveFullscreenExited() override {
  71. enabled_ = false;
  72. visible_fraction_ = 1;
  73. }
  74. void SetVisibleFraction(double visible_fraction) override {
  75. visible_fraction_ = visible_fraction;
  76. }
  77. std::vector<gfx::Rect> GetVisibleBoundsInScreen() const override {
  78. std::vector<gfx::Rect> bounds_in_screen;
  79. bounds_in_screen.push_back(top_container_view_->GetBoundsInScreen());
  80. return bounds_in_screen;
  81. }
  82. bool is_enabled() const { return enabled_; }
  83. double visible_fraction() const { return visible_fraction_; }
  84. private:
  85. views::View* top_container_view_;
  86. bool enabled_;
  87. double visible_fraction_;
  88. };
  89. class ConsumeEventHandler : public ui::test::TestEventHandler {
  90. public:
  91. ConsumeEventHandler() = default;
  92. ConsumeEventHandler(const ConsumeEventHandler&) = delete;
  93. ConsumeEventHandler& operator=(const ConsumeEventHandler&) = delete;
  94. ~ConsumeEventHandler() override = default;
  95. private:
  96. void OnEvent(ui::Event* event) override {
  97. ui::test::TestEventHandler::OnEvent(event);
  98. if (event->cancelable())
  99. event->SetHandled();
  100. }
  101. };
  102. } // namespace
  103. /////////////////////////////////////////////////////////////////////////////
  104. class TestWidgetDelegate : public views::WidgetDelegateView {
  105. public:
  106. TestWidgetDelegate() {
  107. SetCanMaximize(true);
  108. SetCanResize(true);
  109. }
  110. TestWidgetDelegate(const TestWidgetDelegate&) = delete;
  111. TestWidgetDelegate& operator=(const TestWidgetDelegate&) = delete;
  112. ~TestWidgetDelegate() override = default;
  113. // views::WidgetDelegateView:
  114. bool CanActivate() const override { return true; }
  115. std::unique_ptr<views::NonClientFrameView> CreateNonClientFrameView(
  116. views::Widget* widget) override {
  117. return std::make_unique<NonClientFrameViewAsh>(widget);
  118. }
  119. };
  120. class ImmersiveFullscreenControllerTest : public AshTestBase {
  121. public:
  122. enum Modality {
  123. MODALITY_MOUSE,
  124. MODALITY_GESTURE_TAP,
  125. MODALITY_GESTURE_SCROLL
  126. };
  127. ImmersiveFullscreenControllerTest() = default;
  128. ImmersiveFullscreenControllerTest(const ImmersiveFullscreenControllerTest&) =
  129. delete;
  130. ImmersiveFullscreenControllerTest& operator=(
  131. const ImmersiveFullscreenControllerTest&) = delete;
  132. ~ImmersiveFullscreenControllerTest() override = default;
  133. ImmersiveFullscreenController* controller() {
  134. return ImmersiveFullscreenController::Get(widget());
  135. }
  136. views::NativeViewHost* content_view() { return content_view_; }
  137. SplitViewController* split_view_controller() {
  138. return SplitViewController::Get(Shell::GetPrimaryRootWindow());
  139. }
  140. views::View* top_container() {
  141. return NonClientFrameViewAsh::Get(window())->GetHeaderView();
  142. }
  143. views::Widget* widget() { return widget_; }
  144. aura::Window* window() { return widget_->GetNativeWindow(); }
  145. HeaderView* immersive_delegate() {
  146. return NonClientFrameViewAsh::Get(window())->GetHeaderView();
  147. }
  148. // Access to private data from the controller.
  149. bool top_edge_hover_timer_running() {
  150. return controller()->top_edge_hover_timer_.IsRunning();
  151. }
  152. int mouse_x_when_hit_top() {
  153. return controller()->mouse_x_when_hit_top_in_screen_;
  154. }
  155. // AshTestBase:
  156. void SetUp() override {
  157. AshTestBase::SetUp();
  158. test_api_animation_disabler_ = std::make_unique<
  159. ImmersiveFullscreenControllerTestApi::GlobalAnimationDisabler>();
  160. widget_ = new views::Widget();
  161. views::Widget::InitParams params;
  162. params.delegate = new TestWidgetDelegate();
  163. params.context = GetContext();
  164. widget_->Init(std::move(params));
  165. widget_->Show();
  166. SetWindowShowState(ui::SHOW_STATE_FULLSCREEN);
  167. gfx::Size window_size = widget_->GetWindowBoundsInScreen().size();
  168. content_view_ = new views::NativeViewHost();
  169. content_view_->SetBounds(0, 0, window_size.width(), window_size.height());
  170. widget_->GetContentsView()->AddChildView(content_view_);
  171. test_api_ =
  172. std::make_unique<ImmersiveFullscreenControllerTestApi>(controller());
  173. test_api_->SetupForTest();
  174. }
  175. // Enables / disables immersive fullscreen.
  176. void SetEnabled(bool enabled) {
  177. ImmersiveFullscreenController::EnableForWidget(widget_, enabled);
  178. }
  179. // Attempt to reveal the top-of-window views via |modality|.
  180. // The top-of-window views can only be revealed via mouse hover or a gesture.
  181. void AttemptReveal(Modality modality) {
  182. ASSERT_NE(modality, MODALITY_GESTURE_TAP);
  183. AttemptRevealStateChange(true, modality);
  184. }
  185. // Attempt to unreveal the top-of-window views via |modality|. The
  186. // top-of-window views can be unrevealed via any modality.
  187. void AttemptUnreveal(Modality modality) {
  188. AttemptRevealStateChange(false, modality);
  189. }
  190. // Sets whether the mouse is hovered above |top_container_|.
  191. // SetHovered(true) moves the mouse over the |top_container_| but does not
  192. // move it to the top of the screen so will not initiate a reveal.
  193. void SetHovered(bool is_mouse_hovered) {
  194. MoveMouse(0, is_mouse_hovered ? 10 : top_container()->height() + 100);
  195. }
  196. // Move the mouse to the given coordinates. The coordinates should be in
  197. // |top_container_| coordinates.
  198. void MoveMouse(int x, int y) {
  199. gfx::Point screen_position(x, y);
  200. views::View::ConvertPointToScreen(top_container(), &screen_position);
  201. GetEventGenerator()->MoveMouseTo(screen_position.x(), screen_position.y());
  202. // If the top edge timer started running as a result of the mouse move, run
  203. // the task which occurs after the timer delay. This reveals the
  204. // top-of-window views synchronously if the mouse is hovered at the top of
  205. // the screen.
  206. if (controller()->top_edge_hover_timer_.IsRunning()) {
  207. controller()->top_edge_hover_timer_.FireNow();
  208. }
  209. }
  210. void SetWindowShowState(ui::WindowShowState show_state) {
  211. window()->SetProperty(aura::client::kShowStateKey, show_state);
  212. }
  213. // Enable or disable tablet mode based on |enable|.
  214. void EnableTabletMode(bool enable) {
  215. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(enable);
  216. }
  217. private:
  218. // Attempt to change the revealed state to |revealed| via |modality|.
  219. void AttemptRevealStateChange(bool revealed, Modality modality) {
  220. // Compute the event position in |top_container()| coordinates.
  221. gfx::Point event_position(0,
  222. revealed ? 0 : top_container()->height() + 100);
  223. switch (modality) {
  224. case MODALITY_MOUSE: {
  225. MoveMouse(event_position.x(), event_position.y());
  226. break;
  227. }
  228. case MODALITY_GESTURE_TAP: {
  229. gfx::Point screen_position = event_position;
  230. views::View::ConvertPointToScreen(top_container(), &screen_position);
  231. ui::test::EventGenerator* event_generator = GetEventGenerator();
  232. event_generator->MoveTouch(event_position);
  233. event_generator->PressTouch();
  234. event_generator->ReleaseTouch();
  235. break;
  236. }
  237. case MODALITY_GESTURE_SCROLL: {
  238. gfx::Point start(0, revealed ? 0 : 2);
  239. gfx::Vector2d scroll_delta(0, 40);
  240. gfx::Point end = revealed ? start + scroll_delta : start - scroll_delta;
  241. views::View::ConvertPointToScreen(top_container(), &start);
  242. views::View::ConvertPointToScreen(top_container(), &end);
  243. ui::test::EventGenerator* event_generator = GetEventGenerator();
  244. event_generator->GestureScrollSequence(start, end,
  245. base::Milliseconds(30), 1);
  246. break;
  247. }
  248. }
  249. }
  250. std::unique_ptr<ImmersiveFullscreenControllerTestApi::GlobalAnimationDisabler>
  251. test_api_animation_disabler_;
  252. views::Widget* widget_ = nullptr; // Owned by the native widget.
  253. views::NativeViewHost* content_view_ =
  254. nullptr; // Owned by |widget_|'s root-view.
  255. std::unique_ptr<ImmersiveFullscreenControllerTestApi> test_api_;
  256. base::test::ScopedFeatureList scoped_feature_list_;
  257. };
  258. // Test the initial state and that the delegate gets notified of the
  259. // top-of-window views getting hidden and revealed.
  260. TEST_F(ImmersiveFullscreenControllerTest, Delegate) {
  261. SetWindowShowState(ui::SHOW_STATE_MAXIMIZED);
  262. // Initial state.
  263. EXPECT_FALSE(controller()->IsEnabled());
  264. EXPECT_FALSE(controller()->IsRevealed());
  265. EXPECT_FALSE(immersive_delegate()->in_immersive_mode());
  266. // Enabling initially hides the top views.
  267. SetEnabled(true);
  268. EXPECT_TRUE(controller()->IsEnabled());
  269. EXPECT_FALSE(controller()->IsRevealed());
  270. EXPECT_TRUE(immersive_delegate()->in_immersive_mode());
  271. EXPECT_FALSE(immersive_delegate()->is_revealed());
  272. // Revealing shows the top views.
  273. AttemptReveal(MODALITY_MOUSE);
  274. EXPECT_TRUE(controller()->IsEnabled());
  275. EXPECT_TRUE(controller()->IsRevealed());
  276. EXPECT_TRUE(immersive_delegate()->in_immersive_mode());
  277. EXPECT_TRUE(immersive_delegate()->is_revealed());
  278. // Disabling ends the immersive reveal.
  279. SetEnabled(false);
  280. EXPECT_FALSE(controller()->IsEnabled());
  281. EXPECT_FALSE(controller()->IsRevealed());
  282. EXPECT_FALSE(immersive_delegate()->in_immersive_mode());
  283. }
  284. // GetRevealedLock() specific tests.
  285. TEST_F(ImmersiveFullscreenControllerTest, RevealedLock) {
  286. SetWindowShowState(ui::SHOW_STATE_MAXIMIZED);
  287. std::unique_ptr<ImmersiveRevealedLock> lock1;
  288. std::unique_ptr<ImmersiveRevealedLock> lock2;
  289. // Immersive fullscreen is not on by default.
  290. EXPECT_FALSE(controller()->IsEnabled());
  291. // 1) Test acquiring and releasing a revealed state lock while immersive
  292. // fullscreen is disabled. Acquiring or releasing the lock should have no
  293. // effect till immersive fullscreen is enabled.
  294. lock1.reset(controller()->GetRevealedLock(
  295. ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
  296. EXPECT_FALSE(controller()->IsEnabled());
  297. EXPECT_FALSE(controller()->IsRevealed());
  298. // Immersive fullscreen should start in the revealed state due to the lock.
  299. SetEnabled(true);
  300. EXPECT_TRUE(controller()->IsEnabled());
  301. EXPECT_TRUE(controller()->IsRevealed());
  302. SetEnabled(false);
  303. EXPECT_FALSE(controller()->IsEnabled());
  304. EXPECT_FALSE(controller()->IsRevealed());
  305. lock1.reset();
  306. EXPECT_FALSE(controller()->IsEnabled());
  307. EXPECT_FALSE(controller()->IsRevealed());
  308. // Immersive fullscreen should start in the closed state because the lock is
  309. // no longer held.
  310. SetEnabled(true);
  311. EXPECT_TRUE(controller()->IsEnabled());
  312. EXPECT_FALSE(controller()->IsRevealed());
  313. // 2) Test that acquiring a lock reveals the top-of-window views if they are
  314. // hidden.
  315. lock1.reset(controller()->GetRevealedLock(
  316. ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
  317. EXPECT_TRUE(controller()->IsRevealed());
  318. // Move the mouse below the top container bounds so the hover doesn't make the
  319. // reveal persist.
  320. MoveMouse(0, top_container()->GetBoundsInScreen().bottom() + 10);
  321. // 3) Test that the top-of-window views are only hidden when all of the locks
  322. // are released.
  323. lock2.reset(controller()->GetRevealedLock(
  324. ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
  325. lock1.reset();
  326. EXPECT_TRUE(controller()->IsRevealed());
  327. lock2.reset();
  328. EXPECT_FALSE(controller()->IsRevealed());
  329. }
  330. // Test mouse event processing for top-of-screen reveal triggering.
  331. TEST_F(ImmersiveFullscreenControllerTest, OnMouseEvent) {
  332. // Create 2nd display for off screen test.
  333. UpdateDisplay("800x600, 800x600");
  334. // Set up initial state.
  335. SetEnabled(true);
  336. ASSERT_TRUE(controller()->IsEnabled());
  337. ASSERT_FALSE(controller()->IsRevealed());
  338. ui::test::EventGenerator* event_generator = GetEventGenerator();
  339. gfx::Rect top_container_bounds_in_screen =
  340. top_container()->GetBoundsInScreen();
  341. // A position along the top edge of TopContainerView in screen coordinates.
  342. gfx::Point top_edge_pos(top_container_bounds_in_screen.x() + 100,
  343. top_container_bounds_in_screen.y());
  344. // Mouse wheel event does nothing.
  345. ui::MouseWheelEvent wheel(gfx::Vector2d(), top_edge_pos, top_edge_pos,
  346. ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
  347. event_generator->Dispatch(&wheel);
  348. EXPECT_FALSE(top_edge_hover_timer_running());
  349. // Move to top edge of screen starts hover timer running. We cannot use
  350. // MoveMouse() because MoveMouse() stops the timer if it started running.
  351. event_generator->MoveMouseTo(top_edge_pos);
  352. EXPECT_TRUE(top_edge_hover_timer_running());
  353. EXPECT_EQ(top_edge_pos.x(), mouse_x_when_hit_top());
  354. // Moving |ImmersiveFullscreenControllerTest::kMouseRevealBoundsHeight| down
  355. // from the top edge stops it.
  356. event_generator->MoveMouseBy(
  357. 0, ImmersiveFullscreenController::kMouseRevealBoundsHeight);
  358. EXPECT_FALSE(top_edge_hover_timer_running());
  359. // Moving back to the top starts the timer again.
  360. event_generator->MoveMouseTo(top_edge_pos);
  361. EXPECT_TRUE(top_edge_hover_timer_running());
  362. EXPECT_EQ(top_edge_pos.x(), mouse_x_when_hit_top());
  363. // Slight move to the right keeps the timer running for the same hit point.
  364. event_generator->MoveMouseBy(1, 0);
  365. EXPECT_TRUE(top_edge_hover_timer_running());
  366. EXPECT_EQ(top_edge_pos.x(), mouse_x_when_hit_top());
  367. // Moving back to the left also keeps the timer running.
  368. event_generator->MoveMouseBy(-1, 0);
  369. EXPECT_TRUE(top_edge_hover_timer_running());
  370. EXPECT_EQ(top_edge_pos.x(), mouse_x_when_hit_top());
  371. // Large move right restarts the timer (so it is still running) and considers
  372. // this a new hit at the top.
  373. event_generator->MoveMouseTo(top_edge_pos.x() + 100, top_edge_pos.y());
  374. EXPECT_TRUE(top_edge_hover_timer_running());
  375. EXPECT_EQ(top_edge_pos.x() + 100, mouse_x_when_hit_top());
  376. // Moving off the top edge horizontally stops the timer.
  377. event_generator->MoveMouseTo(top_container_bounds_in_screen.right() + 1,
  378. top_container_bounds_in_screen.y());
  379. EXPECT_FALSE(top_edge_hover_timer_running());
  380. // Once revealed, a move just a little below the top container doesn't end a
  381. // reveal.
  382. AttemptReveal(MODALITY_MOUSE);
  383. event_generator->MoveMouseTo(top_container_bounds_in_screen.x(),
  384. top_container_bounds_in_screen.bottom() + 1);
  385. EXPECT_TRUE(controller()->IsRevealed());
  386. // Once revealed, clicking just below the top container ends the reveal.
  387. event_generator->ClickLeftButton();
  388. EXPECT_FALSE(controller()->IsRevealed());
  389. // Moving a lot below the top container ends a reveal.
  390. AttemptReveal(MODALITY_MOUSE);
  391. EXPECT_TRUE(controller()->IsRevealed());
  392. event_generator->MoveMouseTo(top_container_bounds_in_screen.x(),
  393. top_container_bounds_in_screen.bottom() + 50);
  394. EXPECT_FALSE(controller()->IsRevealed());
  395. // The mouse position cannot cause a reveal when the top container's widget
  396. // has capture.
  397. views::Widget* widget = top_container()->GetWidget();
  398. widget->SetCapture(top_container());
  399. AttemptReveal(MODALITY_MOUSE);
  400. EXPECT_FALSE(controller()->IsRevealed());
  401. widget->ReleaseCapture();
  402. // The mouse position cannot end the reveal while the top container's widget
  403. // has capture.
  404. AttemptReveal(MODALITY_MOUSE);
  405. EXPECT_TRUE(controller()->IsRevealed());
  406. widget->SetCapture(top_container());
  407. event_generator->MoveMouseTo(top_container_bounds_in_screen.x(),
  408. top_container_bounds_in_screen.bottom() + 51);
  409. EXPECT_TRUE(controller()->IsRevealed());
  410. // Releasing capture should end the reveal.
  411. widget->ReleaseCapture();
  412. EXPECT_FALSE(controller()->IsRevealed());
  413. }
  414. // Test mouse event processing for top-of-screen reveal triggering when the
  415. // top container's widget is inactive.
  416. TEST_F(ImmersiveFullscreenControllerTest, Inactive) {
  417. // Set up initial state.
  418. views::Widget* popup_widget = views::Widget::CreateWindowWithContext(
  419. nullptr, GetContext(), gfx::Rect(0, 0, 200, 200));
  420. popup_widget->Show();
  421. ASSERT_FALSE(top_container()->GetWidget()->IsActive());
  422. SetEnabled(true);
  423. ASSERT_TRUE(controller()->IsEnabled());
  424. ASSERT_FALSE(controller()->IsRevealed());
  425. gfx::Rect top_container_bounds_in_screen =
  426. top_container()->GetBoundsInScreen();
  427. gfx::Rect popup_bounds_in_screen = popup_widget->GetWindowBoundsInScreen();
  428. ASSERT_EQ(top_container_bounds_in_screen.origin().ToString(),
  429. popup_bounds_in_screen.origin().ToString());
  430. ASSERT_GT(top_container_bounds_in_screen.right(),
  431. popup_bounds_in_screen.right());
  432. // The top-of-window views should stay hidden if the cursor is at the top edge
  433. // but above an obscured portion of the top-of-window views.
  434. MoveMouse(popup_bounds_in_screen.x(), top_container_bounds_in_screen.y());
  435. EXPECT_FALSE(controller()->IsRevealed());
  436. // The top-of-window views should reveal if the cursor is at the top edge and
  437. // above an unobscured portion of the top-of-window views.
  438. MoveMouse(top_container_bounds_in_screen.right() - 1,
  439. top_container_bounds_in_screen.y());
  440. EXPECT_TRUE(controller()->IsRevealed());
  441. // The top-of-window views should stay revealed if the cursor is moved off
  442. // of the top edge.
  443. MoveMouse(top_container_bounds_in_screen.right() - 1,
  444. top_container_bounds_in_screen.bottom() - 1);
  445. EXPECT_TRUE(controller()->IsRevealed());
  446. // Moving way off of the top-of-window views should end the immersive reveal.
  447. MoveMouse(top_container_bounds_in_screen.right() - 1,
  448. top_container_bounds_in_screen.bottom() + 50);
  449. EXPECT_FALSE(controller()->IsRevealed());
  450. // Moving way off of the top-of-window views in a region where the
  451. // top-of-window views are obscured should also end the immersive reveal.
  452. // Ideally, the immersive reveal would end immediately when the cursor moves
  453. // to an obscured portion of the top-of-window views.
  454. MoveMouse(top_container_bounds_in_screen.right() - 1,
  455. top_container_bounds_in_screen.y());
  456. EXPECT_TRUE(controller()->IsRevealed());
  457. MoveMouse(top_container_bounds_in_screen.x(),
  458. top_container_bounds_in_screen.bottom() + 50);
  459. EXPECT_FALSE(controller()->IsRevealed());
  460. }
  461. // Test mouse event processing for top-of-screen reveal triggering when the user
  462. // has a vertical display layout (primary display above/below secondary display)
  463. // and the immersive fullscreen window is on the bottom display.
  464. TEST_F(ImmersiveFullscreenControllerTest, MouseEventsVerticalDisplayLayout) {
  465. // Set up initial state.
  466. UpdateDisplay("800x600,800x600");
  467. Shell::Get()->display_manager()->SetLayoutForCurrentDisplays(
  468. display::test::CreateDisplayLayout(display_manager(),
  469. display::DisplayPlacement::TOP, 0));
  470. SetEnabled(true);
  471. ASSERT_TRUE(controller()->IsEnabled());
  472. ASSERT_FALSE(controller()->IsRevealed());
  473. aura::Window::Windows root_windows = Shell::GetAllRootWindows();
  474. ASSERT_EQ(root_windows[0],
  475. top_container()->GetWidget()->GetNativeWindow()->GetRootWindow());
  476. gfx::Rect primary_root_window_bounds_in_screen =
  477. root_windows[0]->GetBoundsInScreen();
  478. // Do not set |x| to the root window's x position because the display's
  479. // corners have special behavior.
  480. int x = primary_root_window_bounds_in_screen.x() + 10;
  481. // The y position of the top edge of the primary display.
  482. int y_top_edge = primary_root_window_bounds_in_screen.y();
  483. ui::test::EventGenerator* event_generator = GetEventGenerator();
  484. // Moving right below the top edge starts the hover timer running. We
  485. // cannot use MoveMouse() because MoveMouse() stops the timer if it started
  486. // running.
  487. event_generator->MoveMouseTo(x, y_top_edge + 1);
  488. EXPECT_TRUE(top_edge_hover_timer_running());
  489. EXPECT_EQ(y_top_edge + 1,
  490. aura::Env::GetInstance()->last_mouse_location().y());
  491. // The timer should continue running if the user moves the mouse to the top
  492. // edge even though the mouse is warped to the secondary display.
  493. event_generator->MoveMouseTo(x, y_top_edge);
  494. EXPECT_TRUE(top_edge_hover_timer_running());
  495. // The timer should continue running if the user overshoots the top edge
  496. // a bit.
  497. event_generator->MoveMouseTo(x, y_top_edge - 2);
  498. EXPECT_TRUE(top_edge_hover_timer_running());
  499. // The timer should stop running if the user overshoots the top edge by
  500. // a lot.
  501. event_generator->MoveMouseTo(x, y_top_edge - 20);
  502. EXPECT_FALSE(top_edge_hover_timer_running());
  503. // The timer should not start if the user moves the mouse to the bottom of the
  504. // secondary display without crossing the top edge first.
  505. event_generator->MoveMouseTo(x, y_top_edge - 2);
  506. // Reveal the top-of-window views by overshooting the top edge slightly.
  507. event_generator->MoveMouseTo(x, y_top_edge + 1);
  508. // MoveMouse() runs the timer task.
  509. MoveMouse(x, y_top_edge - 2);
  510. EXPECT_TRUE(controller()->IsRevealed());
  511. // The top-of-window views should stay revealed if the user moves the mouse
  512. // around in the bottom region of the secondary display.
  513. event_generator->MoveMouseTo(x + 10, y_top_edge - 3);
  514. EXPECT_TRUE(controller()->IsRevealed());
  515. // The top-of-window views should hide if the user moves the mouse away from
  516. // the bottom region of the secondary display.
  517. event_generator->MoveMouseTo(x, y_top_edge - 20);
  518. EXPECT_FALSE(controller()->IsRevealed());
  519. // Test that it is possible to reveal the top-of-window views by overshooting
  520. // the top edge slightly when the top container's widget is not active.
  521. views::Widget* popup_widget = views::Widget::CreateWindowWithContext(
  522. nullptr, GetContext(), gfx::Rect(0, 200, 100, 100));
  523. popup_widget->Show();
  524. ASSERT_FALSE(top_container()->GetWidget()->IsActive());
  525. ASSERT_FALSE(top_container()->GetBoundsInScreen().Intersects(
  526. popup_widget->GetWindowBoundsInScreen()));
  527. event_generator->MoveMouseTo(x, y_top_edge + 1);
  528. MoveMouse(x, y_top_edge - 2);
  529. EXPECT_TRUE(controller()->IsRevealed());
  530. }
  531. // Test behavior when the mouse becomes hovered without moving.
  532. TEST_F(ImmersiveFullscreenControllerTest, MouseHoveredWithoutMoving) {
  533. SetEnabled(true);
  534. std::unique_ptr<ImmersiveRevealedLock> lock;
  535. // 1) Test that if the mouse becomes hovered without the mouse moving due to a
  536. // lock causing the top-of-window views to be revealed (and the mouse
  537. // happening to be near the top of the screen), the top-of-window views do not
  538. // hide till the mouse moves off of the top-of-window views.
  539. SetHovered(true);
  540. EXPECT_FALSE(controller()->IsRevealed());
  541. lock.reset(controller()->GetRevealedLock(
  542. ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
  543. EXPECT_TRUE(controller()->IsRevealed());
  544. lock.reset();
  545. EXPECT_TRUE(controller()->IsRevealed());
  546. SetHovered(false);
  547. EXPECT_FALSE(controller()->IsRevealed());
  548. // 2) Test that if the mouse becomes hovered without moving because of a
  549. // reveal in ImmersiveFullscreenController::SetEnabled(true) and there are no
  550. // locks keeping the top-of-window views revealed, that mouse hover does not
  551. // prevent the top-of-window views from closing.
  552. SetEnabled(false);
  553. SetHovered(true);
  554. EXPECT_FALSE(controller()->IsRevealed());
  555. SetEnabled(true);
  556. EXPECT_FALSE(controller()->IsRevealed());
  557. // 3) Test that if the mouse becomes hovered without moving because of a
  558. // reveal in ImmersiveFullscreenController::SetEnabled(true) and there is a
  559. // lock keeping the top-of-window views revealed, that the top-of-window views
  560. // do not hide till the mouse moves off of the top-of-window views.
  561. SetEnabled(false);
  562. SetHovered(true);
  563. lock.reset(controller()->GetRevealedLock(
  564. ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
  565. EXPECT_FALSE(controller()->IsRevealed());
  566. SetEnabled(true);
  567. EXPECT_TRUE(controller()->IsRevealed());
  568. lock.reset();
  569. EXPECT_TRUE(controller()->IsRevealed());
  570. SetHovered(false);
  571. EXPECT_FALSE(controller()->IsRevealed());
  572. }
  573. // Test revealing the top-of-window views using one modality and ending
  574. // the reveal via another. For instance, initiating the reveal via a SWIPE_OPEN
  575. // edge gesture, switching to using the mouse and ending the reveal by moving
  576. // the mouse off of the top-of-window views.
  577. TEST_F(ImmersiveFullscreenControllerTest, DifferentModalityEnterExit) {
  578. SetEnabled(true);
  579. EXPECT_TRUE(controller()->IsEnabled());
  580. EXPECT_FALSE(controller()->IsRevealed());
  581. // Initiate reveal via gesture, end reveal via mouse.
  582. AttemptReveal(MODALITY_GESTURE_SCROLL);
  583. EXPECT_TRUE(controller()->IsRevealed());
  584. MoveMouse(1, 1);
  585. EXPECT_TRUE(controller()->IsRevealed());
  586. AttemptUnreveal(MODALITY_MOUSE);
  587. EXPECT_FALSE(controller()->IsRevealed());
  588. // Initiate reveal via gesture, end reveal via touch.
  589. AttemptReveal(MODALITY_GESTURE_SCROLL);
  590. EXPECT_TRUE(controller()->IsRevealed());
  591. AttemptUnreveal(MODALITY_GESTURE_TAP);
  592. EXPECT_FALSE(controller()->IsRevealed());
  593. // Initiate reveal via mouse, end reveal via gesture.
  594. AttemptReveal(MODALITY_MOUSE);
  595. EXPECT_TRUE(controller()->IsRevealed());
  596. AttemptUnreveal(MODALITY_GESTURE_SCROLL);
  597. EXPECT_FALSE(controller()->IsRevealed());
  598. // Initiate reveal via mouse, end reveal via touch.
  599. AttemptReveal(MODALITY_MOUSE);
  600. EXPECT_TRUE(controller()->IsRevealed());
  601. AttemptUnreveal(MODALITY_GESTURE_TAP);
  602. EXPECT_FALSE(controller()->IsRevealed());
  603. }
  604. // Tests the top-of-window views for maximized/full-screened/snapped windows in
  605. // tablet mode.
  606. TEST_F(ImmersiveFullscreenControllerTest, WindowsInTabletMode) {
  607. EnableTabletMode(true);
  608. SetEnabled(true);
  609. EXPECT_TRUE(controller()->IsEnabled());
  610. EXPECT_FALSE(controller()->IsRevealed());
  611. // Top-of-window views will not be revealed through gesture scroll for
  612. // fullscreen window in tablet mode. (Instead, the window is dragged.)
  613. AttemptReveal(MODALITY_GESTURE_SCROLL);
  614. EXPECT_FALSE(controller()->IsRevealed());
  615. // Top-of-window views will be revealed for fullscreen windows not in tablet
  616. // mode.
  617. EnableTabletMode(false);
  618. AttemptReveal(MODALITY_GESTURE_SCROLL);
  619. EXPECT_TRUE(controller()->IsRevealed());
  620. AttemptUnreveal(MODALITY_GESTURE_SCROLL);
  621. EXPECT_FALSE(controller()->IsRevealed());
  622. // Top-of-window views will not be revealed for full-screened window in tablet
  623. // mode either.
  624. EnableTabletMode(true);
  625. SetWindowShowState(ui::SHOW_STATE_FULLSCREEN);
  626. AttemptReveal(MODALITY_GESTURE_SCROLL);
  627. EXPECT_FALSE(controller()->IsRevealed());
  628. // Top-of-window views will not be revealed for snapped window in splitview
  629. // mode either.
  630. split_view_controller()->SnapWindow(window(), SplitViewController::LEFT);
  631. EXPECT_TRUE(WindowState::Get(window())->IsSnapped());
  632. EXPECT_TRUE(split_view_controller()->InSplitViewMode());
  633. AttemptReveal(MODALITY_GESTURE_SCROLL);
  634. EXPECT_FALSE(controller()->IsRevealed());
  635. }
  636. // Test when the SWIPE_CLOSE edge gesture closes the top-of-window views.
  637. TEST_F(ImmersiveFullscreenControllerTest, EndRevealViaGesture) {
  638. SetEnabled(true);
  639. EXPECT_TRUE(controller()->IsEnabled());
  640. EXPECT_FALSE(controller()->IsRevealed());
  641. // A gesture should be able to close the top-of-window views when
  642. // top-of-window views have focus.
  643. AttemptReveal(MODALITY_MOUSE);
  644. top_container()->RequestFocus();
  645. EXPECT_TRUE(controller()->IsRevealed());
  646. AttemptUnreveal(MODALITY_GESTURE_SCROLL);
  647. EXPECT_FALSE(controller()->IsRevealed());
  648. // The top-of-window views should no longer have focus. Clearing focus is
  649. // important because it closes focus-related popup windows like the touch
  650. // selection handles.
  651. EXPECT_FALSE(top_container()->HasFocus());
  652. // If some other code is holding onto a lock, a gesture should not be able to
  653. // end the reveal.
  654. AttemptReveal(MODALITY_MOUSE);
  655. std::unique_ptr<ImmersiveRevealedLock> lock(controller()->GetRevealedLock(
  656. ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
  657. EXPECT_TRUE(controller()->IsRevealed());
  658. AttemptUnreveal(MODALITY_GESTURE_SCROLL);
  659. EXPECT_TRUE(controller()->IsRevealed());
  660. lock.reset();
  661. EXPECT_FALSE(controller()->IsRevealed());
  662. }
  663. // Tests that touch-gesture can be used to reveal the top-of-window views when
  664. // the child window consumes all events.
  665. TEST_F(ImmersiveFullscreenControllerTest, RevealViaGestureChildConsumesEvents) {
  666. // Enabling initially hides the top views.
  667. SetEnabled(true);
  668. EXPECT_TRUE(controller()->IsEnabled());
  669. EXPECT_FALSE(controller()->IsRevealed());
  670. aura::test::TestWindowDelegate child_delegate;
  671. std::unique_ptr<aura::Window> child(
  672. CreateTestWindowInShellWithDelegateAndType(
  673. &child_delegate, aura::client::WINDOW_TYPE_CONTROL, 1234,
  674. gfx::Rect()));
  675. content_view()->Attach(child.get());
  676. content_view()->Layout();
  677. ConsumeEventHandler handler;
  678. child->AddPreTargetHandler(&handler);
  679. // Reveal the top views using a touch-scroll gesture. The child window should
  680. // not receive the touch events.
  681. AttemptReveal(MODALITY_GESTURE_SCROLL);
  682. EXPECT_TRUE(controller()->IsRevealed());
  683. EXPECT_EQ(0, handler.num_touch_events());
  684. AttemptUnreveal(MODALITY_GESTURE_TAP);
  685. EXPECT_FALSE(controller()->IsRevealed());
  686. EXPECT_GT(handler.num_touch_events(), 0);
  687. child->RemovePreTargetHandler(&handler);
  688. }
  689. // Make sure touch events towards the top of the window do not leak through to
  690. // windows underneath.
  691. TEST_F(ImmersiveFullscreenControllerTest, EventsDoNotLeakToWindowUnderneath) {
  692. gfx::Rect window_bounds = window()->GetBoundsInScreen();
  693. aura::test::TestWindowDelegate child_delegate;
  694. std::unique_ptr<aura::Window> behind(CreateTestWindowInShellWithDelegate(
  695. &child_delegate, 1234, window_bounds));
  696. behind->Show();
  697. behind->SetBounds(window_bounds);
  698. widget()->StackAbove(behind.get());
  699. // Make sure the windows are aligned on top.
  700. EXPECT_EQ(behind->GetBoundsInScreen().y(), window()->GetBoundsInScreen().y());
  701. int top = behind->GetBoundsInScreen().y();
  702. ui::TouchEvent touch(ui::ET_TOUCH_MOVED, gfx::Point(10, top),
  703. ui::EventTimeForNow(),
  704. ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  705. aura::Window* root = window()->GetRootWindow();
  706. ui::EventTargeter* targeter =
  707. root->GetHost()->dispatcher()->GetDefaultEventTargeter();
  708. EXPECT_EQ(window(), targeter->FindTargetForEvent(root, &touch));
  709. SetEnabled(true);
  710. EXPECT_FALSE(controller()->IsRevealed());
  711. // Make sure the windows are still aligned on top.
  712. EXPECT_EQ(behind->GetBoundsInScreen().y(), window()->GetBoundsInScreen().y());
  713. top = behind->GetBoundsInScreen().y();
  714. ui::TouchEvent touch2(ui::ET_TOUCH_MOVED, gfx::Point(10, top),
  715. ui::EventTimeForNow(),
  716. ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  717. // The event should still be targeted to window().
  718. EXPECT_EQ(window(), targeter->FindTargetForEvent(root, &touch2));
  719. }
  720. // Check that the window state gets properly marked for immersive fullscreen.
  721. TEST_F(ImmersiveFullscreenControllerTest, WindowStateImmersiveFullscreen) {
  722. WindowState* window_state = WindowState::Get(window());
  723. SetWindowShowState(ui::SHOW_STATE_NORMAL);
  724. EXPECT_FALSE(window_state->IsInImmersiveFullscreen());
  725. SetEnabled(true);
  726. ASSERT_TRUE(controller()->IsEnabled());
  727. EXPECT_TRUE(window_state->IsInImmersiveFullscreen());
  728. SetEnabled(false);
  729. ASSERT_FALSE(controller()->IsEnabled());
  730. EXPECT_FALSE(window_state->IsInImmersiveFullscreen());
  731. }
  732. // Test how focus and activation affects whether the top-of-window views are
  733. // revealed.
  734. TEST_F(ImmersiveFullscreenControllerTest, Focus) {
  735. // Add views to the view hierarchy which we will focus and unfocus during the
  736. // test.
  737. views::View* child_view = new views::View();
  738. child_view->SetBounds(0, 0, 10, 10);
  739. child_view->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
  740. top_container()->AddChildView(child_view);
  741. views::View* unrelated_view = new views::View();
  742. unrelated_view->SetBounds(0, 100, 10, 10);
  743. unrelated_view->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
  744. top_container()->parent()->AddChildView(unrelated_view);
  745. views::FocusManager* focus_manager =
  746. top_container()->GetWidget()->GetFocusManager();
  747. SetEnabled(true);
  748. // 1) Test that the top-of-window views stay revealed as long as either a
  749. // |child_view| has focus or the mouse is hovered above the top-of-window
  750. // views.
  751. AttemptReveal(MODALITY_MOUSE);
  752. child_view->RequestFocus();
  753. focus_manager->ClearFocus();
  754. EXPECT_TRUE(controller()->IsRevealed());
  755. child_view->RequestFocus();
  756. SetHovered(false);
  757. EXPECT_TRUE(controller()->IsRevealed());
  758. focus_manager->ClearFocus();
  759. EXPECT_FALSE(controller()->IsRevealed());
  760. // 2) Test that focusing |unrelated_view| hides the top-of-window views.
  761. AttemptReveal(MODALITY_MOUSE);
  762. child_view->RequestFocus();
  763. SetHovered(false);
  764. EXPECT_TRUE(controller()->IsRevealed());
  765. unrelated_view->RequestFocus();
  766. EXPECT_FALSE(controller()->IsRevealed());
  767. // 3) Test that a loss of focus of |child_view| to |unrelated_view|
  768. // while immersive mode is disabled is properly registered.
  769. AttemptReveal(MODALITY_MOUSE);
  770. child_view->RequestFocus();
  771. SetHovered(false);
  772. EXPECT_TRUE(controller()->IsRevealed());
  773. SetEnabled(false);
  774. EXPECT_FALSE(controller()->IsRevealed());
  775. unrelated_view->RequestFocus();
  776. SetEnabled(true);
  777. EXPECT_FALSE(controller()->IsRevealed());
  778. // Repeat test but with a revealed lock acquired when immersive mode is
  779. // disabled because the code path is different.
  780. AttemptReveal(MODALITY_MOUSE);
  781. child_view->RequestFocus();
  782. SetHovered(false);
  783. EXPECT_TRUE(controller()->IsRevealed());
  784. SetEnabled(false);
  785. std::unique_ptr<ImmersiveRevealedLock> lock(controller()->GetRevealedLock(
  786. ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
  787. EXPECT_FALSE(controller()->IsRevealed());
  788. unrelated_view->RequestFocus();
  789. SetEnabled(true);
  790. EXPECT_TRUE(controller()->IsRevealed());
  791. lock.reset();
  792. EXPECT_FALSE(controller()->IsRevealed());
  793. }
  794. // Test how transient windows affect whether the top-of-window views are
  795. // revealed.
  796. TEST_F(ImmersiveFullscreenControllerTest, Transient) {
  797. views::Widget* top_container_widget = top_container()->GetWidget();
  798. SetEnabled(true);
  799. ASSERT_FALSE(controller()->IsRevealed());
  800. // 1) Test that a transient window which is not a bubble does not trigger a
  801. // reveal but does keep the top-of-window views revealed if they are already
  802. // revealed.
  803. views::Widget::InitParams transient_params;
  804. transient_params.ownership =
  805. views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  806. transient_params.parent = top_container_widget->GetNativeView();
  807. transient_params.bounds = gfx::Rect(0, 100, 100, 100);
  808. std::unique_ptr<views::Widget> transient_widget(new views::Widget());
  809. transient_widget->Init(std::move(transient_params));
  810. EXPECT_FALSE(controller()->IsRevealed());
  811. AttemptReveal(MODALITY_MOUSE);
  812. EXPECT_TRUE(controller()->IsRevealed());
  813. transient_widget->Show();
  814. SetHovered(false);
  815. EXPECT_TRUE(controller()->IsRevealed());
  816. transient_widget.reset();
  817. EXPECT_FALSE(controller()->IsRevealed());
  818. // 2) Test that activating a non-transient window does not keep the
  819. // top-of-window views revealed.
  820. views::Widget::InitParams non_transient_params;
  821. non_transient_params.ownership =
  822. views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  823. non_transient_params.bounds = gfx::Rect(0, 100, 100, 100);
  824. std::unique_ptr<views::Widget> non_transient_widget(new views::Widget());
  825. non_transient_params.context = GetContext();
  826. non_transient_widget->Init(std::move(non_transient_params));
  827. EXPECT_FALSE(controller()->IsRevealed());
  828. AttemptReveal(MODALITY_MOUSE);
  829. EXPECT_TRUE(controller()->IsRevealed());
  830. non_transient_widget->Show();
  831. SetHovered(false);
  832. EXPECT_FALSE(controller()->IsRevealed());
  833. }
  834. // Test how bubbles affect whether the top-of-window views are revealed.
  835. TEST_F(ImmersiveFullscreenControllerTest, Bubbles) {
  836. std::unique_ptr<ImmersiveRevealedLock> revealed_lock;
  837. views::Widget* top_container_widget = top_container()->GetWidget();
  838. // Add views to the view hierarchy to which we will anchor bubbles.
  839. views::View* child_view = new views::View();
  840. child_view->SetBounds(0, 0, 10, 10);
  841. top_container()->AddChildView(child_view);
  842. views::View* unrelated_view = new views::View();
  843. unrelated_view->SetBounds(0, 100, 10, 10);
  844. top_container()->parent()->AddChildView(unrelated_view);
  845. SetEnabled(true);
  846. ASSERT_FALSE(controller()->IsRevealed());
  847. // 1) Test that a bubble anchored to a child of the top container triggers
  848. // a reveal and keeps the top-of-window views revealed for the duration of
  849. // its visibility.
  850. views::Widget* bubble_widget1(views::BubbleDialogDelegateView::CreateBubble(
  851. new TestBubbleDialogDelegate(child_view)));
  852. bubble_widget1->Show();
  853. EXPECT_TRUE(controller()->IsRevealed());
  854. // Activating |top_container_widget| will close |bubble_widget1|.
  855. top_container_widget->Activate();
  856. AttemptReveal(MODALITY_MOUSE);
  857. revealed_lock.reset(controller()->GetRevealedLock(
  858. ImmersiveFullscreenController::ANIMATE_REVEAL_NO));
  859. EXPECT_TRUE(controller()->IsRevealed());
  860. views::Widget* bubble_widget2 = views::BubbleDialogDelegateView::CreateBubble(
  861. new TestBubbleDialogDelegate(child_view));
  862. bubble_widget2->Show();
  863. EXPECT_TRUE(controller()->IsRevealed());
  864. revealed_lock.reset();
  865. SetHovered(false);
  866. EXPECT_TRUE(controller()->IsRevealed());
  867. bubble_widget2->Close();
  868. EXPECT_FALSE(controller()->IsRevealed());
  869. // 2) Test that transitioning from keeping the top-of-window views revealed
  870. // because of a bubble to keeping the top-of-window views revealed because of
  871. // mouse hover by activating |top_container_widget| works.
  872. views::Widget* bubble_widget3 = views::BubbleDialogDelegateView::CreateBubble(
  873. new TestBubbleDialogDelegate(child_view));
  874. bubble_widget3->Show();
  875. SetHovered(true);
  876. EXPECT_TRUE(controller()->IsRevealed());
  877. top_container_widget->Activate();
  878. EXPECT_TRUE(controller()->IsRevealed());
  879. // 3) Test that the top-of-window views stay revealed as long as at least one
  880. // bubble anchored to a child of the top container is visible.
  881. SetHovered(false);
  882. EXPECT_FALSE(controller()->IsRevealed());
  883. views::BubbleDialogDelegateView* bubble_delegate4(
  884. new TestBubbleDialogDelegate(child_view));
  885. bubble_delegate4->SetCanActivate(false);
  886. views::Widget* bubble_widget4(
  887. views::BubbleDialogDelegateView::CreateBubble(bubble_delegate4));
  888. bubble_widget4->Show();
  889. views::BubbleDialogDelegateView* bubble_delegate5(
  890. new TestBubbleDialogDelegate(child_view));
  891. bubble_delegate5->SetCanActivate(false);
  892. views::Widget* bubble_widget5(
  893. views::BubbleDialogDelegateView::CreateBubble(bubble_delegate5));
  894. bubble_widget5->Show();
  895. EXPECT_TRUE(controller()->IsRevealed());
  896. bubble_widget4->Hide();
  897. EXPECT_TRUE(controller()->IsRevealed());
  898. bubble_widget5->Hide();
  899. EXPECT_FALSE(controller()->IsRevealed());
  900. bubble_widget5->Show();
  901. EXPECT_TRUE(controller()->IsRevealed());
  902. // 4) Test that visibility changes which occur while immersive fullscreen is
  903. // disabled are handled upon reenabling immersive fullscreen.
  904. SetEnabled(false);
  905. bubble_widget5->Hide();
  906. SetEnabled(true);
  907. EXPECT_FALSE(controller()->IsRevealed());
  908. // We do not need |bubble_widget4| or |bubble_widget5| anymore, close them.
  909. bubble_widget4->Close();
  910. bubble_widget5->Close();
  911. // 5) Test that a bubble added while immersive fullscreen is disabled is
  912. // handled upon reenabling immersive fullscreen.
  913. SetEnabled(false);
  914. views::Widget* bubble_widget6 = views::BubbleDialogDelegateView::CreateBubble(
  915. new TestBubbleDialogDelegate(child_view));
  916. bubble_widget6->Show();
  917. SetEnabled(true);
  918. EXPECT_TRUE(controller()->IsRevealed());
  919. bubble_widget6->Close();
  920. // 6) Test that a bubble which is not anchored to a child of the
  921. // TopContainerView does not trigger a reveal or keep the
  922. // top-of-window views revealed if they are already revealed.
  923. views::Widget* bubble_widget7 = views::BubbleDialogDelegateView::CreateBubble(
  924. new TestBubbleDialogDelegate(unrelated_view));
  925. bubble_widget7->Show();
  926. EXPECT_FALSE(controller()->IsRevealed());
  927. // Activating |top_container_widget| will close |bubble_widget6|.
  928. top_container_widget->Activate();
  929. AttemptReveal(MODALITY_MOUSE);
  930. EXPECT_TRUE(controller()->IsRevealed());
  931. views::Widget* bubble_widget8 = views::BubbleDialogDelegateView::CreateBubble(
  932. new TestBubbleDialogDelegate(unrelated_view));
  933. bubble_widget8->Show();
  934. SetHovered(false);
  935. EXPECT_FALSE(controller()->IsRevealed());
  936. bubble_widget8->Close();
  937. }
  938. // Test that the shelf is set to auto hide as long as the window is in
  939. // immersive fullscreen and that the shelf's state before entering immersive
  940. // fullscreen is restored upon exiting immersive fullscreen.
  941. TEST_F(ImmersiveFullscreenControllerTest, Shelf) {
  942. Shelf* shelf = GetPrimaryShelf();
  943. // Shelf is visible by default.
  944. SetWindowShowState(ui::SHOW_STATE_NORMAL);
  945. ASSERT_FALSE(controller()->IsEnabled());
  946. ASSERT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
  947. // Entering immersive fullscreen sets the shelf to auto hide.
  948. SetWindowShowState(ui::SHOW_STATE_FULLSCREEN);
  949. SetEnabled(true);
  950. EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
  951. EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
  952. // Verify the shelf can be pulled up.
  953. const gfx::Point start =
  954. shelf->shelf_widget()->GetWindowBoundsInScreen().top_center();
  955. GetEventGenerator()->GestureScrollSequence(
  956. start, start + gfx::Vector2d(0, -ShelfConfig::Get()->shelf_size()),
  957. base::Milliseconds(200), /*steps=*/5);
  958. EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
  959. EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
  960. // Setting the same immersive fullscreen active property should not hide the
  961. // shelf.
  962. SetEnabled(true);
  963. EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
  964. EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
  965. // Disabling immersive fullscreen puts it back.
  966. SetEnabled(false);
  967. SetWindowShowState(ui::SHOW_STATE_NORMAL);
  968. ASSERT_FALSE(controller()->IsEnabled());
  969. EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
  970. // The user could toggle the shelf auto-hide behavior.
  971. shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
  972. EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
  973. // Entering immersive fullscreen keeps auto-hide.
  974. SetWindowShowState(ui::SHOW_STATE_FULLSCREEN);
  975. SetEnabled(true);
  976. EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
  977. // Disabling immersive fullscreen maintains the user's auto-hide selection.
  978. SetEnabled(false);
  979. SetWindowShowState(ui::SHOW_STATE_NORMAL);
  980. EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
  981. }
  982. } // namespase ash