home_button_unittest.cc 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930
  1. // Copyright 2017 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/shelf/home_button.h"
  5. #include <memory>
  6. #include <string>
  7. #include <tuple>
  8. #include <vector>
  9. #include "ash/accessibility/accessibility_controller_impl.h"
  10. #include "ash/app_list/test/app_list_test_helper.h"
  11. #include "ash/app_list/views/app_list_view.h"
  12. #include "ash/assistant/assistant_controller_impl.h"
  13. #include "ash/assistant/model/assistant_ui_model.h"
  14. #include "ash/assistant/test/test_assistant_service.h"
  15. #include "ash/constants/ash_features.h"
  16. #include "ash/public/cpp/assistant/controller/assistant_ui_controller.h"
  17. #include "ash/public/cpp/tablet_mode.h"
  18. #include "ash/root_window_controller.h"
  19. #include "ash/session/session_controller_impl.h"
  20. #include "ash/shelf/shelf.h"
  21. #include "ash/shelf/shelf_navigation_widget.h"
  22. #include "ash/shelf/shelf_view.h"
  23. #include "ash/shelf/shelf_view_test_api.h"
  24. #include "ash/shelf/shelf_widget.h"
  25. #include "ash/shell.h"
  26. #include "ash/test/ash_test_base.h"
  27. #include "ash/wm/tablet_mode/tablet_mode_controller.h"
  28. #include "base/command_line.h"
  29. #include "base/run_loop.h"
  30. #include "base/test/scoped_feature_list.h"
  31. #include "ui/compositor/layer.h"
  32. #include "ui/compositor/layer_animator.h"
  33. #include "ui/compositor/scoped_animation_duration_scale_mode.h"
  34. #include "ui/events/test/event_generator.h"
  35. #include "ui/views/animation/bounds_animator.h"
  36. #include "ui/wm/core/coordinate_conversion.h"
  37. namespace ash {
  38. namespace {
  39. ui::GestureEvent CreateGestureEvent(ui::GestureEventDetails details) {
  40. return ui::GestureEvent(0, 0, ui::EF_NONE, base::TimeTicks(), details);
  41. }
  42. class HomeButtonTest : public AshTestBase,
  43. public testing::WithParamInterface<bool> {
  44. public:
  45. HomeButtonTest() = default;
  46. HomeButtonTest(const HomeButtonTest&) = delete;
  47. HomeButtonTest& operator=(const HomeButtonTest&) = delete;
  48. ~HomeButtonTest() override = default;
  49. // AshTestBase:
  50. void SetUp() override {
  51. scoped_feature_list_.InitWithFeatureState(
  52. features::kHideShelfControlsInTabletMode,
  53. IsHideShelfControlsInTabletModeEnabled());
  54. AshTestBase::SetUp();
  55. }
  56. void SendGestureEvent(ui::GestureEvent* event) {
  57. HomeButton* const home_button =
  58. GetPrimaryShelf()->navigation_widget()->GetHomeButton();
  59. ASSERT_TRUE(home_button);
  60. home_button->OnGestureEvent(event);
  61. }
  62. void SendGestureEventToSecondaryDisplay(ui::GestureEvent* event) {
  63. // Add secondary display.
  64. UpdateDisplay("1+1-1000x600,1002+0-600x400");
  65. ASSERT_TRUE(GetPrimaryShelf()
  66. ->shelf_widget()
  67. ->navigation_widget()
  68. ->GetHomeButton());
  69. // Send the gesture event to the secondary display.
  70. Shelf::ForWindow(Shell::GetAllRootWindows()[1])
  71. ->shelf_widget()
  72. ->navigation_widget()
  73. ->GetHomeButton()
  74. ->OnGestureEvent(event);
  75. }
  76. bool IsHideShelfControlsInTabletModeEnabled() const { return GetParam(); }
  77. const HomeButton* home_button() const {
  78. return GetPrimaryShelf()
  79. ->shelf_widget()
  80. ->navigation_widget()
  81. ->GetHomeButton();
  82. }
  83. AssistantState* assistant_state() const { return AssistantState::Get(); }
  84. PrefService* prefs() {
  85. return Shell::Get()->session_controller()->GetPrimaryUserPrefService();
  86. }
  87. private:
  88. base::test::ScopedFeatureList scoped_feature_list_;
  89. };
  90. // Tests home button visibility animations.
  91. class HomeButtonAnimationTest : public AshTestBase {
  92. public:
  93. HomeButtonAnimationTest() {
  94. scoped_feature_list_.InitAndEnableFeature(
  95. features::kHideShelfControlsInTabletMode);
  96. }
  97. ~HomeButtonAnimationTest() override = default;
  98. // AshTestBase:
  99. void SetUp() override {
  100. AshTestBase::SetUp();
  101. animation_duration_.emplace(
  102. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  103. }
  104. void TearDown() override {
  105. animation_duration_.reset();
  106. AshTestBase::TearDown();
  107. }
  108. private:
  109. absl::optional<ui::ScopedAnimationDurationScaleMode> animation_duration_;
  110. base::test::ScopedFeatureList scoped_feature_list_;
  111. };
  112. enum class TestAccessibilityFeature {
  113. kTabletModeShelfNavigationButtons,
  114. kSpokenFeedback,
  115. kAutoclick,
  116. kSwitchAccess
  117. };
  118. // Tests home button visibility with number of accessibility setting enabled,
  119. // with kHideControlsInTabletModeFeature.
  120. class HomeButtonVisibilityWithAccessibilityFeaturesTest
  121. : public AshTestBase,
  122. public ::testing::WithParamInterface<TestAccessibilityFeature> {
  123. public:
  124. HomeButtonVisibilityWithAccessibilityFeaturesTest() {
  125. scoped_feature_list_.InitAndEnableFeature(
  126. features::kHideShelfControlsInTabletMode);
  127. }
  128. ~HomeButtonVisibilityWithAccessibilityFeaturesTest() override = default;
  129. void SetTestA11yFeatureEnabled(bool enabled) {
  130. switch (GetParam()) {
  131. case TestAccessibilityFeature::kTabletModeShelfNavigationButtons:
  132. Shell::Get()
  133. ->accessibility_controller()
  134. ->SetTabletModeShelfNavigationButtonsEnabled(enabled);
  135. break;
  136. case TestAccessibilityFeature::kSpokenFeedback:
  137. Shell::Get()->accessibility_controller()->SetSpokenFeedbackEnabled(
  138. enabled, A11Y_NOTIFICATION_NONE);
  139. break;
  140. case TestAccessibilityFeature::kAutoclick:
  141. Shell::Get()->accessibility_controller()->autoclick().SetEnabled(
  142. enabled);
  143. break;
  144. case TestAccessibilityFeature::kSwitchAccess:
  145. Shell::Get()->accessibility_controller()->switch_access().SetEnabled(
  146. enabled);
  147. break;
  148. }
  149. }
  150. private:
  151. base::test::ScopedFeatureList scoped_feature_list_;
  152. };
  153. } // namespace
  154. // The parameter indicates whether the kHideShelfControlsInTabletMode feature
  155. // is enabled.
  156. INSTANTIATE_TEST_SUITE_P(All, HomeButtonTest, testing::Bool());
  157. // Tests that the shelf navigation widget clip rect is not clipping the intended
  158. // home button bounds.
  159. TEST_P(HomeButtonTest, ClipRectDoesNotClipHomeButtonBounds) {
  160. ShelfNavigationWidget* const nav_widget =
  161. GetPrimaryShelf()->navigation_widget();
  162. ShelfNavigationWidget::TestApi test_api(nav_widget);
  163. ASSERT_TRUE(test_api.IsHomeButtonVisible());
  164. ASSERT_TRUE(home_button());
  165. auto home_button_bounds = [&]() -> gfx::Rect {
  166. return home_button()->GetBoundsInScreen();
  167. };
  168. auto clip_rect_bounds = [&]() -> gfx::Rect {
  169. gfx::Rect clip_bounds = nav_widget->GetLayer()->clip_rect();
  170. wm::ConvertRectToScreen(nav_widget->GetNativeWindow(), &clip_bounds);
  171. return clip_bounds;
  172. };
  173. std::string display_configs[] = {
  174. "1+1-1200x1000",
  175. "1+1-1000x1200",
  176. "1+1-800x600",
  177. "1+1-600x800",
  178. };
  179. for (const auto& display_config : display_configs) {
  180. SCOPED_TRACE(display_config);
  181. UpdateDisplay(display_config);
  182. EXPECT_TRUE(clip_rect_bounds().Contains(home_button_bounds()));
  183. // Enter tablet mode - note that home button may be invisible in this case.
  184. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  185. ShelfViewTestAPI shelf_test_api(
  186. GetPrimaryShelf()->GetShelfViewForTesting());
  187. shelf_test_api.RunMessageLoopUntilAnimationsDone(
  188. test_api.GetBoundsAnimator());
  189. if (home_button() && test_api.IsHomeButtonVisible())
  190. EXPECT_TRUE(clip_rect_bounds().Contains(home_button_bounds()));
  191. // Create a test widget to transition to in-app shelf.
  192. std::unique_ptr<views::Widget> widget = CreateTestWidget();
  193. shelf_test_api.RunMessageLoopUntilAnimationsDone(
  194. test_api.GetBoundsAnimator());
  195. if (home_button() && test_api.IsHomeButtonVisible())
  196. EXPECT_TRUE(clip_rect_bounds().Contains(home_button_bounds()));
  197. // Back to home launcher shelf.
  198. widget.reset();
  199. shelf_test_api.RunMessageLoopUntilAnimationsDone(
  200. test_api.GetBoundsAnimator());
  201. if (home_button() && test_api.IsHomeButtonVisible())
  202. EXPECT_TRUE(clip_rect_bounds().Contains(home_button_bounds()));
  203. // Open another window and go back to clamshell.
  204. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
  205. widget = CreateTestWidget();
  206. shelf_test_api.RunMessageLoopUntilAnimationsDone(
  207. test_api.GetBoundsAnimator());
  208. EXPECT_TRUE(clip_rect_bounds().Contains(home_button_bounds()));
  209. // Verify bounds after the test widget is closed.
  210. widget.reset();
  211. shelf_test_api.RunMessageLoopUntilAnimationsDone(
  212. test_api.GetBoundsAnimator());
  213. EXPECT_TRUE(clip_rect_bounds().Contains(home_button_bounds()));
  214. }
  215. }
  216. TEST_P(HomeButtonTest, SwipeUpToOpenFullscreenAppList) {
  217. // ProductivityLauncher does not support shelf drags to show app list.
  218. base::test::ScopedFeatureList feature_list;
  219. feature_list.InitAndDisableFeature(features::kProductivityLauncher);
  220. Shelf* shelf = GetPrimaryShelf();
  221. EXPECT_EQ(ShelfAlignment::kBottom, shelf->alignment());
  222. // Start the drags from the center of the shelf.
  223. const ShelfView* shelf_view = shelf->GetShelfViewForTesting();
  224. gfx::Point start =
  225. gfx::Point(shelf_view->width() / 2, shelf_view->height() / 2);
  226. views::View::ConvertPointToScreen(shelf_view, &start);
  227. // Swiping up less than the threshold should trigger a peeking app list.
  228. gfx::Point end = start;
  229. end.set_y(shelf->GetIdealBounds().bottom() -
  230. AppListView::kDragSnapToPeekingThreshold + 10);
  231. GetEventGenerator()->GestureScrollSequence(
  232. start, end, base::Milliseconds(100), 4 /* steps */);
  233. GetAppListTestHelper()->WaitUntilIdle();
  234. GetAppListTestHelper()->CheckVisibility(true);
  235. GetAppListTestHelper()->CheckState(AppListViewState::kPeeking);
  236. // Closing the app list.
  237. GetAppListTestHelper()->DismissAndRunLoop();
  238. GetAppListTestHelper()->CheckVisibility(false);
  239. GetAppListTestHelper()->CheckState(AppListViewState::kClosed);
  240. // Swiping above the threshold should trigger a fullscreen app list.
  241. end.set_y(shelf->GetIdealBounds().bottom() -
  242. AppListView::kDragSnapToPeekingThreshold - 10);
  243. GetEventGenerator()->GestureScrollSequence(
  244. start, end, base::Milliseconds(100), 4 /* steps */);
  245. base::RunLoop().RunUntilIdle();
  246. GetAppListTestHelper()->WaitUntilIdle();
  247. GetAppListTestHelper()->CheckVisibility(true);
  248. GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
  249. // Dismiss the app list to avoid cleanup issues with ProductivityLauncher.
  250. GetAppListTestHelper()->Dismiss();
  251. }
  252. TEST_P(HomeButtonTest, ClickToOpenAppList) {
  253. Shelf* shelf = GetPrimaryShelf();
  254. EXPECT_EQ(ShelfAlignment::kBottom, shelf->alignment());
  255. ShelfNavigationWidget::TestApi test_api(
  256. GetPrimaryShelf()->navigation_widget());
  257. ASSERT_TRUE(test_api.IsHomeButtonVisible());
  258. ASSERT_TRUE(home_button());
  259. gfx::Point center = home_button()->GetBoundsInScreen().CenterPoint();
  260. GetEventGenerator()->MoveMouseTo(center);
  261. // Click on the home button should toggle the app list.
  262. GetEventGenerator()->ClickLeftButton();
  263. GetAppListTestHelper()->WaitUntilIdle();
  264. GetAppListTestHelper()->CheckVisibility(true);
  265. // ProductivityLauncher does not have states like peeking.
  266. if (!features::IsProductivityLauncherEnabled())
  267. GetAppListTestHelper()->CheckState(AppListViewState::kPeeking);
  268. GetEventGenerator()->ClickLeftButton();
  269. GetAppListTestHelper()->WaitUntilIdle();
  270. GetAppListTestHelper()->CheckVisibility(false);
  271. if (!features::IsProductivityLauncherEnabled()) {
  272. GetAppListTestHelper()->CheckState(AppListViewState::kClosed);
  273. // Shift-click should open the app list in fullscreen.
  274. GetEventGenerator()->set_flags(ui::EF_SHIFT_DOWN);
  275. GetEventGenerator()->ClickLeftButton();
  276. GetEventGenerator()->set_flags(0);
  277. GetAppListTestHelper()->WaitUntilIdle();
  278. GetAppListTestHelper()->CheckVisibility(true);
  279. GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
  280. // Another shift-click should close the app list.
  281. GetEventGenerator()->set_flags(ui::EF_SHIFT_DOWN);
  282. GetEventGenerator()->ClickLeftButton();
  283. GetEventGenerator()->set_flags(0);
  284. GetAppListTestHelper()->WaitUntilIdle();
  285. GetAppListTestHelper()->CheckVisibility(false);
  286. GetAppListTestHelper()->CheckState(AppListViewState::kClosed);
  287. }
  288. }
  289. TEST_P(HomeButtonTest, ClickToOpenAppListInTabletMode) {
  290. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  291. Shelf* shelf = GetPrimaryShelf();
  292. EXPECT_EQ(ShelfAlignment::kBottom, shelf->alignment());
  293. ShelfNavigationWidget::TestApi test_api(shelf->navigation_widget());
  294. // Home button is expected to be hidden in tablet mode if shelf controls
  295. // should be hidden.
  296. const bool should_show_home_button =
  297. !IsHideShelfControlsInTabletModeEnabled();
  298. EXPECT_EQ(should_show_home_button, test_api.IsHomeButtonVisible());
  299. ASSERT_EQ(should_show_home_button, static_cast<bool>(home_button()));
  300. if (!should_show_home_button)
  301. return;
  302. // App list should be shown by default in tablet mode.
  303. GetAppListTestHelper()->CheckVisibility(true);
  304. GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
  305. // Click on the home button should not close the app list.
  306. gfx::Point center = home_button()->GetBoundsInScreen().CenterPoint();
  307. GetEventGenerator()->MoveMouseTo(center);
  308. GetEventGenerator()->ClickLeftButton();
  309. GetAppListTestHelper()->WaitUntilIdle();
  310. GetAppListTestHelper()->CheckVisibility(true);
  311. GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
  312. // Shift-click should not close the app list.
  313. GetEventGenerator()->set_flags(ui::EF_SHIFT_DOWN);
  314. GetEventGenerator()->ClickLeftButton();
  315. GetEventGenerator()->set_flags(0);
  316. GetAppListTestHelper()->WaitUntilIdle();
  317. GetAppListTestHelper()->CheckVisibility(true);
  318. GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
  319. }
  320. TEST_P(HomeButtonTest, ButtonPositionInTabletMode) {
  321. // Finish all setup tasks. In particular we want to finish the
  322. // GetSwitchStates post task in (Fake)PowerManagerClient which is triggered
  323. // by TabletModeController otherwise this will cause tablet mode to exit
  324. // while we wait for animations in the test.
  325. base::RunLoop().RunUntilIdle();
  326. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  327. Shelf* const shelf = GetPrimaryShelf();
  328. ShelfViewTestAPI shelf_test_api(shelf->GetShelfViewForTesting());
  329. ShelfNavigationWidget::TestApi test_api(shelf->navigation_widget());
  330. // Home button is expected to be hidden in tablet mode if shelf controls
  331. // should be hidden.
  332. const bool should_show_home_button =
  333. !IsHideShelfControlsInTabletModeEnabled();
  334. EXPECT_EQ(should_show_home_button, test_api.IsHomeButtonVisible());
  335. EXPECT_EQ(should_show_home_button, static_cast<bool>(home_button()));
  336. // Wait for the navigation widget's animation.
  337. shelf_test_api.RunMessageLoopUntilAnimationsDone(
  338. test_api.GetBoundsAnimator());
  339. EXPECT_EQ(should_show_home_button, test_api.IsHomeButtonVisible());
  340. ASSERT_EQ(should_show_home_button, static_cast<bool>(home_button()));
  341. if (should_show_home_button) {
  342. EXPECT_EQ(home_button()->bounds().x(),
  343. ShelfConfig::Get()->control_button_edge_spacing(
  344. true /* is_primary_axis_edge */));
  345. }
  346. // Switch to in-app shelf.
  347. std::unique_ptr<views::Widget> widget = CreateTestWidget();
  348. // Wait for the navigation widget's animation.
  349. shelf_test_api.RunMessageLoopUntilAnimationsDone(
  350. test_api.GetBoundsAnimator());
  351. EXPECT_EQ(should_show_home_button, test_api.IsHomeButtonVisible());
  352. EXPECT_EQ(should_show_home_button, static_cast<bool>(home_button()));
  353. if (should_show_home_button)
  354. EXPECT_GT(home_button()->bounds().x(), 0);
  355. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
  356. shelf_test_api.RunMessageLoopUntilAnimationsDone(
  357. test_api.GetBoundsAnimator());
  358. EXPECT_TRUE(test_api.IsHomeButtonVisible());
  359. ASSERT_TRUE(home_button());
  360. // The space between button and screen edge is within the widget.
  361. EXPECT_EQ(ShelfConfig::Get()->control_button_edge_spacing(
  362. true /* is_primary_axis_edge */),
  363. home_button()->bounds().x());
  364. }
  365. // Verifies that home button visibility updates are animated.
  366. TEST_F(HomeButtonAnimationTest, VisibilityAnimation) {
  367. views::View* const home_button_view =
  368. GetPrimaryShelf()->shelf_widget()->navigation_widget()->GetHomeButton();
  369. ASSERT_TRUE(home_button_view);
  370. EXPECT_TRUE(home_button_view->GetVisible());
  371. EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
  372. EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
  373. // Switch to tablet mode changes the button visibility.
  374. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  375. // Verify that the button view is still visible, and animating to 0 opacity.
  376. EXPECT_TRUE(home_button_view->GetVisible());
  377. EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
  378. EXPECT_EQ(0.0f, home_button_view->layer()->GetTargetOpacity());
  379. // Once the opacity animation finishes, the button should not be visible.
  380. home_button_view->layer()->GetAnimator()->StopAnimating();
  381. EXPECT_FALSE(home_button_view->GetVisible());
  382. // Tablet mode exit should schedule animation to the visible state.
  383. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
  384. EXPECT_TRUE(home_button_view->GetVisible());
  385. EXPECT_EQ(0.0f, home_button_view->layer()->opacity());
  386. EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
  387. home_button_view->layer()->GetAnimator()->StopAnimating();
  388. EXPECT_TRUE(home_button_view->GetVisible());
  389. EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
  390. EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
  391. }
  392. // Verifies that home button visibility updates if the button gets hidden while
  393. // it's still being shown.
  394. TEST_F(HomeButtonAnimationTest, HideWhileAnimatingToShow) {
  395. views::View* const home_button_view =
  396. GetPrimaryShelf()->shelf_widget()->navigation_widget()->GetHomeButton();
  397. ASSERT_TRUE(home_button_view);
  398. EXPECT_TRUE(home_button_view->GetVisible());
  399. EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
  400. EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
  401. // Switch to tablet mode to initiate home button hide animation.
  402. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  403. EXPECT_TRUE(home_button_view->GetVisible());
  404. EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
  405. EXPECT_EQ(0.0f, home_button_view->layer()->GetTargetOpacity());
  406. home_button_view->layer()->GetAnimator()->StopAnimating();
  407. // Tablet mode exit should schedule an animation to the visible state.
  408. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
  409. EXPECT_TRUE(home_button_view->GetVisible());
  410. EXPECT_EQ(0.0f, home_button_view->layer()->opacity());
  411. EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
  412. // Enter tablet mode immediately, to interrupt the show animation.
  413. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  414. EXPECT_TRUE(home_button_view->GetVisible());
  415. EXPECT_EQ(0.0f, home_button_view->layer()->opacity());
  416. EXPECT_EQ(0.0f, home_button_view->layer()->GetTargetOpacity());
  417. home_button_view->layer()->GetAnimator()->StopAnimating();
  418. EXPECT_FALSE(home_button_view->GetVisible());
  419. }
  420. // Verifies that home button becomes visible if reshown while a hide animation
  421. // is still in progress.
  422. TEST_F(HomeButtonAnimationTest, ShowWhileAnimatingToHide) {
  423. views::View* const home_button_view =
  424. GetPrimaryShelf()->shelf_widget()->navigation_widget()->GetHomeButton();
  425. ASSERT_TRUE(home_button_view);
  426. EXPECT_TRUE(home_button_view->GetVisible());
  427. EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
  428. EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
  429. // Switch to tablet mode to initiate the home button hide animation.
  430. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  431. EXPECT_TRUE(home_button_view->GetVisible());
  432. EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
  433. EXPECT_EQ(0.0f, home_button_view->layer()->GetTargetOpacity());
  434. // Tablet mode exit should schedule an animation to the visible state.
  435. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
  436. EXPECT_TRUE(home_button_view->GetVisible());
  437. EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
  438. EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
  439. // Verify that the button ends up in the visible state.
  440. home_button_view->layer()->GetAnimator()->StopAnimating();
  441. EXPECT_TRUE(home_button_view->GetVisible());
  442. EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
  443. EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
  444. }
  445. // Verifies that unanimated navigation widget layout update interrupts in
  446. // progress button animation.
  447. TEST_F(HomeButtonAnimationTest, NonAnimatedLayoutDuringAnimation) {
  448. Shelf* const shelf = GetPrimaryShelf();
  449. views::View* const home_button_view =
  450. shelf->shelf_widget()->navigation_widget()->GetHomeButton();
  451. ASSERT_TRUE(home_button_view);
  452. EXPECT_TRUE(home_button_view->GetVisible());
  453. EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
  454. EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
  455. // Switch to tablet mode changes the button visibility.
  456. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  457. ShelfViewTestAPI shelf_test_api(shelf->GetShelfViewForTesting());
  458. ShelfNavigationWidget::TestApi test_api(shelf->navigation_widget());
  459. // Verify the button bounds are animating.
  460. EXPECT_TRUE(test_api.GetBoundsAnimator()->IsAnimating(home_button_view));
  461. // Verify that the button visibility is animating.
  462. EXPECT_TRUE(home_button_view->GetVisible());
  463. EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
  464. EXPECT_EQ(0.0f, home_button_view->layer()->GetTargetOpacity());
  465. // Request non-animated navigation widget layout, and verify the button is not
  466. // animating any longer.
  467. shelf->navigation_widget()->UpdateLayout(/*animate=*/false);
  468. EXPECT_FALSE(home_button_view->GetVisible());
  469. EXPECT_FALSE(home_button_view->layer()->GetAnimator()->is_animating());
  470. EXPECT_FALSE(test_api.GetBoundsAnimator()->IsAnimating(home_button_view));
  471. // Tablet mode exit should schedule animation to the visible state.
  472. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
  473. EXPECT_TRUE(test_api.GetBoundsAnimator()->IsAnimating(home_button_view));
  474. EXPECT_TRUE(home_button_view->GetVisible());
  475. EXPECT_EQ(0.0f, home_button_view->layer()->opacity());
  476. EXPECT_EQ(1.0f, home_button_view->layer()->GetTargetOpacity());
  477. // Request non-animated navigation widget layout, and verify the button is not
  478. // animating any longer.
  479. shelf->navigation_widget()->UpdateLayout(/*animate=*/false);
  480. EXPECT_FALSE(test_api.GetBoundsAnimator()->IsAnimating(home_button_view));
  481. EXPECT_TRUE(home_button_view->GetVisible());
  482. EXPECT_FALSE(home_button_view->layer()->GetAnimator()->is_animating());
  483. EXPECT_EQ(1.0f, home_button_view->layer()->opacity());
  484. }
  485. TEST_P(HomeButtonTest, LongPressGesture) {
  486. // Simulate two users with primary user as active.
  487. CreateUserSessions(2);
  488. // Enable the Assistant in system settings.
  489. prefs()->SetBoolean(assistant::prefs::kAssistantEnabled, true);
  490. assistant_state()->NotifyFeatureAllowed(
  491. assistant::AssistantAllowedState::ALLOWED);
  492. assistant_state()->NotifyStatusChanged(assistant::AssistantStatus::READY);
  493. ShelfNavigationWidget::TestApi test_api(
  494. GetPrimaryShelf()->navigation_widget());
  495. EXPECT_TRUE(test_api.IsHomeButtonVisible());
  496. ASSERT_TRUE(home_button());
  497. ui::GestureEvent long_press =
  498. CreateGestureEvent(ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
  499. SendGestureEvent(&long_press);
  500. GetAppListTestHelper()->WaitUntilIdle();
  501. EXPECT_EQ(AssistantVisibility::kVisible,
  502. AssistantUiController::Get()->GetModel()->visibility());
  503. AssistantUiController::Get()->CloseUi(
  504. assistant::AssistantExitPoint::kUnspecified);
  505. // Test long press gesture on secondary display.
  506. SendGestureEventToSecondaryDisplay(&long_press);
  507. GetAppListTestHelper()->WaitUntilIdle();
  508. EXPECT_EQ(AssistantVisibility::kVisible,
  509. AssistantUiController::Get()->GetModel()->visibility());
  510. }
  511. TEST_P(HomeButtonTest, LongPressGestureInTabletMode) {
  512. // Simulate two users with primary user as active.
  513. CreateUserSessions(2);
  514. // Enable the Assistant in system settings.
  515. prefs()->SetBoolean(assistant::prefs::kAssistantEnabled, true);
  516. assistant_state()->NotifyFeatureAllowed(
  517. assistant::AssistantAllowedState::ALLOWED);
  518. assistant_state()->NotifyStatusChanged(assistant::AssistantStatus::READY);
  519. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  520. ShelfNavigationWidget::TestApi test_api(
  521. GetPrimaryShelf()->navigation_widget());
  522. const bool should_show_home_button =
  523. !IsHideShelfControlsInTabletModeEnabled();
  524. EXPECT_EQ(should_show_home_button, test_api.IsHomeButtonVisible());
  525. ASSERT_EQ(should_show_home_button, static_cast<bool>(home_button()));
  526. // App list should be shown by default in tablet mode.
  527. GetAppListTestHelper()->CheckVisibility(true);
  528. GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
  529. if (!should_show_home_button)
  530. return;
  531. ui::GestureEvent long_press =
  532. CreateGestureEvent(ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
  533. SendGestureEvent(&long_press);
  534. GetAppListTestHelper()->WaitUntilIdle();
  535. EXPECT_EQ(AssistantVisibility::kVisible,
  536. AssistantUiController::Get()->GetModel()->visibility());
  537. GetAppListTestHelper()->CheckVisibility(true);
  538. GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
  539. // Tap on the home button should close assistant.
  540. gfx::Point center = home_button()->GetBoundsInScreen().CenterPoint();
  541. GetEventGenerator()->MoveMouseTo(center);
  542. GetEventGenerator()->ClickLeftButton();
  543. GetAppListTestHelper()->WaitUntilIdle();
  544. GetAppListTestHelper()->CheckVisibility(true);
  545. GetAppListTestHelper()->CheckState(AppListViewState::kFullscreenAllApps);
  546. EXPECT_EQ(AssistantVisibility::kClosed,
  547. AssistantUiController::Get()->GetModel()->visibility());
  548. AssistantUiController::Get()->CloseUi(
  549. assistant::AssistantExitPoint::kUnspecified);
  550. }
  551. TEST_P(HomeButtonTest, LongPressGestureWithSecondaryUser) {
  552. // Disallowed by secondary user.
  553. assistant_state()->NotifyFeatureAllowed(
  554. assistant::AssistantAllowedState::DISALLOWED_BY_NONPRIMARY_USER);
  555. // Enable the Assistant in system settings.
  556. prefs()->SetBoolean(assistant::prefs::kAssistantEnabled, true);
  557. ShelfNavigationWidget::TestApi test_api(
  558. GetPrimaryShelf()->navigation_widget());
  559. EXPECT_TRUE(test_api.IsHomeButtonVisible());
  560. ASSERT_TRUE(home_button());
  561. ui::GestureEvent long_press =
  562. CreateGestureEvent(ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
  563. SendGestureEvent(&long_press);
  564. // The Assistant is disabled for secondary user.
  565. EXPECT_NE(AssistantVisibility::kVisible,
  566. AssistantUiController::Get()->GetModel()->visibility());
  567. // Test long press gesture on secondary display.
  568. SendGestureEventToSecondaryDisplay(&long_press);
  569. EXPECT_NE(AssistantVisibility::kVisible,
  570. AssistantUiController::Get()->GetModel()->visibility());
  571. }
  572. TEST_P(HomeButtonTest, LongPressGestureWithSettingsDisabled) {
  573. // Simulate two user with primary user as active.
  574. CreateUserSessions(2);
  575. // Simulate a user who has already completed setup flow, but disabled the
  576. // Assistant in settings.
  577. prefs()->SetBoolean(assistant::prefs::kAssistantEnabled, false);
  578. assistant_state()->NotifyFeatureAllowed(
  579. assistant::AssistantAllowedState::ALLOWED);
  580. ShelfNavigationWidget::TestApi test_api(
  581. GetPrimaryShelf()->navigation_widget());
  582. EXPECT_TRUE(test_api.IsHomeButtonVisible());
  583. ASSERT_TRUE(home_button());
  584. ui::GestureEvent long_press =
  585. CreateGestureEvent(ui::GestureEventDetails(ui::ET_GESTURE_LONG_PRESS));
  586. SendGestureEvent(&long_press);
  587. EXPECT_NE(AssistantVisibility::kVisible,
  588. AssistantUiController::Get()->GetModel()->visibility());
  589. // Test long press gesture on secondary display.
  590. SendGestureEventToSecondaryDisplay(&long_press);
  591. EXPECT_NE(AssistantVisibility::kVisible,
  592. AssistantUiController::Get()->GetModel()->visibility());
  593. }
  594. // Tests that tapping in the bottom left corner in tablet mode results in the
  595. // home button activating.
  596. TEST_P(HomeButtonTest, InteractOutsideHomeButtonBounds) {
  597. EXPECT_EQ(ShelfAlignment::kBottom, GetPrimaryShelf()->alignment());
  598. // Tap the bottom left of the shelf. The button should work.
  599. gfx::Point bottom_left = GetPrimaryShelf()
  600. ->shelf_widget()
  601. ->GetWindowBoundsInScreen()
  602. .bottom_left();
  603. GetEventGenerator()->GestureTapAt(bottom_left);
  604. GetAppListTestHelper()->WaitUntilIdle();
  605. GetAppListTestHelper()->CheckVisibility(true);
  606. // Tap the top left of the shelf, the button should work.
  607. gfx::Point bottom_right = GetPrimaryShelf()
  608. ->shelf_widget()
  609. ->GetWindowBoundsInScreen()
  610. .bottom_right();
  611. GetEventGenerator()->GestureTapAt(bottom_right);
  612. GetAppListTestHelper()->WaitUntilIdle();
  613. GetAppListTestHelper()->CheckVisibility(false);
  614. // Test left shelf.
  615. GetPrimaryShelf()->SetAlignment(ShelfAlignment::kLeft);
  616. gfx::Point top_left =
  617. GetPrimaryShelf()->shelf_widget()->GetWindowBoundsInScreen().origin();
  618. GetEventGenerator()->GestureTapAt(top_left);
  619. GetAppListTestHelper()->WaitUntilIdle();
  620. GetAppListTestHelper()->CheckVisibility(true);
  621. bottom_left = GetPrimaryShelf()
  622. ->shelf_widget()
  623. ->GetWindowBoundsInScreen()
  624. .bottom_left();
  625. GetEventGenerator()->GestureTapAt(bottom_left);
  626. GetAppListTestHelper()->WaitUntilIdle();
  627. GetAppListTestHelper()->CheckVisibility(false);
  628. // Test right shelf.
  629. GetPrimaryShelf()->SetAlignment(ShelfAlignment::kRight);
  630. gfx::Point top_right =
  631. GetPrimaryShelf()->shelf_widget()->GetWindowBoundsInScreen().top_right();
  632. GetEventGenerator()->GestureTapAt(top_right);
  633. GetAppListTestHelper()->WaitUntilIdle();
  634. GetAppListTestHelper()->CheckVisibility(true);
  635. bottom_right = GetPrimaryShelf()
  636. ->shelf_widget()
  637. ->GetWindowBoundsInScreen()
  638. .bottom_right();
  639. GetEventGenerator()->GestureTapAt(bottom_right);
  640. GetAppListTestHelper()->WaitUntilIdle();
  641. GetAppListTestHelper()->CheckVisibility(false);
  642. }
  643. // Tests that clicking the corner of the display opens and closes the AppList.
  644. TEST_P(HomeButtonTest, ClickOnCornerPixel) {
  645. // Screen corners are extremely easy to reach with a mouse. Let's make sure
  646. // that a click on the bottom-left corner (or bottom-right corner in RTL)
  647. // can trigger the home button.
  648. gfx::Point corner(
  649. 0, display::Screen::GetScreen()->GetPrimaryDisplay().bounds().height());
  650. ShelfNavigationWidget::TestApi test_api(
  651. GetPrimaryShelf()->navigation_widget());
  652. ASSERT_TRUE(test_api.IsHomeButtonVisible());
  653. GetAppListTestHelper()->CheckVisibility(false);
  654. GetEventGenerator()->MoveMouseTo(corner);
  655. GetEventGenerator()->ClickLeftButton();
  656. GetAppListTestHelper()->WaitUntilIdle();
  657. GetAppListTestHelper()->CheckVisibility(true);
  658. GetEventGenerator()->ClickLeftButton();
  659. GetAppListTestHelper()->WaitUntilIdle();
  660. GetAppListTestHelper()->CheckVisibility(false);
  661. }
  662. // Test that for a gesture tap which covers both the shelf navigation widget
  663. // and the home button, the home button is returned as the event target. When
  664. // the home button is the only button within the widget,
  665. // ViewTageterDelegate::TargetForRect() can return the incorrect view. Ensuring
  666. // the center point of the home button is the same as the content view's center
  667. // point will avoid this problem. See http://crbug.com/1083713
  668. TEST_P(HomeButtonTest, GestureHomeButtonHitTest) {
  669. ShelfNavigationWidget* nav_widget =
  670. AshTestBase::GetPrimaryShelf()->navigation_widget();
  671. ShelfNavigationWidget::TestApi test_api(nav_widget);
  672. gfx::Rect nav_widget_bounds = nav_widget->GetRootView()->bounds();
  673. // The home button should be the only shown button.
  674. EXPECT_TRUE(test_api.IsHomeButtonVisible());
  675. EXPECT_FALSE(test_api.IsBackButtonVisible());
  676. // The center point of the widget and the center point of the home button
  677. // should be equally close to the event location.
  678. gfx::Point home_button_center(
  679. nav_widget->GetHomeButton()->bounds().CenterPoint());
  680. gfx::Point nav_widget_center(nav_widget_bounds.CenterPoint());
  681. EXPECT_EQ(home_button_center, nav_widget_center);
  682. ui::GestureEventDetails details = ui::GestureEventDetails(ui::ET_GESTURE_TAP);
  683. // Create and test a gesture-event targeting >60% of the navigation widget,
  684. // as well as ~60% of the home button.
  685. gfx::RectF gesture_event_rect(0, 0, .7f * nav_widget_bounds.width(),
  686. nav_widget_bounds.height());
  687. details.set_bounding_box(gesture_event_rect);
  688. {
  689. const gfx::Point event_center(gesture_event_rect.width() / 2,
  690. gesture_event_rect.height() / 2);
  691. ui::GestureEvent gesture(event_center.x(), event_center.y(), 0,
  692. base::TimeTicks(), details);
  693. ui::EventTargeter* targeter = nav_widget->GetRootView()->GetEventTargeter();
  694. ui::EventTarget* target =
  695. targeter->FindTargetForEvent(nav_widget->GetRootView(), &gesture);
  696. EXPECT_TRUE(target);
  697. // Check that the event target is the home button.
  698. EXPECT_EQ(target, nav_widget->GetHomeButton());
  699. }
  700. // Test a gesture event centered on the top corner of the home button.
  701. {
  702. const gfx::Point event_center(nav_widget->GetHomeButton()->bounds().x(),
  703. nav_widget->GetHomeButton()->bounds().y());
  704. ui::GestureEvent gesture(event_center.x(), event_center.y(), 0,
  705. base::TimeTicks(), details);
  706. ui::EventTargeter* targeter = nav_widget->GetRootView()->GetEventTargeter();
  707. ui::EventTarget* target =
  708. targeter->FindTargetForEvent(nav_widget->GetRootView(), &gesture);
  709. EXPECT_TRUE(target);
  710. // Check that the event target is the home button.
  711. EXPECT_EQ(target, nav_widget->GetHomeButton());
  712. }
  713. // Test a gesture event centered to the left of the nav_widget's center
  714. // point.
  715. {
  716. const gfx::Point event_center(nav_widget_center.x() - 1,
  717. nav_widget_center.y());
  718. ui::GestureEvent gesture(event_center.x(), event_center.y(), 0,
  719. base::TimeTicks(), details);
  720. ui::EventTargeter* targeter = nav_widget->GetRootView()->GetEventTargeter();
  721. ui::EventTarget* target =
  722. targeter->FindTargetForEvent(nav_widget->GetRootView(), &gesture);
  723. EXPECT_TRUE(target);
  724. // Check that the event target is the home button.
  725. EXPECT_EQ(target, nav_widget->GetHomeButton());
  726. }
  727. }
  728. INSTANTIATE_TEST_SUITE_P(
  729. All,
  730. HomeButtonVisibilityWithAccessibilityFeaturesTest,
  731. ::testing::Values(
  732. TestAccessibilityFeature::kTabletModeShelfNavigationButtons,
  733. TestAccessibilityFeature::kSpokenFeedback,
  734. TestAccessibilityFeature::kAutoclick,
  735. TestAccessibilityFeature::kSwitchAccess));
  736. TEST_P(HomeButtonVisibilityWithAccessibilityFeaturesTest,
  737. TabletModeSwitchWithA11yFeatureEnabled) {
  738. SetTestA11yFeatureEnabled(true /*enabled*/);
  739. ShelfNavigationWidget::TestApi test_api(
  740. GetPrimaryShelf()->navigation_widget());
  741. EXPECT_TRUE(test_api.IsHomeButtonVisible());
  742. // Switch to tablet mode, and verify the home button is still visible.
  743. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  744. EXPECT_TRUE(test_api.IsHomeButtonVisible());
  745. // The button should be hidden if the feature gets disabled.
  746. SetTestA11yFeatureEnabled(false /*enabled*/);
  747. EXPECT_FALSE(test_api.IsHomeButtonVisible());
  748. }
  749. TEST_P(HomeButtonVisibilityWithAccessibilityFeaturesTest,
  750. FeatureEnabledWhileInTabletMode) {
  751. ShelfNavigationWidget::TestApi test_api(
  752. GetPrimaryShelf()->navigation_widget());
  753. EXPECT_TRUE(test_api.IsHomeButtonVisible());
  754. // Switch to tablet mode, and verify the home button is hidden.
  755. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  756. EXPECT_FALSE(test_api.IsHomeButtonVisible());
  757. // The button should be shown if the feature gets enabled.
  758. SetTestA11yFeatureEnabled(true /*enabled*/);
  759. EXPECT_TRUE(test_api.IsHomeButtonVisible());
  760. }
  761. } // namespace ash