shelf_widget_unittest.cc 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190
  1. // Copyright (c) 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 "ash/shelf/shelf_widget.h"
  5. #include "ash/bubble/bubble_constants.h"
  6. #include "ash/constants/ash_features.h"
  7. #include "ash/constants/ash_switches.h"
  8. #include "ash/keyboard/ui/keyboard_ui_controller.h"
  9. #include "ash/keyboard/ui/keyboard_util.h"
  10. #include "ash/keyboard/ui/test/keyboard_test_util.h"
  11. #include "ash/public/cpp/keyboard/keyboard_switches.h"
  12. #include "ash/public/cpp/shelf_config.h"
  13. #include "ash/public/cpp/shelf_types.h"
  14. #include "ash/public/cpp/tablet_mode.h"
  15. #include "ash/root_window_controller.h"
  16. #include "ash/screen_util.h"
  17. #include "ash/shelf/drag_handle.h"
  18. #include "ash/shelf/hotseat_transition_animator.h"
  19. #include "ash/shelf/login_shelf_view.h"
  20. #include "ash/shelf/shelf.h"
  21. #include "ash/shelf/shelf_layout_manager.h"
  22. #include "ash/shelf/shelf_navigation_widget.h"
  23. #include "ash/shelf/shelf_test_util.h"
  24. #include "ash/shelf/shelf_view.h"
  25. #include "ash/shelf/shelf_view_test_api.h"
  26. #include "ash/shell.h"
  27. #include "ash/style/dark_light_mode_controller_impl.h"
  28. #include "ash/system/message_center/unified_message_center_bubble.h"
  29. #include "ash/system/status_area_widget.h"
  30. #include "ash/system/unified/unified_system_tray.h"
  31. #include "ash/system/unified/unified_system_tray_bubble.h"
  32. #include "ash/test/ash_test_base.h"
  33. #include "ash/test/ash_test_helper.h"
  34. #include "ash/test_shell_delegate.h"
  35. #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
  36. #include "ash/wm/window_util.h"
  37. #include "base/callback_helpers.h"
  38. #include "base/command_line.h"
  39. #include "base/i18n/rtl.h"
  40. #include "base/run_loop.h"
  41. #include "base/test/icu_test_util.h"
  42. #include "base/test/scoped_feature_list.h"
  43. #include "chromeos/constants/chromeos_features.h"
  44. #include "components/session_manager/session_manager_types.h"
  45. #include "ui/aura/window_event_dispatcher.h"
  46. #include "ui/base/models/image_model.h"
  47. #include "ui/compositor/layer.h"
  48. #include "ui/compositor/scoped_animation_duration_scale_mode.h"
  49. #include "ui/display/display.h"
  50. #include "ui/events/event_utils.h"
  51. #include "ui/events/test/event_generator.h"
  52. #include "ui/message_center/message_center.h"
  53. #include "ui/message_center/public/cpp/notification.h"
  54. #include "ui/message_center/public/cpp/notification_types.h"
  55. #include "ui/message_center/public/cpp/notifier_id.h"
  56. #include "ui/views/view.h"
  57. #include "ui/views/widget/widget.h"
  58. #include "url/gurl.h"
  59. namespace ash {
  60. namespace {
  61. ShelfWidget* GetShelfWidget() {
  62. return AshTestBase::GetPrimaryShelf()->shelf_widget();
  63. }
  64. ShelfLayoutManager* GetShelfLayoutManager() {
  65. return GetShelfWidget()->shelf_layout_manager();
  66. }
  67. void TestLauncherAlignment(aura::Window* root,
  68. ShelfAlignment alignment,
  69. const gfx::Rect& expected) {
  70. Shelf::ForWindow(root)->SetAlignment(alignment);
  71. EXPECT_EQ(expected.ToString(), display::Screen::GetScreen()
  72. ->GetDisplayNearestWindow(root)
  73. .work_area()
  74. .ToString());
  75. }
  76. using SessionState = session_manager::SessionState;
  77. using ShelfWidgetTest = AshTestBase;
  78. TEST_F(ShelfWidgetTest, TestAlignment) {
  79. UpdateDisplay("401x400");
  80. const int bottom_inset = 400 - ShelfConfig::Get()->shelf_size();
  81. {
  82. SCOPED_TRACE("Single Bottom");
  83. TestLauncherAlignment(Shell::GetPrimaryRootWindow(),
  84. ShelfAlignment::kBottom,
  85. gfx::Rect(0, 0, 401, bottom_inset));
  86. }
  87. {
  88. SCOPED_TRACE("Single Locked");
  89. TestLauncherAlignment(Shell::GetPrimaryRootWindow(),
  90. ShelfAlignment::kBottomLocked,
  91. gfx::Rect(0, 0, 401, bottom_inset));
  92. }
  93. {
  94. SCOPED_TRACE("Single Right");
  95. TestLauncherAlignment(Shell::GetPrimaryRootWindow(), ShelfAlignment::kRight,
  96. gfx::Rect(0, 0, bottom_inset + 1, 400));
  97. }
  98. {
  99. SCOPED_TRACE("Single Left");
  100. TestLauncherAlignment(
  101. Shell::GetPrimaryRootWindow(), ShelfAlignment::kLeft,
  102. gfx::Rect(ShelfConfig::Get()->shelf_size(), 0, bottom_inset + 1, 400));
  103. }
  104. }
  105. TEST_F(ShelfWidgetTest, TestAlignmentForMultipleDisplays) {
  106. UpdateDisplay("301x300,501x500");
  107. const int shelf_inset_first = 300 - ShelfConfig::Get()->shelf_size();
  108. const int shelf_inset_second = 500 - ShelfConfig::Get()->shelf_size();
  109. aura::Window::Windows root_windows = Shell::GetAllRootWindows();
  110. {
  111. SCOPED_TRACE("Primary Bottom");
  112. TestLauncherAlignment(root_windows[0], ShelfAlignment::kBottom,
  113. gfx::Rect(0, 0, 301, shelf_inset_first));
  114. }
  115. {
  116. SCOPED_TRACE("Primary Locked");
  117. TestLauncherAlignment(root_windows[0], ShelfAlignment::kBottomLocked,
  118. gfx::Rect(0, 0, 301, shelf_inset_first));
  119. }
  120. {
  121. SCOPED_TRACE("Primary Right");
  122. TestLauncherAlignment(root_windows[0], ShelfAlignment::kRight,
  123. gfx::Rect(0, 0, shelf_inset_first + 1, 300));
  124. }
  125. {
  126. SCOPED_TRACE("Primary Left");
  127. TestLauncherAlignment(root_windows[0], ShelfAlignment::kLeft,
  128. gfx::Rect(ShelfConfig::Get()->shelf_size(), 0,
  129. shelf_inset_first + 1, 300));
  130. }
  131. {
  132. SCOPED_TRACE("Secondary Bottom");
  133. TestLauncherAlignment(root_windows[1], ShelfAlignment::kBottom,
  134. gfx::Rect(301, 0, 501, shelf_inset_second));
  135. }
  136. {
  137. SCOPED_TRACE("Secondary Locked");
  138. TestLauncherAlignment(root_windows[1], ShelfAlignment::kBottomLocked,
  139. gfx::Rect(301, 0, 501, shelf_inset_second));
  140. }
  141. {
  142. SCOPED_TRACE("Secondary Right");
  143. TestLauncherAlignment(root_windows[1], ShelfAlignment::kRight,
  144. gfx::Rect(301, 0, shelf_inset_second + 1, 500));
  145. }
  146. {
  147. SCOPED_TRACE("Secondary Left");
  148. TestLauncherAlignment(root_windows[1], ShelfAlignment::kLeft,
  149. gfx::Rect(301 + ShelfConfig::Get()->shelf_size(), 0,
  150. shelf_inset_second + 1, 500));
  151. }
  152. }
  153. class ShelfWidgetDarkLightModeTest : public ShelfWidgetTest {
  154. public:
  155. ShelfWidgetDarkLightModeTest() {
  156. scoped_feature_list_.InitAndEnableFeature(
  157. chromeos::features::kDarkLightMode);
  158. }
  159. void SetUp() override {
  160. ShelfWidgetTest::SetUp();
  161. // Enable tablet mode transition screenshots to simulate production behavior
  162. // where shelf layers get recreated during the tablet mode transition.
  163. TabletModeController::SetUseScreenshotForTest(true);
  164. }
  165. private:
  166. base::test::ScopedFeatureList scoped_feature_list_;
  167. };
  168. TEST_F(ShelfWidgetDarkLightModeTest, TabletModeTransition) {
  169. ShelfWidget* const shelf_widget = GetShelfWidget();
  170. TabletMode::Waiter enter_waiter(/*enable=*/true);
  171. TabletModeControllerTestApi().EnterTabletMode();
  172. enter_waiter.Wait();
  173. shelf_widget->background_animator_for_testing()
  174. ->CompleteAnimationForTesting();
  175. EXPECT_EQ(AshColorProvider::Get()->GetBaseLayerColor(
  176. AshColorProvider::BaseLayerType::kTransparent60),
  177. shelf_widget->GetShelfBackgroundColor());
  178. EXPECT_EQ(0.0, shelf_widget->GetOpaqueBackground()->background_blur());
  179. auto* dark_light_mode_controller = ash::DarkLightModeControllerImpl::Get();
  180. dark_light_mode_controller->ToggleColorMode();
  181. EXPECT_EQ(AshColorProvider::Get()->GetBaseLayerColor(
  182. AshColorProvider::BaseLayerType::kTransparent60),
  183. shelf_widget->GetShelfBackgroundColor());
  184. EXPECT_EQ(0.0f, shelf_widget->GetOpaqueBackground()->background_blur());
  185. TabletMode::Waiter leave_waiter(/*enable=*/false);
  186. TabletModeControllerTestApi().LeaveTabletMode();
  187. leave_waiter.Wait();
  188. shelf_widget->background_animator_for_testing()
  189. ->CompleteAnimationForTesting();
  190. EXPECT_EQ(AshColorProvider::Get()->GetBaseLayerColor(
  191. AshColorProvider::BaseLayerType::kTransparent80),
  192. shelf_widget->GetShelfBackgroundColor());
  193. EXPECT_GT(shelf_widget->GetOpaqueBackground()->background_blur(), 0.0f);
  194. dark_light_mode_controller->ToggleColorMode();
  195. EXPECT_EQ(AshColorProvider::Get()->GetBaseLayerColor(
  196. AshColorProvider::BaseLayerType::kTransparent80),
  197. shelf_widget->GetShelfBackgroundColor());
  198. EXPECT_GT(shelf_widget->GetOpaqueBackground()->background_blur(), 0.0f);
  199. }
  200. TEST_F(ShelfWidgetDarkLightModeTest, TabletModeTransitionWithWindowOpen) {
  201. ShelfWidget* const shelf_widget = GetShelfWidget();
  202. auto window = AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 800, 800));
  203. TabletMode::Waiter enter_waiter(/*enable=*/true);
  204. TabletModeControllerTestApi().EnterTabletMode();
  205. enter_waiter.Wait();
  206. shelf_widget->background_animator_for_testing()
  207. ->CompleteAnimationForTesting();
  208. EXPECT_EQ(AshColorProvider::Get()->GetBaseLayerColor(
  209. AshColorProvider::BaseLayerType::kOpaque),
  210. shelf_widget->GetShelfBackgroundColor());
  211. EXPECT_EQ(0.0f, shelf_widget->GetOpaqueBackground()->background_blur());
  212. auto* dark_light_mode_controller = ash::DarkLightModeControllerImpl::Get();
  213. dark_light_mode_controller->ToggleColorMode();
  214. EXPECT_EQ(AshColorProvider::Get()->GetBaseLayerColor(
  215. AshColorProvider::BaseLayerType::kOpaque),
  216. shelf_widget->GetShelfBackgroundColor());
  217. EXPECT_EQ(0.0f, shelf_widget->GetOpaqueBackground()->background_blur());
  218. TabletMode::Waiter leave_waiter(/*enable=*/false);
  219. TabletModeControllerTestApi().LeaveTabletMode();
  220. leave_waiter.Wait();
  221. shelf_widget->background_animator_for_testing()
  222. ->CompleteAnimationForTesting();
  223. EXPECT_EQ(AshColorProvider::Get()->GetBaseLayerColor(
  224. AshColorProvider::BaseLayerType::kTransparent80),
  225. shelf_widget->GetShelfBackgroundColor());
  226. EXPECT_GT(shelf_widget->GetOpaqueBackground()->background_blur(), 0.0f);
  227. dark_light_mode_controller->ToggleColorMode();
  228. EXPECT_EQ(AshColorProvider::Get()->GetBaseLayerColor(
  229. AshColorProvider::BaseLayerType::kTransparent80),
  230. shelf_widget->GetShelfBackgroundColor());
  231. EXPECT_GT(shelf_widget->GetOpaqueBackground()->background_blur(), 0.0f);
  232. }
  233. class ShelfWidgetLayoutBasicsTest
  234. : public ShelfWidgetTest,
  235. public testing::WithParamInterface<std::tuple<bool, bool>> {
  236. public:
  237. ShelfWidgetLayoutBasicsTest() {
  238. scoped_feature_list_.InitWithFeatureState(
  239. features::kHideShelfControlsInTabletMode, std::get<1>(GetParam()));
  240. }
  241. ~ShelfWidgetLayoutBasicsTest() override = default;
  242. void SetUp() override {
  243. ShelfWidgetTest::SetUp();
  244. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(
  245. std::get<0>(GetParam()));
  246. }
  247. private:
  248. base::test::ScopedFeatureList scoped_feature_list_;
  249. };
  250. // First parameter - whether test should run in tablet mode.
  251. // Second parameter - whether shelf navigation buttons are enabled in tablet
  252. // mode.
  253. INSTANTIATE_TEST_SUITE_P(All,
  254. ShelfWidgetLayoutBasicsTest,
  255. testing::Combine(testing::Bool(), testing::Bool()));
  256. // Makes sure the shelf is initially sized correctly in clamshell/tablet.
  257. TEST_P(ShelfWidgetLayoutBasicsTest, LauncherInitiallySized) {
  258. ShelfWidget* shelf_widget = GetShelfWidget();
  259. ShelfLayoutManager* shelf_layout_manager = GetShelfLayoutManager();
  260. ASSERT_TRUE(shelf_layout_manager);
  261. ASSERT_TRUE(shelf_widget->status_area_widget());
  262. int status_width =
  263. shelf_widget->status_area_widget()->GetWindowBoundsInScreen().width();
  264. // Test only makes sense if the status is > 0, which it better be.
  265. EXPECT_GT(status_width, 0);
  266. const int total_width =
  267. screen_util::GetDisplayBoundsWithShelf(shelf_widget->GetNativeWindow())
  268. .width();
  269. const gfx::Rect nav_widget_clip_rect =
  270. shelf_widget->navigation_widget()->GetLayer()->clip_rect();
  271. if (!nav_widget_clip_rect.IsEmpty())
  272. EXPECT_EQ(gfx::Point(), nav_widget_clip_rect.origin());
  273. int nav_width =
  274. nav_widget_clip_rect.IsEmpty()
  275. ? shelf_widget->navigation_widget()->GetWindowBoundsInScreen().width()
  276. : nav_widget_clip_rect.width();
  277. ASSERT_GE(nav_width, 0);
  278. if (nav_width) {
  279. nav_width -= ShelfConfig::Get()->control_button_edge_spacing(
  280. true /* is_primary_axis_edge */);
  281. }
  282. const int hotseat_width =
  283. shelf_widget->hotseat_widget()->GetWindowBoundsInScreen().width();
  284. const int margins = 2 * ShelfConfig::Get()->GetAppIconGroupMargin();
  285. EXPECT_EQ(status_width, total_width - nav_width - hotseat_width - margins);
  286. }
  287. TEST_F(ShelfWidgetTest, CheckVerticalShelfCornersInOverviewMode) {
  288. // Verify corners of the shelf on the left alignment.
  289. Shelf* shelf = GetPrimaryShelf();
  290. shelf->SetAlignment(ShelfAlignment::kLeft);
  291. EXPECT_EQ(ShelfAlignment::kLeft, GetPrimaryShelf()->alignment());
  292. ShelfWidget* const shelf_widget = GetShelfWidget();
  293. ui::Layer* opaque_background_layer =
  294. shelf_widget->GetDelegateViewOpaqueBackgroundLayerForTesting();
  295. // The gfx::RoundedCornersF object is considered empty when all of the
  296. // corners are squared (no effective radius).
  297. EXPECT_FALSE(opaque_background_layer->rounded_corner_radii().IsEmpty());
  298. OverviewController* overview_controller = Shell::Get()->overview_controller();
  299. // Enter overview mode. Expect the shelf with square corners.
  300. EnterOverview();
  301. WaitForOverviewAnimation(/*enter=*/true);
  302. EXPECT_TRUE(overview_controller->InOverviewSession());
  303. EXPECT_TRUE(opaque_background_layer->rounded_corner_radii().IsEmpty());
  304. // Exit overview mode. Expect the shelf with rounded corners.
  305. ExitOverview();
  306. WaitForOverviewAnimation(/*enter=*/false);
  307. EXPECT_FALSE(overview_controller->InOverviewSession());
  308. EXPECT_FALSE(opaque_background_layer->rounded_corner_radii().IsEmpty());
  309. // Verify corners of the shelf on the right alignment.
  310. shelf->SetAlignment(ShelfAlignment::kRight);
  311. EXPECT_EQ(ShelfAlignment::kRight, GetPrimaryShelf()->alignment());
  312. EXPECT_FALSE(opaque_background_layer->rounded_corner_radii().IsEmpty());
  313. // Enter overview mode. Expect the shelf with square corners.
  314. EnterOverview();
  315. WaitForOverviewAnimation(/*enter=*/true);
  316. EXPECT_TRUE(overview_controller->InOverviewSession());
  317. EXPECT_TRUE(opaque_background_layer->rounded_corner_radii().IsEmpty());
  318. // Exit overview mode. Expect the shelf with rounded corners.
  319. ExitOverview();
  320. WaitForOverviewAnimation(/*enter=*/false);
  321. EXPECT_FALSE(overview_controller->InOverviewSession());
  322. EXPECT_FALSE(opaque_background_layer->rounded_corner_radii().IsEmpty());
  323. }
  324. // Verifies when the shell is deleted with a full screen window we don't crash.
  325. TEST_F(ShelfWidgetTest, DontReferenceShelfAfterDeletion) {
  326. views::Widget* widget = new views::Widget;
  327. views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
  328. params.bounds = gfx::Rect(0, 0, 200, 200);
  329. params.context = GetContext();
  330. // Widget is now owned by the parent window.
  331. widget->Init(std::move(params));
  332. widget->SetFullscreen(true);
  333. }
  334. // Verifies shelf is created with correct size after user login and when its
  335. // container and status widget has finished sizing.
  336. // See http://crbug.com/252533
  337. TEST_F(ShelfWidgetTest, ShelfInitiallySizedAfterLogin) {
  338. ClearLogin();
  339. UpdateDisplay("300x200,400x300");
  340. // Both displays have a shelf controller.
  341. aura::Window::Windows roots = Shell::GetAllRootWindows();
  342. Shelf* shelf1 = Shelf::ForWindow(roots[0]);
  343. Shelf* shelf2 = Shelf::ForWindow(roots[1]);
  344. ASSERT_TRUE(shelf1);
  345. ASSERT_TRUE(shelf2);
  346. // Both shelf controllers have a shelf widget.
  347. ShelfWidget* shelf_widget1 = shelf1->shelf_widget();
  348. ShelfWidget* shelf_widget2 = shelf2->shelf_widget();
  349. ASSERT_TRUE(shelf_widget1);
  350. ASSERT_TRUE(shelf_widget2);
  351. // Simulate login.
  352. CreateUserSessions(1);
  353. const int total_width1 =
  354. screen_util::GetDisplayBoundsWithShelf(shelf_widget1->GetNativeWindow())
  355. .width();
  356. const int nav_width1 =
  357. shelf_widget1->navigation_widget()->GetWindowBoundsInScreen().width() -
  358. ShelfConfig::Get()->control_button_edge_spacing(
  359. true /* is_primary_axis_edge */);
  360. const int hotseat_width1 =
  361. shelf_widget1->hotseat_widget()->GetWindowBoundsInScreen().width();
  362. const int margins = 2 * ShelfConfig::Get()->GetAppIconGroupMargin();
  363. const int total_width2 =
  364. screen_util::GetDisplayBoundsWithShelf(shelf_widget2->GetNativeWindow())
  365. .width();
  366. const int nav_width2 =
  367. shelf_widget2->navigation_widget()->GetWindowBoundsInScreen().width() -
  368. ShelfConfig::Get()->control_button_edge_spacing(
  369. true /* is_primary_axis_edge */);
  370. const int hotseat_width2 =
  371. shelf_widget2->hotseat_widget()->GetWindowBoundsInScreen().width();
  372. // The shelf view and status area horizontally fill the shelf widget.
  373. const int status_width1 =
  374. shelf_widget1->status_area_widget()->GetWindowBoundsInScreen().width();
  375. EXPECT_GT(status_width1, 0);
  376. EXPECT_EQ(total_width1,
  377. nav_width1 + hotseat_width1 + margins + status_width1);
  378. const int status_width2 =
  379. shelf_widget2->status_area_widget()->GetWindowBoundsInScreen().width();
  380. EXPECT_GT(status_width2, 0);
  381. EXPECT_EQ(total_width2,
  382. nav_width2 + hotseat_width2 + margins + status_width2);
  383. }
  384. // Tests that the shelf has a slightly larger hit-region for touch-events when
  385. // it's in the auto-hidden state.
  386. TEST_F(ShelfWidgetTest, HiddenShelfHitTestTouch) {
  387. Shelf* shelf = GetPrimaryShelf();
  388. ShelfWidget* shelf_widget = GetShelfWidget();
  389. gfx::Rect shelf_bounds = shelf_widget->GetWindowBoundsInScreen();
  390. EXPECT_TRUE(!shelf_bounds.IsEmpty());
  391. ShelfLayoutManager* shelf_layout_manager =
  392. shelf_widget->shelf_layout_manager();
  393. ASSERT_TRUE(shelf_layout_manager);
  394. EXPECT_EQ(SHELF_VISIBLE, shelf_layout_manager->visibility_state());
  395. // Create a widget to make sure that the shelf does auto-hide.
  396. views::Widget* widget = new views::Widget;
  397. views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
  398. params.bounds = gfx::Rect(0, 0, 200, 200);
  399. params.context = GetContext();
  400. // Widget is now owned by the parent window.
  401. widget->Init(std::move(params));
  402. widget->Show();
  403. aura::Window* root = shelf_widget->GetNativeWindow()->GetRootWindow();
  404. ui::EventTargeter* targeter =
  405. root->GetHost()->dispatcher()->GetDefaultEventTargeter();
  406. // Touch just over the shelf. Since the shelf is visible, the window-targeter
  407. // should not find the shelf as the target.
  408. {
  409. gfx::Point event_location(20, shelf_bounds.y() - 1);
  410. ui::TouchEvent touch(ui::ET_TOUCH_PRESSED, event_location,
  411. ui::EventTimeForNow(),
  412. ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  413. EXPECT_NE(shelf_widget->GetNativeWindow(),
  414. targeter->FindTargetForEvent(root, &touch));
  415. }
  416. // Now auto-hide (hidden) the shelf.
  417. shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
  418. shelf_layout_manager->LayoutShelf();
  419. EXPECT_EQ(SHELF_AUTO_HIDE, shelf_layout_manager->visibility_state());
  420. EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_layout_manager->auto_hide_state());
  421. shelf_bounds = shelf_widget->GetWindowBoundsInScreen();
  422. EXPECT_TRUE(!shelf_bounds.IsEmpty());
  423. // Touch just over the shelf again. This time, the targeter should find the
  424. // shelf as the target.
  425. {
  426. gfx::Point event_location(20, shelf_bounds.y() - 1);
  427. ui::TouchEvent touch(ui::ET_TOUCH_PRESSED, event_location,
  428. ui::EventTimeForNow(),
  429. ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  430. EXPECT_EQ(shelf_widget->GetNativeWindow(),
  431. targeter->FindTargetForEvent(root, &touch));
  432. }
  433. }
  434. class LtrRtlShelfWidgetTest : public ShelfWidgetTest,
  435. public testing::WithParamInterface<bool> {
  436. public:
  437. LtrRtlShelfWidgetTest() : scoped_locale_(GetParam() ? "he" : "") {}
  438. LtrRtlShelfWidgetTest(const LtrRtlShelfWidgetTest&) = delete;
  439. LtrRtlShelfWidgetTest& operator=(const LtrRtlShelfWidgetTest&) = delete;
  440. ~LtrRtlShelfWidgetTest() override = default;
  441. private:
  442. // Restores locale to the default when destructor is called.
  443. base::test::ScopedRestoreICUDefaultLocale scoped_locale_;
  444. };
  445. INSTANTIATE_TEST_SUITE_P(All, LtrRtlShelfWidgetTest, testing::Bool());
  446. TEST_P(LtrRtlShelfWidgetTest, MessageCenterBounds) {
  447. // Add a notification to force the message center bubble to show with the
  448. // UnifiedSystemTrayBubble.
  449. message_center::MessageCenter::Get()->AddNotification(
  450. std::make_unique<message_center::Notification>(
  451. message_center::NOTIFICATION_TYPE_SIMPLE, base::NumberToString(0),
  452. u"test title", u"test message", ui::ImageModel(), std::u16string(),
  453. GURL(), message_center::NotifierId(),
  454. message_center::RichNotificationData(),
  455. new message_center::NotificationDelegate()));
  456. auto shelf_alignments = {ShelfAlignment::kBottom, ShelfAlignment::kLeft,
  457. ShelfAlignment::kRight};
  458. for (const auto& alignment : shelf_alignments) {
  459. GetPrimaryShelf()->SetAlignment(alignment);
  460. // Show UnifiedSystemTrayBubble, which shows a message center bubble as well
  461. // in a separate widget.
  462. GetPrimaryUnifiedSystemTray()->ShowBubble();
  463. gfx::Rect message_center_bubble_bounds_in_screen =
  464. GetPrimaryUnifiedSystemTray()
  465. ->message_center_bubble()
  466. ->GetBoundsInScreen();
  467. gfx::Rect unified_system_tray_bubble_bounds_in_screen =
  468. GetPrimaryUnifiedSystemTray()->bubble()->GetBoundsInScreen();
  469. // The MessageCenterBubble and UnifiedSystemTrayBubble should be flush
  470. // despite the shelf alignment.
  471. EXPECT_EQ(message_center_bubble_bounds_in_screen.x(),
  472. unified_system_tray_bubble_bounds_in_screen.x());
  473. EXPECT_EQ(message_center_bubble_bounds_in_screen.width(),
  474. unified_system_tray_bubble_bounds_in_screen.width());
  475. GetPrimaryUnifiedSystemTray()->CloseBubble();
  476. }
  477. }
  478. // Tests that the shelf lets mouse-events close to the edge fall through to the
  479. // window underneath.
  480. TEST_F(ShelfWidgetTest, ShelfEdgeOverlappingWindowHitTestMouse) {
  481. UpdateDisplay("500x400");
  482. ShelfWidget* shelf_widget = GetShelfWidget();
  483. gfx::Rect shelf_bounds = shelf_widget->GetWindowBoundsInScreen();
  484. EXPECT_TRUE(!shelf_bounds.IsEmpty());
  485. ShelfLayoutManager* shelf_layout_manager =
  486. shelf_widget->shelf_layout_manager();
  487. ASSERT_TRUE(shelf_layout_manager);
  488. EXPECT_EQ(SHELF_VISIBLE, shelf_layout_manager->visibility_state());
  489. // Create a Widget which overlaps the shelf in both left and bottom
  490. // alignments.
  491. const int kOverlapSize = 15;
  492. const int kWindowHeight = 200;
  493. const int kWindowWidth = 200;
  494. const gfx::Rect bounds(shelf_bounds.height() - kOverlapSize,
  495. shelf_bounds.y() - kWindowHeight + kOverlapSize,
  496. kWindowWidth, kWindowHeight);
  497. views::Widget* widget = new views::Widget;
  498. views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
  499. params.bounds = bounds;
  500. params.context = GetContext();
  501. // Widget is now owned by the parent window.
  502. widget->Init(std::move(params));
  503. // Explicitly set the bounds which will allow the widget to overlap the shelf.
  504. widget->SetBounds(bounds);
  505. widget->Show();
  506. gfx::Rect widget_bounds = widget->GetWindowBoundsInScreen();
  507. EXPECT_TRUE(widget_bounds.Intersects(shelf_bounds));
  508. aura::Window* root = widget->GetNativeWindow()->GetRootWindow();
  509. ui::EventTargeter* targeter =
  510. root->GetHost()->dispatcher()->GetDefaultEventTargeter();
  511. {
  512. // Create a mouse-event targeting the top of the shelf widget. The
  513. // window-targeter should find |widget| as the target (instead of the
  514. // shelf).
  515. gfx::Point event_location(widget_bounds.x() + 5, shelf_bounds.y() + 1);
  516. ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
  517. ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
  518. ui::EventTarget* target = targeter->FindTargetForEvent(root, &mouse);
  519. EXPECT_EQ(widget->GetNativeWindow(), target);
  520. }
  521. // Change shelf alignment to verify that the targeter insets are updated.
  522. Shelf* shelf = GetPrimaryShelf();
  523. shelf->SetAlignment(ShelfAlignment::kLeft);
  524. shelf_layout_manager->LayoutShelf();
  525. shelf_bounds = shelf_widget->GetWindowBoundsInScreen();
  526. {
  527. // Create a mouse-event targeting the right edge of the shelf widget. The
  528. // window-targeter should find |widget| as the target (instead of the
  529. // shelf).
  530. gfx::Point event_location(shelf_bounds.right() - 1, widget_bounds.y() + 5);
  531. ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
  532. ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
  533. ui::EventTarget* target = targeter->FindTargetForEvent(root, &mouse);
  534. EXPECT_EQ(widget->GetNativeWindow(), target);
  535. }
  536. // Now restore shelf alignment (bottom) and auto-hide (hidden) the shelf.
  537. shelf->SetAlignment(ShelfAlignment::kBottom);
  538. shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
  539. shelf_layout_manager->LayoutShelf();
  540. EXPECT_EQ(SHELF_AUTO_HIDE, shelf_layout_manager->visibility_state());
  541. EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_layout_manager->auto_hide_state());
  542. shelf_bounds = shelf_widget->GetWindowBoundsInScreen();
  543. EXPECT_TRUE(!shelf_bounds.IsEmpty());
  544. // Move |widget| so it still overlaps the shelf.
  545. widget->SetBounds(gfx::Rect(0,
  546. shelf_bounds.y() - kWindowHeight + kOverlapSize,
  547. kWindowWidth, kWindowHeight));
  548. widget_bounds = widget->GetWindowBoundsInScreen();
  549. EXPECT_TRUE(widget_bounds.Intersects(shelf_bounds));
  550. {
  551. // Create a mouse-event targeting the top of the shelf widget. This time,
  552. // window-target should find the shelf as the target.
  553. gfx::Point event_location(widget_bounds.x() + 5, shelf_bounds.y() + 1);
  554. ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location,
  555. ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE);
  556. ui::EventTarget* target = targeter->FindTargetForEvent(root, &mouse);
  557. EXPECT_EQ(shelf_widget->GetNativeWindow(), target);
  558. }
  559. }
  560. class TransitionAnimationWaiter
  561. : public HotseatTransitionAnimator::TestObserver {
  562. public:
  563. explicit TransitionAnimationWaiter(
  564. HotseatTransitionAnimator* hotseat_transition_animator)
  565. : hotseat_transition_animator_(hotseat_transition_animator) {
  566. hotseat_transition_animator_->SetTestObserver(this);
  567. }
  568. ~TransitionAnimationWaiter() override {
  569. hotseat_transition_animator_->SetTestObserver(nullptr);
  570. }
  571. void Wait() {
  572. run_loop_ = std::make_unique<base::RunLoop>();
  573. run_loop_->Run();
  574. }
  575. private:
  576. void OnTransitionTestAnimationEnded() override {
  577. DCHECK(run_loop_.get());
  578. run_loop_->Quit();
  579. }
  580. HotseatTransitionAnimator* hotseat_transition_animator_ = nullptr;
  581. std::unique_ptr<base::RunLoop> run_loop_;
  582. };
  583. // Tests the drag handle bounds and visibility when the in-app shelf is shown.
  584. TEST_F(ShelfWidgetTest, OpaqueBackgroundAndDragHandleTransition) {
  585. ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
  586. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  587. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  588. UpdateDisplay("800x700");
  589. ASSERT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  590. ASSERT_FALSE(GetShelfWidget()->GetOpaqueBackground()->visible());
  591. // Create a window to transition to the in-app shelf.
  592. auto window = AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 800, 800));
  593. {
  594. TransitionAnimationWaiter waiter(
  595. GetShelfWidget()->hotseat_transition_animator());
  596. waiter.Wait();
  597. }
  598. // Ensure the ShelfWidget and drag handle have the correct bounds and
  599. // visibility for in-app shelf.
  600. EXPECT_EQ(GetShelfWidget()->GetWindowBoundsInScreen(),
  601. gfx::Rect(0, 660, 800, 40));
  602. EXPECT_EQ(GetShelfWidget()->GetDragHandle()->bounds(),
  603. gfx::Rect(360, 18, 80, 4));
  604. ASSERT_TRUE(GetShelfWidget()->GetDragHandle()->GetVisible());
  605. ASSERT_TRUE(GetShelfWidget()->GetOpaqueBackground()->visible());
  606. window->Hide();
  607. ASSERT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  608. ASSERT_FALSE(GetShelfWidget()->GetOpaqueBackground()->visible());
  609. }
  610. // Tests the shelf widget does not animate for hotseat transitions during tablet
  611. // mode start.
  612. TEST_F(ShelfWidgetTest, NoAnimatingBackgroundDuringTabletModeStartToInApp) {
  613. UpdateDisplay("800x700");
  614. // Create a window so tablet mode uses in-app shelf.
  615. auto window = AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 800, 800));
  616. EXPECT_TRUE(GetShelfWidget()->GetOpaqueBackground()->visible());
  617. EXPECT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  618. ASSERT_FALSE(GetShelfWidget()->GetAnimatingBackground()->visible());
  619. ASSERT_FALSE(GetShelfWidget()
  620. ->GetAnimatingBackground()
  621. ->GetAnimator()
  622. ->is_animating());
  623. ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
  624. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  625. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  626. EXPECT_TRUE(GetShelfWidget()->GetDragHandle()->GetVisible());
  627. EXPECT_TRUE(GetShelfWidget()->GetOpaqueBackground()->visible());
  628. EXPECT_FALSE(GetShelfWidget()->GetAnimatingBackground()->visible());
  629. EXPECT_FALSE(GetShelfWidget()
  630. ->GetAnimatingBackground()
  631. ->GetAnimator()
  632. ->is_animating());
  633. }
  634. // Tests the shelf widget does not animate for hotseat transitions during tablet
  635. // mode end.
  636. TEST_F(ShelfWidgetTest, NoAnimatingBackgroundDuringTabletModeEndFromInApp) {
  637. UpdateDisplay("800x700");
  638. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  639. // Create a window so tablet mode uses in-app shelf.
  640. auto window = AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 800, 800));
  641. EXPECT_TRUE(GetShelfWidget()->GetOpaqueBackground()->visible());
  642. EXPECT_TRUE(GetShelfWidget()->GetDragHandle()->GetVisible());
  643. ASSERT_FALSE(GetShelfWidget()->GetAnimatingBackground()->visible());
  644. ASSERT_FALSE(GetShelfWidget()
  645. ->GetAnimatingBackground()
  646. ->GetAnimator()
  647. ->is_animating());
  648. ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
  649. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  650. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
  651. EXPECT_TRUE(GetShelfWidget()->GetOpaqueBackground()->visible());
  652. EXPECT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  653. EXPECT_FALSE(GetShelfWidget()->GetAnimatingBackground()->visible());
  654. EXPECT_FALSE(GetShelfWidget()
  655. ->GetAnimatingBackground()
  656. ->GetAnimator()
  657. ->is_animating());
  658. }
  659. // Tests the shelf widget does not animate for hotseat transitions during tablet
  660. // mode start with no app windows.
  661. TEST_F(ShelfWidgetTest, NoAnimatingBackgroundDuringTabletModeStartToHome) {
  662. UpdateDisplay("800x700");
  663. EXPECT_TRUE(GetShelfWidget()->GetOpaqueBackground()->visible());
  664. EXPECT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  665. ASSERT_FALSE(GetShelfWidget()->GetAnimatingBackground()->visible());
  666. ASSERT_FALSE(GetShelfWidget()
  667. ->GetAnimatingBackground()
  668. ->GetAnimator()
  669. ->is_animating());
  670. ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
  671. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  672. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  673. EXPECT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  674. EXPECT_FALSE(GetShelfWidget()->GetOpaqueBackground()->visible());
  675. EXPECT_FALSE(GetShelfWidget()->GetAnimatingBackground()->visible());
  676. EXPECT_FALSE(GetShelfWidget()
  677. ->GetAnimatingBackground()
  678. ->GetAnimator()
  679. ->is_animating());
  680. }
  681. // Tests the shelf widget does not animate for hotseat transitions during tablet
  682. // mode end with no app windows.
  683. TEST_F(ShelfWidgetTest, NoAnimatingBackgroundDuringTabletModeEndFromHome) {
  684. UpdateDisplay("800x700");
  685. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  686. EXPECT_FALSE(GetShelfWidget()->GetOpaqueBackground()->visible());
  687. EXPECT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  688. ASSERT_FALSE(GetShelfWidget()->GetAnimatingBackground()->visible());
  689. ASSERT_FALSE(GetShelfWidget()
  690. ->GetAnimatingBackground()
  691. ->GetAnimator()
  692. ->is_animating());
  693. ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
  694. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  695. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
  696. EXPECT_TRUE(GetShelfWidget()->GetOpaqueBackground()->visible());
  697. EXPECT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  698. EXPECT_FALSE(GetShelfWidget()->GetAnimatingBackground()->visible());
  699. EXPECT_FALSE(GetShelfWidget()
  700. ->GetAnimatingBackground()
  701. ->GetAnimator()
  702. ->is_animating());
  703. }
  704. // Tests the shelf widget does not animate for hotseat transitions if the screen
  705. // is locked.
  706. TEST_F(ShelfWidgetTest, NoAnimatingBackgroundOnLockScreen) {
  707. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  708. UpdateDisplay("800x700");
  709. ASSERT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  710. ASSERT_FALSE(GetShelfWidget()->GetOpaqueBackground()->visible());
  711. // Create a window to transition to the in-app shelf.
  712. auto window = AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 800, 800));
  713. // At this point animations have zero duration, so the transition happens
  714. // immediately.
  715. ASSERT_TRUE(GetShelfWidget()->GetDragHandle()->GetVisible());
  716. ASSERT_TRUE(GetShelfWidget()->GetOpaqueBackground()->visible());
  717. ASSERT_FALSE(GetShelfWidget()->GetAnimatingBackground()->visible());
  718. GetSessionControllerClient()->SetSessionState(SessionState::LOCKED);
  719. ASSERT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  720. ASSERT_FALSE(GetShelfWidget()->GetOpaqueBackground()->visible());
  721. ASSERT_FALSE(GetShelfWidget()->GetAnimatingBackground()->visible());
  722. ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
  723. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  724. // Hide the test window, and verify that does not start shelf animation.
  725. window->Hide();
  726. ASSERT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  727. ASSERT_FALSE(GetShelfWidget()->GetOpaqueBackground()->visible());
  728. ASSERT_FALSE(GetShelfWidget()->GetAnimatingBackground()->visible());
  729. ASSERT_FALSE(GetShelfWidget()
  730. ->GetAnimatingBackground()
  731. ->GetAnimator()
  732. ->is_animating());
  733. // Ensure the ShelfWidget and the drag handle are still hidden (i.e. in home
  734. // screen state) when the screen is unlocked.
  735. GetSessionControllerClient()->SetSessionState(SessionState::ACTIVE);
  736. ASSERT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  737. ASSERT_FALSE(GetShelfWidget()->GetOpaqueBackground()->visible());
  738. ASSERT_FALSE(GetShelfWidget()->GetAnimatingBackground()->visible());
  739. ASSERT_FALSE(GetShelfWidget()
  740. ->GetAnimatingBackground()
  741. ->GetAnimator()
  742. ->is_animating());
  743. }
  744. // Tests the shelf widget animations for hotseat transitions are stopped when
  745. // the screen is locked.
  746. TEST_F(ShelfWidgetTest, ScreenLockStopsHotseatTransitionAnimation) {
  747. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  748. UpdateDisplay("800x700");
  749. ASSERT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  750. ASSERT_FALSE(GetShelfWidget()->GetOpaqueBackground()->visible());
  751. ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
  752. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  753. // Create a window to transition to the in-app shelf.
  754. auto window = AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 800, 800));
  755. ASSERT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  756. ASSERT_FALSE(GetShelfWidget()->GetOpaqueBackground()->visible());
  757. ASSERT_TRUE(GetShelfWidget()->GetAnimatingBackground()->visible());
  758. ASSERT_TRUE(GetShelfWidget()
  759. ->GetAnimatingBackground()
  760. ->GetAnimator()
  761. ->is_animating());
  762. GetSessionControllerClient()->SetSessionState(SessionState::LOCKED);
  763. ASSERT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  764. ASSERT_FALSE(GetShelfWidget()->GetOpaqueBackground()->visible());
  765. ASSERT_FALSE(GetShelfWidget()->GetAnimatingBackground()->visible());
  766. ASSERT_FALSE(GetShelfWidget()
  767. ->GetAnimatingBackground()
  768. ->GetAnimator()
  769. ->is_animating());
  770. GetSessionControllerClient()->SetSessionState(SessionState::ACTIVE);
  771. // Ensure the ShelfWidget and the drag handle have the correct bounds and
  772. // visibility for in-app shelf when the screen is unlocked.
  773. ASSERT_TRUE(GetShelfWidget()->GetDragHandle()->GetVisible());
  774. ASSERT_TRUE(GetShelfWidget()->GetOpaqueBackground()->visible());
  775. ASSERT_FALSE(GetShelfWidget()->GetAnimatingBackground()->visible());
  776. EXPECT_EQ(GetShelfWidget()->GetWindowBoundsInScreen(),
  777. gfx::Rect(0, 660, 800, 40));
  778. EXPECT_EQ(GetShelfWidget()->GetDragHandle()->bounds(),
  779. gfx::Rect(360, 18, 80, 4));
  780. }
  781. // Tests the shelf widget's opaque background gets reshown if hotseat transition
  782. // from kShown state gets interrupted by a transition back to kShown state.
  783. TEST_F(ShelfWidgetTest,
  784. OpaqueBackgroundReshownAfterTransitionFromHomeChangesBackToHome) {
  785. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
  786. UpdateDisplay("800x700");
  787. ASSERT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  788. ASSERT_FALSE(GetShelfWidget()->GetOpaqueBackground()->visible());
  789. ui::ScopedAnimationDurationScaleMode non_zero_duration_mode(
  790. ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
  791. // Create a window to transition to the in-app shelf.
  792. auto window = AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 800, 800));
  793. ASSERT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  794. ASSERT_FALSE(GetShelfWidget()->GetOpaqueBackground()->visible());
  795. ASSERT_TRUE(GetShelfWidget()->GetAnimatingBackground()->visible());
  796. ASSERT_TRUE(GetShelfWidget()
  797. ->GetAnimatingBackground()
  798. ->GetAnimator()
  799. ->is_animating());
  800. const gfx::Rect animating_background_bounds =
  801. GetShelfWidget()->GetAnimatingBackground()->bounds();
  802. EXPECT_NE(GetShelfWidget()->GetAnimatingBackground()->transform(),
  803. GetShelfWidget()->GetAnimatingBackground()->GetTargetTransform());
  804. // Go back home before the transition to in-app shelf finishes.
  805. window->Hide();
  806. // The shelf background should still be animating at this point, but to
  807. // different bounds.
  808. ASSERT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  809. ASSERT_FALSE(GetShelfWidget()->GetOpaqueBackground()->visible());
  810. ASSERT_TRUE(GetShelfWidget()->GetAnimatingBackground()->visible());
  811. ASSERT_TRUE(GetShelfWidget()
  812. ->GetAnimatingBackground()
  813. ->GetAnimator()
  814. ->is_animating());
  815. EXPECT_EQ(animating_background_bounds,
  816. GetShelfWidget()->GetAnimatingBackground()->bounds());
  817. // The original animation did not have a chance to update the transform yet,
  818. // so the current transform matches the original state, that matches the new
  819. // target state.
  820. EXPECT_EQ(GetShelfWidget()->GetAnimatingBackground()->transform(),
  821. GetShelfWidget()->GetAnimatingBackground()->GetTargetTransform());
  822. // Run the current animation to the end, end verify the opaque background is
  823. // reshown after ending tablet mode.
  824. GetShelfWidget()->GetAnimatingBackground()->GetAnimator()->StopAnimating();
  825. ASSERT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  826. ASSERT_FALSE(GetShelfWidget()->GetOpaqueBackground()->visible());
  827. ASSERT_FALSE(GetShelfWidget()->GetAnimatingBackground()->visible());
  828. Shell::Get()->tablet_mode_controller()->SetEnabledForTest(false);
  829. EXPECT_FALSE(GetShelfWidget()->GetDragHandle()->GetVisible());
  830. ASSERT_TRUE(GetShelfWidget()->GetOpaqueBackground()->visible());
  831. ASSERT_FALSE(GetShelfWidget()->GetAnimatingBackground()->visible());
  832. }
  833. class ShelfWidgetAfterLoginTest : public AshTestBase {
  834. public:
  835. ShelfWidgetAfterLoginTest() { set_start_session(false); }
  836. ShelfWidgetAfterLoginTest(const ShelfWidgetAfterLoginTest&) = delete;
  837. ShelfWidgetAfterLoginTest& operator=(const ShelfWidgetAfterLoginTest&) =
  838. delete;
  839. ~ShelfWidgetAfterLoginTest() override = default;
  840. void TestShelf(ShelfAlignment alignment,
  841. ShelfAutoHideBehavior auto_hide_behavior,
  842. ShelfVisibilityState expected_shelf_visibility_state,
  843. ShelfAutoHideState expected_shelf_auto_hide_state) {
  844. // Simulate login.
  845. CreateUserSessions(1);
  846. // Simulate shelf settings being applied from profile prefs.
  847. Shelf* shelf = GetPrimaryShelf();
  848. ASSERT_NE(nullptr, shelf);
  849. shelf->SetAlignment(alignment);
  850. shelf->SetAutoHideBehavior(auto_hide_behavior);
  851. shelf->UpdateVisibilityState();
  852. // Ensure settings are applied correctly.
  853. EXPECT_EQ(alignment, shelf->alignment());
  854. EXPECT_EQ(auto_hide_behavior, shelf->auto_hide_behavior());
  855. EXPECT_EQ(expected_shelf_visibility_state, shelf->GetVisibilityState());
  856. EXPECT_EQ(expected_shelf_auto_hide_state, shelf->GetAutoHideState());
  857. }
  858. };
  859. TEST_F(ShelfWidgetAfterLoginTest, InitialValues) {
  860. // Ensure shelf components are created.
  861. Shelf* shelf = GetPrimaryShelf();
  862. ASSERT_NE(nullptr, shelf);
  863. ShelfWidget* shelf_widget = GetShelfWidget();
  864. ASSERT_NE(nullptr, shelf_widget);
  865. ASSERT_NE(nullptr, shelf_widget->shelf_view_for_testing());
  866. ASSERT_NE(nullptr, shelf_widget->GetLoginShelfView());
  867. ASSERT_NE(nullptr, shelf_widget->shelf_layout_manager());
  868. // Ensure settings are correct before login.
  869. EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
  870. EXPECT_EQ(ShelfAlignment::kBottomLocked, shelf->alignment());
  871. EXPECT_EQ(ShelfAutoHideBehavior::kAlwaysHidden, shelf->auto_hide_behavior());
  872. EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
  873. // Simulate login.
  874. CreateUserSessions(1);
  875. // Ensure settings are correct after login.
  876. EXPECT_EQ(SHELF_VISIBLE, shelf->GetVisibilityState());
  877. EXPECT_EQ(ShelfAlignment::kBottom, shelf->alignment());
  878. EXPECT_EQ(ShelfAutoHideBehavior::kNever, shelf->auto_hide_behavior());
  879. // "Hidden" is the default state when auto-hide is turned off.
  880. EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState());
  881. }
  882. TEST_F(ShelfWidgetAfterLoginTest, CreateAutoHideAlwaysShelf) {
  883. // The actual auto hide state is shown because there are no open windows.
  884. TestShelf(ShelfAlignment::kBottom, ShelfAutoHideBehavior::kAlways,
  885. SHELF_AUTO_HIDE, SHELF_AUTO_HIDE_SHOWN);
  886. }
  887. TEST_F(ShelfWidgetAfterLoginTest, CreateAutoHideNeverShelf) {
  888. // The auto hide state 'HIDDEN' is returned for any non-auto-hide behavior.
  889. TestShelf(ShelfAlignment::kLeft, ShelfAutoHideBehavior::kNever, SHELF_VISIBLE,
  890. SHELF_AUTO_HIDE_HIDDEN);
  891. }
  892. TEST_F(ShelfWidgetAfterLoginTest, CreateAutoHideAlwaysHideShelf) {
  893. // The auto hide state 'HIDDEN' is returned for any non-auto-hide behavior.
  894. TestShelf(ShelfAlignment::kRight, ShelfAutoHideBehavior::kAlwaysHidden,
  895. SHELF_HIDDEN, SHELF_AUTO_HIDE_HIDDEN);
  896. }
  897. TEST_F(ShelfWidgetAfterLoginTest, CreateLockedShelf) {
  898. // The auto hide state 'HIDDEN' is returned for any non-auto-hide behavior.
  899. TestShelf(ShelfAlignment::kBottomLocked, ShelfAutoHideBehavior::kNever,
  900. SHELF_VISIBLE, SHELF_AUTO_HIDE_HIDDEN);
  901. }
  902. class ShelfWidgetViewsVisibilityTest : public AshTestBase {
  903. public:
  904. ShelfWidgetViewsVisibilityTest() { set_start_session(false); }
  905. ShelfWidgetViewsVisibilityTest(const ShelfWidgetViewsVisibilityTest&) =
  906. delete;
  907. ShelfWidgetViewsVisibilityTest& operator=(
  908. const ShelfWidgetViewsVisibilityTest&) = delete;
  909. ~ShelfWidgetViewsVisibilityTest() override = default;
  910. enum ShelfVisibility {
  911. kNone, // Shelf views hidden.
  912. kShelf, // ShelfView visible.
  913. kLoginShelf, // LoginShelfView visible.
  914. };
  915. void InitShelfVariables() {
  916. // Create setup with 2 displays primary and secondary.
  917. UpdateDisplay("800x600,800x600");
  918. aura::Window::Windows root_windows = Shell::GetAllRootWindows();
  919. ASSERT_EQ(2u, root_windows.size());
  920. primary_shelf_widget_ = Shelf::ForWindow(root_windows[0])->shelf_widget();
  921. ASSERT_NE(nullptr, primary_shelf_widget_);
  922. secondary_shelf_widget_ = Shelf::ForWindow(root_windows[1])->shelf_widget();
  923. ASSERT_NE(nullptr, secondary_shelf_widget_);
  924. }
  925. void ExpectVisible(session_manager::SessionState state,
  926. ShelfVisibility primary_shelf_visibility,
  927. ShelfVisibility secondary_shelf_visibility) {
  928. GetSessionControllerClient()->SetSessionState(state);
  929. EXPECT_EQ(primary_shelf_visibility == kNone,
  930. !primary_shelf_widget_->IsVisible());
  931. if (primary_shelf_visibility != kNone) {
  932. EXPECT_EQ(primary_shelf_visibility == kLoginShelf,
  933. primary_shelf_widget_->GetLoginShelfView()->GetVisible());
  934. EXPECT_EQ(primary_shelf_visibility == kShelf,
  935. primary_shelf_widget_->shelf_view_for_testing()->GetVisible());
  936. }
  937. EXPECT_EQ(secondary_shelf_visibility == kNone,
  938. !secondary_shelf_widget_->IsVisible());
  939. if (secondary_shelf_visibility != kNone) {
  940. EXPECT_EQ(secondary_shelf_visibility == kLoginShelf,
  941. secondary_shelf_widget_->GetLoginShelfView()->GetVisible());
  942. EXPECT_EQ(
  943. secondary_shelf_visibility == kShelf,
  944. secondary_shelf_widget_->shelf_view_for_testing()->GetVisible());
  945. }
  946. }
  947. private:
  948. ShelfWidget* primary_shelf_widget_ = nullptr;
  949. ShelfWidget* secondary_shelf_widget_ = nullptr;
  950. };
  951. TEST_F(ShelfWidgetViewsVisibilityTest, LoginViewsLockViews) {
  952. ASSERT_NO_FATAL_FAILURE(InitShelfVariables());
  953. ExpectVisible(SessionState::UNKNOWN, kNone /*primary*/, kNone /*secondary*/);
  954. ExpectVisible(SessionState::OOBE, kLoginShelf, kNone);
  955. ExpectVisible(SessionState::LOGIN_PRIMARY, kLoginShelf, kNone);
  956. SimulateUserLogin("user1@test.com");
  957. ExpectVisible(SessionState::LOGGED_IN_NOT_ACTIVE, kLoginShelf, kNone);
  958. ExpectVisible(SessionState::ACTIVE, kShelf, kShelf);
  959. ExpectVisible(SessionState::LOCKED, kLoginShelf, kNone);
  960. ExpectVisible(SessionState::ACTIVE, kShelf, kShelf);
  961. ExpectVisible(SessionState::LOGIN_SECONDARY, kLoginShelf, kNone);
  962. ExpectVisible(SessionState::ACTIVE, kShelf, kShelf);
  963. }
  964. class ShelfWidgetVirtualKeyboardTest : public AshTestBase {
  965. protected:
  966. void SetUp() override {
  967. base::CommandLine::ForCurrentProcess()->AppendSwitch(
  968. keyboard::switches::kEnableVirtualKeyboard);
  969. AshTestBase::SetUp();
  970. ASSERT_TRUE(keyboard::IsKeyboardEnabled());
  971. keyboard::test::WaitUntilLoaded();
  972. // These tests only apply to the floating virtual keyboard, as it is the
  973. // only case where both the virtual keyboard and the shelf are visible.
  974. const gfx::Rect keyboard_bounds(0, 0, 1, 1);
  975. keyboard_ui_controller()->SetContainerType(
  976. keyboard::ContainerType::kFloating, keyboard_bounds, base::DoNothing());
  977. }
  978. keyboard::KeyboardUIController* keyboard_ui_controller() {
  979. return keyboard::KeyboardUIController::Get();
  980. }
  981. };
  982. TEST_F(ShelfWidgetVirtualKeyboardTest, ClickingHidesVirtualKeyboard) {
  983. keyboard_ui_controller()->ShowKeyboard(false /* locked */);
  984. ASSERT_TRUE(keyboard::WaitUntilShown());
  985. ui::test::EventGenerator* generator = GetEventGenerator();
  986. generator->set_current_screen_location(
  987. GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint());
  988. generator->ClickLeftButton();
  989. // Times out if test fails.
  990. ASSERT_TRUE(keyboard::WaitUntilHidden());
  991. }
  992. TEST_F(ShelfWidgetVirtualKeyboardTest, TappingHidesVirtualKeyboard) {
  993. keyboard_ui_controller()->ShowKeyboard(false /* locked */);
  994. ASSERT_TRUE(keyboard::WaitUntilShown());
  995. ui::test::EventGenerator* generator = GetEventGenerator();
  996. generator->set_current_screen_location(
  997. GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint());
  998. generator->PressTouch();
  999. // Times out if test fails.
  1000. ASSERT_TRUE(keyboard::WaitUntilHidden());
  1001. }
  1002. TEST_F(ShelfWidgetVirtualKeyboardTest, DoesNotHideLockedVirtualKeyboard) {
  1003. keyboard_ui_controller()->ShowKeyboard(true /* locked */);
  1004. ASSERT_TRUE(keyboard::WaitUntilShown());
  1005. ui::test::EventGenerator* generator = GetEventGenerator();
  1006. generator->set_current_screen_location(
  1007. GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint());
  1008. generator->ClickLeftButton();
  1009. EXPECT_FALSE(keyboard::IsKeyboardHiding());
  1010. generator->PressTouch();
  1011. EXPECT_FALSE(keyboard::IsKeyboardHiding());
  1012. }
  1013. } // namespace
  1014. } // namespace ash