screen_orientation_controller_unittest.cc 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982
  1. // Copyright 2014 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/display/screen_orientation_controller.h"
  5. #include <memory>
  6. #include <vector>
  7. #include "ash/accelerometer/accelerometer_reader.h"
  8. #include "ash/accelerometer/accelerometer_types.h"
  9. #include "ash/constants/app_types.h"
  10. #include "ash/constants/ash_switches.h"
  11. #include "ash/display/screen_orientation_controller.h"
  12. #include "ash/display/screen_orientation_controller_test_api.h"
  13. #include "ash/shell.h"
  14. #include "ash/system/screen_layout_observer.h"
  15. #include "ash/test/ash_test_base.h"
  16. #include "ash/test/ash_test_helper.h"
  17. #include "ash/test_shell_delegate.h"
  18. #include "ash/wm/splitview/split_view_controller.h"
  19. #include "ash/wm/tablet_mode/tablet_mode_controller.h"
  20. #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
  21. #include "ash/wm/window_state.h"
  22. #include "ash/wm/window_util.h"
  23. #include "base/command_line.h"
  24. #include "base/numerics/math_constants.h"
  25. #include "ui/aura/client/aura_constants.h"
  26. #include "ui/aura/window.h"
  27. #include "ui/compositor/layer_type.h"
  28. #include "ui/display/display.h"
  29. #include "ui/display/display_switches.h"
  30. #include "ui/display/manager/display_manager.h"
  31. #include "ui/display/manager/managed_display_info.h"
  32. #include "ui/display/test/display_manager_test_api.h"
  33. #include "ui/events/event_constants.h"
  34. #include "ui/wm/core/window_util.h"
  35. #include "ui/wm/public/activation_client.h"
  36. namespace ash {
  37. namespace {
  38. using base::kMeanGravityFloat;
  39. const float kDegreesToRadians = 3.1415926f / 180.0f;
  40. display::ManagedDisplayInfo CreateDisplayInfo(int64_t id,
  41. const gfx::Rect& bounds) {
  42. display::ManagedDisplayInfo info(id, "dummy", false);
  43. info.SetBounds(bounds);
  44. return info;
  45. }
  46. void EnableTabletMode(bool enable) {
  47. Shell::Get()->tablet_mode_controller()->ForceUiTabletModeState(enable);
  48. }
  49. bool RotationLocked() {
  50. return Shell::Get()->screen_orientation_controller()->rotation_locked();
  51. }
  52. bool UserRotationLocked() {
  53. return Shell::Get()->screen_orientation_controller()->user_rotation_locked();
  54. }
  55. void SetDisplayRotationById(int64_t display_id,
  56. display::Display::Rotation rotation) {
  57. Shell::Get()->display_manager()->SetDisplayRotation(
  58. display_id, rotation, display::Display::RotationSource::USER);
  59. }
  60. void SetInternalDisplayRotation(display::Display::Rotation rotation) {
  61. SetDisplayRotationById(display::Display::InternalDisplayId(), rotation);
  62. }
  63. void TriggerLidUpdate(const gfx::Vector3dF& lid) {
  64. AccelerometerUpdate update;
  65. update.Set(ACCELEROMETER_SOURCE_SCREEN, lid.x(), lid.y(), lid.z());
  66. Shell::Get()->screen_orientation_controller()->OnAccelerometerUpdated(update);
  67. }
  68. // Shows |child| and adds |child| to |parent|.
  69. void AddWindowAndShow(aura::Window* child, aura::Window* parent) {
  70. child->Show();
  71. parent->AddChild(child);
  72. }
  73. // Adds |child| to |parent| and activates |parent|.
  74. void AddWindowAndActivateParent(aura::Window* child, aura::Window* parent) {
  75. AddWindowAndShow(child, parent);
  76. Shell::Get()->activation_client()->ActivateWindow(parent);
  77. }
  78. void Lock(aura::Window* window, chromeos::OrientationType orientation_lock) {
  79. Shell::Get()->screen_orientation_controller()->LockOrientationForWindow(
  80. window, orientation_lock);
  81. }
  82. void Unlock(aura::Window* window) {
  83. Shell::Get()->screen_orientation_controller()->UnlockOrientationForWindow(
  84. window);
  85. }
  86. // Creates a window of type WINDOW_TYPE_CONTROL.
  87. std::unique_ptr<aura::Window> CreateControlWindow() {
  88. std::unique_ptr<aura::Window> window = std::make_unique<aura::Window>(
  89. nullptr, aura::client::WindowType::WINDOW_TYPE_CONTROL);
  90. window->Init(ui::LAYER_NOT_DRAWN);
  91. window->set_owned_by_parent(false);
  92. return window;
  93. }
  94. } // namespace
  95. class ScreenOrientationControllerTest : public AshTestBase {
  96. public:
  97. ScreenOrientationControllerTest() = default;
  98. ScreenOrientationControllerTest(const ScreenOrientationControllerTest&) =
  99. delete;
  100. ScreenOrientationControllerTest& operator=(
  101. const ScreenOrientationControllerTest&) = delete;
  102. ~ScreenOrientationControllerTest() override = default;
  103. // AshTestBase:
  104. void SetUp() override {
  105. base::CommandLine::ForCurrentProcess()->AppendSwitch(
  106. ::switches::kUseFirstDisplayAsInternal);
  107. base::CommandLine::ForCurrentProcess()->AppendSwitch(
  108. switches::kAshEnableTabletMode);
  109. AshTestBase::SetUp();
  110. }
  111. protected:
  112. aura::Window* CreateAppWindowInShellWithId(int id) {
  113. aura::Window* window = CreateTestWindowInShellWithId(id);
  114. window->SetProperty(aura::client::kAppType,
  115. static_cast<int>(AppType::CHROME_APP));
  116. return window;
  117. }
  118. void SetSystemRotationLocked(bool rotation_locked) {
  119. ScreenOrientationControllerTestApi(
  120. Shell::Get()->screen_orientation_controller())
  121. .SetRotationLocked(rotation_locked);
  122. }
  123. void SetUserRotationLocked(bool rotation_locked) {
  124. if (Shell::Get()->screen_orientation_controller()->user_rotation_locked() !=
  125. rotation_locked) {
  126. Shell::Get()->screen_orientation_controller()->ToggleUserRotationLock();
  127. }
  128. }
  129. chromeos::OrientationType UserLockedOrientation() const {
  130. ScreenOrientationControllerTestApi test_api(
  131. Shell::Get()->screen_orientation_controller());
  132. return test_api.UserLockedOrientation();
  133. }
  134. SplitViewController* split_view_controller() {
  135. return SplitViewController::Get(Shell::GetPrimaryRootWindow());
  136. }
  137. };
  138. // Tests that a Window can lock rotation.
  139. TEST_F(ScreenOrientationControllerTest, LockOrientation) {
  140. EnableTabletMode(true);
  141. std::unique_ptr<aura::Window> child_window = CreateControlWindow();
  142. std::unique_ptr<aura::Window> focus_window(CreateAppWindowInShellWithId(0));
  143. ASSERT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  144. ASSERT_FALSE(RotationLocked());
  145. AddWindowAndActivateParent(child_window.get(), focus_window.get());
  146. Lock(child_window.get(), chromeos::OrientationType::kLandscape);
  147. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  148. EXPECT_TRUE(RotationLocked());
  149. auto modal = CreateTestWindow(gfx::Rect(0, 0, 400, 400));
  150. modal->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_SYSTEM);
  151. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  152. EXPECT_TRUE(RotationLocked());
  153. }
  154. // Tests that a Window can unlock rotation.
  155. TEST_F(ScreenOrientationControllerTest, Unlock) {
  156. EnableTabletMode(true);
  157. std::unique_ptr<aura::Window> child_window = CreateControlWindow();
  158. std::unique_ptr<aura::Window> focus_window(CreateAppWindowInShellWithId(0));
  159. ASSERT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  160. ASSERT_FALSE(RotationLocked());
  161. AddWindowAndActivateParent(child_window.get(), focus_window.get());
  162. Lock(child_window.get(), chromeos::OrientationType::kLandscape);
  163. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  164. EXPECT_TRUE(RotationLocked());
  165. Unlock(child_window.get());
  166. EXPECT_FALSE(RotationLocked());
  167. }
  168. // Tests that a Window is able to change the orientation of the display after
  169. // having locked rotation.
  170. TEST_F(ScreenOrientationControllerTest, OrientationChanges) {
  171. EnableTabletMode(true);
  172. std::unique_ptr<aura::Window> child_window = CreateControlWindow();
  173. std::unique_ptr<aura::Window> focus_window(CreateAppWindowInShellWithId(0));
  174. ASSERT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  175. ASSERT_FALSE(RotationLocked());
  176. AddWindowAndActivateParent(child_window.get(), focus_window.get());
  177. Lock(child_window.get(), chromeos::OrientationType::kPortrait);
  178. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  179. EXPECT_TRUE(RotationLocked());
  180. Lock(child_window.get(), chromeos::OrientationType::kLandscape);
  181. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  182. }
  183. // Tests that orientation can only be set by the first Window that has set a
  184. // rotation lock.
  185. TEST_F(ScreenOrientationControllerTest, SecondContentCannotChangeOrientation) {
  186. EnableTabletMode(true);
  187. std::unique_ptr<aura::Window> child_window1 = CreateControlWindow();
  188. std::unique_ptr<aura::Window> child_window2 = CreateControlWindow();
  189. std::unique_ptr<aura::Window> focus_window1(CreateAppWindowInShellWithId(0));
  190. std::unique_ptr<aura::Window> focus_window2(CreateAppWindowInShellWithId(1));
  191. AddWindowAndActivateParent(child_window1.get(), focus_window1.get());
  192. AddWindowAndShow(child_window2.get(), focus_window2.get());
  193. Lock(child_window1.get(), chromeos::OrientationType::kLandscape);
  194. Lock(child_window2.get(), chromeos::OrientationType::kPortrait);
  195. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  196. }
  197. // Tests that only the Window that set a rotation lock can perform an unlock.
  198. TEST_F(ScreenOrientationControllerTest, SecondContentCannotUnlock) {
  199. EnableTabletMode(true);
  200. std::unique_ptr<aura::Window> child_window1 = CreateControlWindow();
  201. std::unique_ptr<aura::Window> child_window2 = CreateControlWindow();
  202. std::unique_ptr<aura::Window> focus_window1(CreateAppWindowInShellWithId(0));
  203. std::unique_ptr<aura::Window> focus_window2(CreateAppWindowInShellWithId(1));
  204. AddWindowAndActivateParent(child_window1.get(), focus_window1.get());
  205. AddWindowAndShow(child_window2.get(), focus_window2.get());
  206. Lock(child_window1.get(), chromeos::OrientationType::kLandscape);
  207. Unlock(child_window2.get());
  208. EXPECT_TRUE(RotationLocked());
  209. }
  210. // Tests that a rotation lock is applied only while the Window are a part of the
  211. // active window.
  212. TEST_F(ScreenOrientationControllerTest, ActiveWindowChangesUpdateLock) {
  213. EnableTabletMode(true);
  214. std::unique_ptr<aura::Window> child_window = CreateControlWindow();
  215. std::unique_ptr<aura::Window> focus_window1(CreateAppWindowInShellWithId(0));
  216. std::unique_ptr<aura::Window> focus_window2(CreateAppWindowInShellWithId(1));
  217. AddWindowAndActivateParent(child_window.get(), focus_window1.get());
  218. Lock(child_window.get(), chromeos::OrientationType::kLandscape);
  219. ASSERT_TRUE(RotationLocked());
  220. ::wm::ActivationClient* activation_client = Shell::Get()->activation_client();
  221. activation_client->ActivateWindow(focus_window2.get());
  222. EXPECT_FALSE(RotationLocked());
  223. activation_client->ActivateWindow(focus_window1.get());
  224. EXPECT_TRUE(RotationLocked());
  225. }
  226. // Tests that switching between windows with different orientation locks change
  227. // the orientation.
  228. TEST_F(ScreenOrientationControllerTest, ActiveWindowChangesUpdateOrientation) {
  229. EnableTabletMode(true);
  230. std::unique_ptr<aura::Window> child_window1 = CreateControlWindow();
  231. std::unique_ptr<aura::Window> child_window2 = CreateControlWindow();
  232. std::unique_ptr<aura::Window> focus_window1(CreateAppWindowInShellWithId(0));
  233. std::unique_ptr<aura::Window> focus_window2(CreateAppWindowInShellWithId(1));
  234. AddWindowAndActivateParent(child_window1.get(), focus_window1.get());
  235. AddWindowAndShow(child_window2.get(), focus_window2.get());
  236. Lock(child_window1.get(), chromeos::OrientationType::kLandscape);
  237. Lock(child_window2.get(), chromeos::OrientationType::kPortrait);
  238. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  239. ::wm::ActivationClient* activation_client = Shell::Get()->activation_client();
  240. activation_client->ActivateWindow(focus_window2.get());
  241. EXPECT_TRUE(RotationLocked());
  242. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  243. activation_client->ActivateWindow(focus_window1.get());
  244. EXPECT_TRUE(RotationLocked());
  245. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  246. }
  247. // Tests that a rotation lock is removed when the setting window is hidden, and
  248. // that it is reapplied when the window becomes visible.
  249. TEST_F(ScreenOrientationControllerTest, VisibilityChangesLock) {
  250. EnableTabletMode(true);
  251. std::unique_ptr<aura::Window> child_window = CreateControlWindow();
  252. std::unique_ptr<aura::Window> focus_window(CreateAppWindowInShellWithId(0));
  253. AddWindowAndActivateParent(child_window.get(), focus_window.get());
  254. Lock(child_window.get(), chromeos::OrientationType::kLandscape);
  255. EXPECT_TRUE(RotationLocked());
  256. child_window->Hide();
  257. EXPECT_FALSE(RotationLocked());
  258. child_window->Show();
  259. EXPECT_TRUE(RotationLocked());
  260. }
  261. // Tests that when a window is destroyed that its rotation lock is removed, and
  262. // window activations no longer change the lock
  263. TEST_F(ScreenOrientationControllerTest, WindowDestructionRemovesLock) {
  264. EnableTabletMode(true);
  265. std::unique_ptr<aura::Window> child_window = CreateControlWindow();
  266. std::unique_ptr<aura::Window> focus_window1(CreateAppWindowInShellWithId(0));
  267. std::unique_ptr<aura::Window> focus_window2(CreateAppWindowInShellWithId(1));
  268. AddWindowAndActivateParent(child_window.get(), focus_window1.get());
  269. Lock(child_window.get(), chromeos::OrientationType::kLandscape);
  270. ASSERT_TRUE(RotationLocked());
  271. focus_window1->RemoveChild(child_window.get());
  272. child_window.reset();
  273. EXPECT_FALSE(RotationLocked());
  274. ::wm::ActivationClient* activation_client = Shell::Get()->activation_client();
  275. activation_client->ActivateWindow(focus_window2.get());
  276. EXPECT_FALSE(RotationLocked());
  277. activation_client->ActivateWindow(focus_window1.get());
  278. EXPECT_FALSE(RotationLocked());
  279. }
  280. TEST_F(ScreenOrientationControllerTest, SplitViewPreventsLock) {
  281. EnableTabletMode(true);
  282. std::unique_ptr<aura::Window> child_window1 = CreateControlWindow();
  283. std::unique_ptr<aura::Window> child_window2 = CreateControlWindow();
  284. std::unique_ptr<aura::Window> focus_window1(CreateAppWindowInShellWithId(0));
  285. std::unique_ptr<aura::Window> focus_window2(CreateAppWindowInShellWithId(1));
  286. AddWindowAndActivateParent(child_window1.get(), focus_window1.get());
  287. AddWindowAndShow(child_window2.get(), focus_window2.get());
  288. Lock(child_window1.get(), chromeos::OrientationType::kLandscape);
  289. Lock(child_window2.get(), chromeos::OrientationType::kPortrait);
  290. ASSERT_TRUE(RotationLocked());
  291. split_view_controller()->SnapWindow(focus_window1.get(),
  292. SplitViewController::LEFT);
  293. split_view_controller()->SnapWindow(focus_window1.get(),
  294. SplitViewController::RIGHT);
  295. EXPECT_FALSE(RotationLocked());
  296. split_view_controller()->EndSplitView();
  297. EXPECT_TRUE(RotationLocked());
  298. }
  299. // Tests that accelerometer readings in each of the screen angles will trigger a
  300. // rotation of the internal display.
  301. TEST_F(ScreenOrientationControllerTest, DisplayRotation) {
  302. EnableTabletMode(true);
  303. // Now test rotating in all directions.
  304. TriggerLidUpdate(gfx::Vector3dF(kMeanGravityFloat, 0.0f, 0.0f));
  305. EXPECT_EQ(display::Display::ROTATE_90, GetCurrentInternalDisplayRotation());
  306. TriggerLidUpdate(gfx::Vector3dF(0.0f, -kMeanGravityFloat, 0.0f));
  307. EXPECT_EQ(display::Display::ROTATE_180, GetCurrentInternalDisplayRotation());
  308. TriggerLidUpdate(gfx::Vector3dF(-kMeanGravityFloat, 0.0f, 0.0f));
  309. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  310. TriggerLidUpdate(gfx::Vector3dF(0.0f, kMeanGravityFloat, 0.0f));
  311. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  312. }
  313. // Tests that low angles are ignored by the accelerometer (i.e. when the device
  314. // is almost laying flat).
  315. TEST_F(ScreenOrientationControllerTest, RotationIgnoresLowAngles) {
  316. EnableTabletMode(true);
  317. TriggerLidUpdate(gfx::Vector3dF(0.0f, kMeanGravityFloat, kMeanGravityFloat));
  318. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  319. TriggerLidUpdate(gfx::Vector3dF(-2.0f, 0.0f, kMeanGravityFloat));
  320. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  321. TriggerLidUpdate(gfx::Vector3dF(0.0f, 2.0f, kMeanGravityFloat));
  322. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  323. TriggerLidUpdate(gfx::Vector3dF(2.0f, 0.0f, kMeanGravityFloat));
  324. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  325. TriggerLidUpdate(gfx::Vector3dF(0.0f, -2.0f, kMeanGravityFloat));
  326. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  327. }
  328. // Tests that the display will stick to the current orientation beyond the
  329. // halfway point, preventing frequent updates back and forth.
  330. TEST_F(ScreenOrientationControllerTest, RotationSticky) {
  331. EnableTabletMode(true);
  332. gfx::Vector3dF gravity(0.0f, kMeanGravityFloat, 0.0f);
  333. TriggerLidUpdate(gravity);
  334. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  335. // Turn past half-way point to next direction and rotation should remain
  336. // the same.
  337. float degrees = 50.0;
  338. gravity.set_x(-sin(degrees * kDegreesToRadians) * -kMeanGravityFloat);
  339. gravity.set_y(-cos(degrees * kDegreesToRadians) * -kMeanGravityFloat);
  340. TriggerLidUpdate(gravity);
  341. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  342. // Turn more and the screen should rotate.
  343. degrees = 70.0;
  344. gravity.set_x(-sin(degrees * kDegreesToRadians) * -kMeanGravityFloat);
  345. gravity.set_y(-cos(degrees * kDegreesToRadians) * -kMeanGravityFloat);
  346. TriggerLidUpdate(gravity);
  347. EXPECT_EQ(display::Display::ROTATE_90, GetCurrentInternalDisplayRotation());
  348. // Turn back just beyond the half-way point and the new rotation should
  349. // still be in effect.
  350. degrees = 40.0;
  351. gravity.set_x(-sin(degrees * kDegreesToRadians) * -kMeanGravityFloat);
  352. gravity.set_y(-cos(degrees * kDegreesToRadians) * -kMeanGravityFloat);
  353. TriggerLidUpdate(gravity);
  354. EXPECT_EQ(display::Display::ROTATE_90, GetCurrentInternalDisplayRotation());
  355. }
  356. // Tests that the display will stick to its current orientation when the
  357. // rotation lock has been set.
  358. TEST_F(ScreenOrientationControllerTest, RotationLockPreventsRotation) {
  359. EnableTabletMode(true);
  360. SetUserRotationLocked(true);
  361. // Turn past the threshold for rotation.
  362. float degrees = 90.0;
  363. gfx::Vector3dF gravity(-sin(degrees * kDegreesToRadians) * -kMeanGravityFloat,
  364. -cos(degrees * kDegreesToRadians) * -kMeanGravityFloat,
  365. 0.0f);
  366. TriggerLidUpdate(gravity);
  367. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  368. SetUserRotationLocked(false);
  369. TriggerLidUpdate(gravity);
  370. EXPECT_EQ(display::Display::ROTATE_90, GetCurrentInternalDisplayRotation());
  371. }
  372. // Tests that if a user has set a display rotation that it is restored upon
  373. // exiting tablet mode.
  374. TEST_F(ScreenOrientationControllerTest, ResetUserRotationUponExit) {
  375. display::test::DisplayManagerTestApi(display_manager())
  376. .SetFirstDisplayAsInternalDisplay();
  377. SetInternalDisplayRotation(display::Display::ROTATE_90);
  378. EnableTabletMode(true);
  379. TriggerLidUpdate(gfx::Vector3dF(0.0f, -kMeanGravityFloat, 0.0f));
  380. EXPECT_EQ(display::Display::ROTATE_180, GetCurrentInternalDisplayRotation());
  381. EnableTabletMode(false);
  382. EXPECT_EQ(display::Display::ROTATE_90, GetCurrentInternalDisplayRotation());
  383. }
  384. // Tests that if a user changes the display rotation, while rotation is locked,
  385. // that the updates are recorded. Upon exiting tablet mode the latest user
  386. // rotation should be applied.
  387. TEST_F(ScreenOrientationControllerTest, UpdateUserRotationWhileRotationLocked) {
  388. EnableTabletMode(true);
  389. SetInternalDisplayRotation(display::Display::ROTATE_270);
  390. // User sets rotation to the same rotation that the display was at when
  391. // tablet mode was activated.
  392. SetInternalDisplayRotation(display::Display::ROTATE_0);
  393. EnableTabletMode(false);
  394. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  395. }
  396. // Tests that when the orientation lock is set to Landscape, that rotation can
  397. // be done between the two angles of the orientation.
  398. TEST_F(ScreenOrientationControllerTest, LandscapeOrientationAllowsRotation) {
  399. std::unique_ptr<aura::Window> child_window = CreateControlWindow();
  400. std::unique_ptr<aura::Window> focus_window(CreateAppWindowInShellWithId(0));
  401. EnableTabletMode(true);
  402. AddWindowAndActivateParent(child_window.get(), focus_window.get());
  403. Lock(child_window.get(), chromeos::OrientationType::kLandscape);
  404. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  405. EXPECT_TRUE(RotationLocked());
  406. // Inverse of orientation is allowed
  407. TriggerLidUpdate(gfx::Vector3dF(0.0f, -kMeanGravityFloat, 0.0f));
  408. EXPECT_EQ(display::Display::ROTATE_180, GetCurrentInternalDisplayRotation());
  409. // Display rotations between are not allowed
  410. TriggerLidUpdate(gfx::Vector3dF(-kMeanGravityFloat, 0.0f, 0.0f));
  411. EXPECT_EQ(display::Display::ROTATE_180, GetCurrentInternalDisplayRotation());
  412. TriggerLidUpdate(gfx::Vector3dF(kMeanGravityFloat, 0.0f, 0.0f));
  413. EXPECT_EQ(display::Display::ROTATE_180, GetCurrentInternalDisplayRotation());
  414. }
  415. // Tests that when the orientation lock is set to Portrait, that rotation can be
  416. // done between the two angles of the orientation.
  417. TEST_F(ScreenOrientationControllerTest, PortraitOrientationAllowsRotation) {
  418. std::unique_ptr<aura::Window> child_window = CreateControlWindow();
  419. std::unique_ptr<aura::Window> focus_window(CreateAppWindowInShellWithId(0));
  420. EnableTabletMode(true);
  421. AddWindowAndActivateParent(child_window.get(), focus_window.get());
  422. Lock(child_window.get(), chromeos::OrientationType::kPortrait);
  423. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  424. EXPECT_TRUE(RotationLocked());
  425. // Inverse of orientation is allowed
  426. TriggerLidUpdate(gfx::Vector3dF(kMeanGravityFloat, 0.0f, 0.0f));
  427. EXPECT_EQ(display::Display::ROTATE_90, GetCurrentInternalDisplayRotation());
  428. // Display rotations between are not allowed
  429. TriggerLidUpdate(gfx::Vector3dF(0.0f, -kMeanGravityFloat, 0.0f));
  430. EXPECT_EQ(display::Display::ROTATE_90, GetCurrentInternalDisplayRotation());
  431. TriggerLidUpdate(gfx::Vector3dF(0.0f, kMeanGravityFloat, 0.0f));
  432. EXPECT_EQ(display::Display::ROTATE_90, GetCurrentInternalDisplayRotation());
  433. }
  434. // Tests that for an orientation lock which does not allow rotation, that the
  435. // display rotation remains constant.
  436. TEST_F(ScreenOrientationControllerTest, OrientationLockDisallowsRotation) {
  437. std::unique_ptr<aura::Window> child_window = CreateControlWindow();
  438. std::unique_ptr<aura::Window> focus_window(CreateAppWindowInShellWithId(0));
  439. EnableTabletMode(true);
  440. AddWindowAndActivateParent(child_window.get(), focus_window.get());
  441. Lock(child_window.get(), chromeos::OrientationType::kPortraitPrimary);
  442. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  443. EXPECT_TRUE(RotationLocked());
  444. // Rotation does not change.
  445. TriggerLidUpdate(gfx::Vector3dF(-kMeanGravityFloat, 0.0f, 0.0f));
  446. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  447. TriggerLidUpdate(gfx::Vector3dF(0.0f, -kMeanGravityFloat, 0.0f));
  448. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  449. TriggerLidUpdate(gfx::Vector3dF(0.0f, kMeanGravityFloat, 0.0f));
  450. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  451. }
  452. // Tests that after a Window has applied an orientation lock which supports
  453. // rotation, that a user rotation lock does not allow rotation.
  454. TEST_F(ScreenOrientationControllerTest, UserRotationLockDisallowsRotation) {
  455. std::unique_ptr<aura::Window> child_window = CreateControlWindow();
  456. std::unique_ptr<aura::Window> focus_window(CreateAppWindowInShellWithId(0));
  457. EnableTabletMode(true);
  458. AddWindowAndActivateParent(child_window.get(), focus_window.get());
  459. Lock(child_window.get(), chromeos::OrientationType::kLandscape);
  460. Unlock(child_window.get());
  461. SetUserRotationLocked(true);
  462. EXPECT_TRUE(RotationLocked());
  463. EXPECT_TRUE(UserRotationLocked());
  464. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  465. TriggerLidUpdate(gfx::Vector3dF(0.0f, -kMeanGravityFloat, 0.0f));
  466. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  467. }
  468. // Verifies rotating an inactive Display is successful.
  469. TEST_F(ScreenOrientationControllerTest, RotateInactiveDisplay) {
  470. const int64_t kInternalDisplayId = 9;
  471. const int64_t kExternalDisplayId = 10;
  472. const display::Display::Rotation kNewRotation = display::Display::ROTATE_180;
  473. const display::ManagedDisplayInfo internal_display_info =
  474. CreateDisplayInfo(kInternalDisplayId, gfx::Rect(0, 0, 600, 500));
  475. const display::ManagedDisplayInfo external_display_info =
  476. CreateDisplayInfo(kExternalDisplayId, gfx::Rect(1, 1, 600, 500));
  477. std::vector<display::ManagedDisplayInfo> display_info_list_two_active;
  478. display_info_list_two_active.push_back(internal_display_info);
  479. display_info_list_two_active.push_back(external_display_info);
  480. std::vector<display::ManagedDisplayInfo> display_info_list_one_active;
  481. display_info_list_one_active.push_back(external_display_info);
  482. // The display::ManagedDisplayInfo list with two active displays needs to be
  483. // added first so that the DisplayManager can track the
  484. // |internal_display_info| as inactive instead of non-existent.
  485. display_manager()->OnNativeDisplaysChanged(display_info_list_two_active);
  486. display_manager()->OnNativeDisplaysChanged(display_info_list_one_active);
  487. display::test::ScopedSetInternalDisplayId set_internal(display_manager(),
  488. kInternalDisplayId);
  489. ASSERT_NE(kNewRotation, display_manager()
  490. ->GetDisplayInfo(kInternalDisplayId)
  491. .GetActiveRotation());
  492. ScreenOrientationControllerTestApi(
  493. Shell::Get()->screen_orientation_controller())
  494. .SetDisplayRotation(kNewRotation,
  495. display::Display::RotationSource::ACTIVE);
  496. EXPECT_EQ(kNewRotation, display_manager()
  497. ->GetDisplayInfo(kInternalDisplayId)
  498. .GetActiveRotation());
  499. }
  500. TEST_F(ScreenOrientationControllerTest, UserRotationLockedOrientation) {
  501. ScreenOrientationController* orientation_controller =
  502. Shell::Get()->screen_orientation_controller();
  503. orientation_controller->ToggleUserRotationLock();
  504. EXPECT_TRUE(orientation_controller->user_rotation_locked());
  505. EXPECT_EQ(chromeos::OrientationType::kLandscapePrimary,
  506. UserLockedOrientation());
  507. orientation_controller->ToggleUserRotationLock();
  508. SetInternalDisplayRotation(display::Display::ROTATE_270);
  509. orientation_controller->ToggleUserRotationLock();
  510. EXPECT_EQ(chromeos::OrientationType::kPortraitPrimary,
  511. UserLockedOrientation());
  512. orientation_controller->ToggleUserRotationLock();
  513. SetInternalDisplayRotation(display::Display::ROTATE_180);
  514. orientation_controller->ToggleUserRotationLock();
  515. EXPECT_EQ(chromeos::OrientationType::kLandscapeSecondary,
  516. UserLockedOrientation());
  517. orientation_controller->ToggleUserRotationLock();
  518. SetInternalDisplayRotation(display::Display::ROTATE_90);
  519. orientation_controller->ToggleUserRotationLock();
  520. EXPECT_EQ(chromeos::OrientationType::kPortraitSecondary,
  521. UserLockedOrientation());
  522. orientation_controller->ToggleUserRotationLock();
  523. SetInternalDisplayRotation(display::Display::ROTATE_270);
  524. UpdateDisplay("800x1280");
  525. orientation_controller->ToggleUserRotationLock();
  526. EXPECT_TRUE(orientation_controller->user_rotation_locked());
  527. EXPECT_EQ(chromeos::OrientationType::kPortraitPrimary,
  528. UserLockedOrientation());
  529. orientation_controller->ToggleUserRotationLock();
  530. SetInternalDisplayRotation(display::Display::ROTATE_90);
  531. orientation_controller->ToggleUserRotationLock();
  532. EXPECT_EQ(chromeos::OrientationType::kLandscapePrimary,
  533. UserLockedOrientation());
  534. orientation_controller->ToggleUserRotationLock();
  535. SetInternalDisplayRotation(display::Display::ROTATE_180);
  536. orientation_controller->ToggleUserRotationLock();
  537. EXPECT_EQ(chromeos::OrientationType::kPortraitSecondary,
  538. UserLockedOrientation());
  539. orientation_controller->ToggleUserRotationLock();
  540. SetInternalDisplayRotation(display::Display::ROTATE_270);
  541. orientation_controller->ToggleUserRotationLock();
  542. EXPECT_EQ(chromeos::OrientationType::kLandscapeSecondary,
  543. UserLockedOrientation());
  544. orientation_controller->ToggleUserRotationLock();
  545. }
  546. TEST_F(ScreenOrientationControllerTest, UserRotationLock) {
  547. EnableTabletMode(true);
  548. std::unique_ptr<aura::Window> child_window1 = CreateControlWindow();
  549. std::unique_ptr<aura::Window> child_window2 = CreateControlWindow();
  550. std::unique_ptr<aura::Window> focus_window1(CreateAppWindowInShellWithId(0));
  551. std::unique_ptr<aura::Window> focus_window2(CreateAppWindowInShellWithId(1));
  552. AddWindowAndActivateParent(child_window2.get(), focus_window2.get());
  553. AddWindowAndActivateParent(child_window1.get(), focus_window1.get());
  554. ASSERT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  555. ASSERT_FALSE(RotationLocked());
  556. ASSERT_FALSE(UserRotationLocked());
  557. ScreenOrientationController* orientation_controller =
  558. Shell::Get()->screen_orientation_controller();
  559. ASSERT_FALSE(orientation_controller->user_rotation_locked());
  560. orientation_controller->ToggleUserRotationLock();
  561. ASSERT_TRUE(orientation_controller->user_rotation_locked());
  562. Lock(child_window1.get(), chromeos::OrientationType::kPortrait);
  563. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  564. ::wm::ActivationClient* activation_client = Shell::Get()->activation_client();
  565. // Activating any will switch to the natural orientation.
  566. activation_client->ActivateWindow(focus_window2.get());
  567. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  568. // Activating the portrait window will rotate to the portrait.
  569. activation_client->ActivateWindow(focus_window1.get());
  570. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  571. // User locked to the 90 dig.
  572. orientation_controller->ToggleUserRotationLock();
  573. orientation_controller->ToggleUserRotationLock();
  574. // Switching to Any orientation will stay to the user locked orientation.
  575. activation_client->ActivateWindow(focus_window2.get());
  576. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  577. // Application forced to be landscape.
  578. Lock(child_window2.get(), chromeos::OrientationType::kLandscape);
  579. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  580. Lock(child_window1.get(), chromeos::OrientationType::kAny);
  581. activation_client->ActivateWindow(focus_window1.get());
  582. // Switching back to any will rotate to user rotation.
  583. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  584. }
  585. TEST_F(ScreenOrientationControllerTest, ClamshellPhysicalTabletState) {
  586. // Auto-rotation is disabled while the device is not physically used as a
  587. // tablet.
  588. TabletModeControllerTestApi tablet_mode_controller_test_api;
  589. EXPECT_FALSE(tablet_mode_controller_test_api.IsInPhysicalTabletState());
  590. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  591. TriggerLidUpdate(gfx::Vector3dF(kMeanGravityFloat, 0.0f, 0.0f));
  592. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  593. // Once the device goes into tablet mode, it becomes possible to auto-rotate.
  594. tablet_mode_controller_test_api.OpenLidToAngle(270);
  595. EXPECT_TRUE(tablet_mode_controller_test_api.IsInPhysicalTabletState());
  596. EXPECT_TRUE(tablet_mode_controller_test_api.IsTabletModeStarted());
  597. TriggerLidUpdate(gfx::Vector3dF(kMeanGravityFloat, 0.0f, 0.0f));
  598. EXPECT_EQ(display::Display::ROTATE_90, GetCurrentInternalDisplayRotation());
  599. // Hooking an external pointing device will exits tablet UI mode, but the
  600. // device is still in a physical tablet state, which means auto-rotation is
  601. // still possible.
  602. tablet_mode_controller_test_api.AttachExternalMouse();
  603. EXPECT_TRUE(tablet_mode_controller_test_api.IsInPhysicalTabletState());
  604. EXPECT_FALSE(tablet_mode_controller_test_api.IsTabletModeStarted());
  605. TriggerLidUpdate(gfx::Vector3dF(0.0f, -kMeanGravityFloat, 0.0f));
  606. EXPECT_EQ(display::Display::ROTATE_180, GetCurrentInternalDisplayRotation());
  607. }
  608. TEST_F(ScreenOrientationControllerTest,
  609. ApplyAppsRequestedLocksOnlyInUITabletMode) {
  610. std::unique_ptr<aura::Window> window(CreateAppWindowInShellWithId(0));
  611. TabletModeControllerTestApi tablet_mode_controller_test_api;
  612. // Unit tests are supposed to be in reference to a hypothetical computer, but
  613. // they can detect a mouse connected to the actual computer on which they are
  614. // run. That is relevant here because external pointing devices prevent tablet
  615. // mode. Detach all mice, so that this unit test will produce the same results
  616. // whether the host machine has a mouse or not.
  617. tablet_mode_controller_test_api.DetachAllMice();
  618. tablet_mode_controller_test_api.OpenLidToAngle(270);
  619. EXPECT_TRUE(tablet_mode_controller_test_api.IsInPhysicalTabletState());
  620. EXPECT_TRUE(tablet_mode_controller_test_api.IsTabletModeStarted());
  621. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  622. ScreenOrientationController* orientation_controller =
  623. Shell::Get()->screen_orientation_controller();
  624. orientation_controller->ToggleUserRotationLock();
  625. EXPECT_TRUE(orientation_controller->user_rotation_locked());
  626. EXPECT_EQ(chromeos::OrientationType::kLandscapePrimary,
  627. UserLockedOrientation());
  628. // Apps' requested orientation locks are only applied in UI tablet mode.
  629. Lock(window.get(), chromeos::OrientationType::kPortrait);
  630. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  631. // Exiting to clamshell mode while the device is still physically a tablet
  632. // should restore the user rotation lock, and ignore the app-requested one.
  633. tablet_mode_controller_test_api.AttachExternalMouse();
  634. EXPECT_TRUE(tablet_mode_controller_test_api.IsInPhysicalTabletState());
  635. EXPECT_FALSE(tablet_mode_controller_test_api.IsTabletModeStarted());
  636. EXPECT_TRUE(orientation_controller->user_rotation_locked());
  637. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  638. EXPECT_EQ(chromeos::OrientationType::kLandscapePrimary,
  639. UserLockedOrientation());
  640. // Further requested orientation locks by apps will remain ignored.
  641. Lock(window.get(), chromeos::OrientationType::kPortraitSecondary);
  642. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  643. EXPECT_EQ(chromeos::OrientationType::kLandscapePrimary,
  644. UserLockedOrientation());
  645. // When UI tablet mode triggers again, the most recent app requested
  646. // orientation lock for the active window will be applied.
  647. tablet_mode_controller_test_api.DetachAllMice();
  648. EXPECT_TRUE(tablet_mode_controller_test_api.IsInPhysicalTabletState());
  649. EXPECT_TRUE(tablet_mode_controller_test_api.IsTabletModeStarted());
  650. EXPECT_EQ(display::Display::ROTATE_90, GetCurrentInternalDisplayRotation());
  651. // Orientation should be restored once the device exits the physical tablet
  652. // state.
  653. tablet_mode_controller_test_api.OpenLidToAngle(90);
  654. EXPECT_FALSE(tablet_mode_controller_test_api.IsInPhysicalTabletState());
  655. EXPECT_FALSE(tablet_mode_controller_test_api.IsTabletModeStarted());
  656. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  657. }
  658. TEST_F(ScreenOrientationControllerTest, GetCurrentAppRequestedOrientationLock) {
  659. UpdateDisplay("0+0-400x300,+400+0-500x400");
  660. auto win0 = CreateAppWindow(gfx::Rect{100, 200});
  661. auto win1 = CreateAppWindow(gfx::Rect{460, 10, 100, 200});
  662. auto roots = Shell::GetAllRootWindows();
  663. ASSERT_EQ(2u, roots.size());
  664. EXPECT_EQ(win0->GetRootWindow(), roots[0]);
  665. EXPECT_EQ(win1->GetRootWindow(), roots[1]);
  666. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  667. EXPECT_EQ(chromeos::OrientationType::kAny, UserLockedOrientation());
  668. auto* screen_orientation_controller =
  669. Shell::Get()->screen_orientation_controller();
  670. screen_orientation_controller->LockOrientationForWindow(
  671. win0.get(), chromeos::OrientationType::kPortraitPrimary);
  672. screen_orientation_controller->LockOrientationForWindow(
  673. win1.get(), chromeos::OrientationType::kLandscape);
  674. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  675. EXPECT_EQ(chromeos::OrientationType::kAny, UserLockedOrientation());
  676. EXPECT_EQ(
  677. chromeos::OrientationType::kAny,
  678. screen_orientation_controller->GetCurrentAppRequestedOrientationLock());
  679. // Enter tablet mode and expect nothing will change until we activate win0.
  680. TabletModeControllerTestApi().DetachAllMice();
  681. EnableTabletMode(true);
  682. // Run a loop for mirror mode to kick in which is triggered asynchronously.
  683. base::RunLoop().RunUntilIdle();
  684. EXPECT_TRUE(display_manager()->IsInSoftwareMirrorMode());
  685. EXPECT_EQ(chromeos::OrientationType::kLandscape,
  686. screen_orientation_controller->natural_orientation());
  687. EXPECT_EQ(win1.get(), window_util::GetActiveWindow());
  688. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  689. EXPECT_EQ(chromeos::OrientationType::kAny, UserLockedOrientation());
  690. wm::ActivateWindow(win0.get());
  691. EXPECT_EQ(
  692. chromeos::OrientationType::kPortraitPrimary,
  693. screen_orientation_controller->GetCurrentAppRequestedOrientationLock());
  694. EXPECT_EQ(win0.get(), window_util::GetActiveWindow());
  695. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  696. EXPECT_EQ(chromeos::OrientationType::kAny, UserLockedOrientation());
  697. display_manager()->SetMirrorMode(display::MirrorMode::kOff, absl::nullopt);
  698. base::RunLoop().RunUntilIdle();
  699. roots = Shell::GetAllRootWindows();
  700. ASSERT_EQ(2u, roots.size());
  701. EXPECT_EQ(win0->GetRootWindow(), roots[0]);
  702. EXPECT_EQ(win1->GetRootWindow(), roots[1]);
  703. // `win1` belongs to the external display, so it is not allowed to lock the
  704. // rotation.
  705. EXPECT_EQ(win0.get(), window_util::GetActiveWindow());
  706. EXPECT_EQ(
  707. chromeos::OrientationType::kPortraitPrimary,
  708. screen_orientation_controller->GetCurrentAppRequestedOrientationLock());
  709. EXPECT_TRUE(screen_orientation_controller->rotation_locked());
  710. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  711. EXPECT_EQ(chromeos::OrientationType::kAny, UserLockedOrientation());
  712. // Even if you activate `win1`, internal display is not affected and remain
  713. // locked to the rotation requested by `win0`.
  714. wm::ActivateWindow(win1.get());
  715. EXPECT_EQ(
  716. chromeos::OrientationType::kPortraitPrimary,
  717. screen_orientation_controller->GetCurrentAppRequestedOrientationLock());
  718. EXPECT_TRUE(screen_orientation_controller->rotation_locked());
  719. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  720. EXPECT_EQ(chromeos::OrientationType::kAny, UserLockedOrientation());
  721. // Once `win0` is snapped in splitview, it can no longer lock the rotation.
  722. SplitViewController::Get(win0->GetRootWindow())
  723. ->SnapWindow(win0.get(), SplitViewController::RIGHT);
  724. EXPECT_EQ(
  725. chromeos::OrientationType::kAny,
  726. screen_orientation_controller->GetCurrentAppRequestedOrientationLock());
  727. }
  728. TEST_F(ScreenOrientationControllerTest,
  729. MoveWindowWithOrientationLockBetweenDisplays) {
  730. UpdateDisplay("400x300,500x400");
  731. // Enter tablet mode and expect nothing will change until we activate win0.
  732. TabletModeControllerTestApi().DetachAllMice();
  733. EnableTabletMode(true);
  734. // Run a loop for mirror mode to kick in which is triggered asynchronously.
  735. base::RunLoop().RunUntilIdle();
  736. EXPECT_TRUE(display_manager()->IsInSoftwareMirrorMode());
  737. // Now switch mirror mode off so that we can have two displays in tablet mode.
  738. display_manager()->SetMirrorMode(display::MirrorMode::kOff, absl::nullopt);
  739. base::RunLoop().RunUntilIdle();
  740. auto roots = Shell::GetAllRootWindows();
  741. ASSERT_EQ(2u, roots.size());
  742. // Create a window that locks the orientation to portriat-primary.
  743. auto win0 = CreateAppWindow(gfx::Rect{100, 200});
  744. EXPECT_EQ(win0->GetRootWindow(), roots[0]);
  745. EXPECT_EQ(win0.get(), window_util::GetActiveWindow());
  746. auto* screen_orientation_controller =
  747. Shell::Get()->screen_orientation_controller();
  748. EXPECT_EQ(chromeos::OrientationType::kLandscape,
  749. screen_orientation_controller->natural_orientation());
  750. screen_orientation_controller->LockOrientationForWindow(
  751. win0.get(), chromeos::OrientationType::kPortraitPrimary);
  752. // Even with an accelerometer update that would trigger a 0 degree rotation,
  753. // the rotation of the internal display is locked to 270.
  754. TriggerLidUpdate(gfx::Vector3dF(0.0f, kMeanGravityFloat, 0.0f));
  755. EXPECT_EQ(
  756. chromeos::OrientationType::kPortraitPrimary,
  757. screen_orientation_controller->GetCurrentAppRequestedOrientationLock());
  758. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  759. EXPECT_EQ(chromeos::OrientationType::kAny, UserLockedOrientation());
  760. // Triggers the move-active-window-between-displays shortcut.
  761. auto* event_generator = GetEventGenerator();
  762. auto trigger_shortcut = [event_generator]() {
  763. constexpr int kFlags = ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN;
  764. event_generator->PressKey(ui::VKEY_M, kFlags);
  765. event_generator->ReleaseKey(ui::VKEY_M, kFlags);
  766. };
  767. // Move the window to the external display, and expect that the internal
  768. // display's orientation is no longer locked.
  769. trigger_shortcut();
  770. TriggerLidUpdate(gfx::Vector3dF(0.0f, kMeanGravityFloat, 0.0f));
  771. EXPECT_EQ(win0->GetRootWindow(), roots[1]);
  772. EXPECT_EQ(
  773. chromeos::OrientationType::kAny,
  774. screen_orientation_controller->GetCurrentAppRequestedOrientationLock());
  775. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  776. EXPECT_EQ(chromeos::OrientationType::kAny, UserLockedOrientation());
  777. // Move the window back to the internal display, and expect that its
  778. // orientation is locked again by that window.
  779. trigger_shortcut();
  780. TriggerLidUpdate(gfx::Vector3dF(0.0f, kMeanGravityFloat, 0.0f));
  781. EXPECT_EQ(win0->GetRootWindow(), roots[0]);
  782. EXPECT_EQ(
  783. chromeos::OrientationType::kPortraitPrimary,
  784. screen_orientation_controller->GetCurrentAppRequestedOrientationLock());
  785. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  786. EXPECT_EQ(chromeos::OrientationType::kAny, UserLockedOrientation());
  787. }
  788. class SupportsClamshellAutoRotation : public ScreenOrientationControllerTest {
  789. public:
  790. SupportsClamshellAutoRotation() = default;
  791. SupportsClamshellAutoRotation(const SupportsClamshellAutoRotation&) = delete;
  792. SupportsClamshellAutoRotation& operator=(
  793. const SupportsClamshellAutoRotation&) = delete;
  794. ~SupportsClamshellAutoRotation() override = default;
  795. // ScreenOrientationControllerTest:
  796. void SetUp() override {
  797. base::CommandLine::ForCurrentProcess()->AppendSwitch(
  798. switches::kSupportsClamshellAutoRotation);
  799. ScreenOrientationControllerTest::SetUp();
  800. }
  801. };
  802. // Tests that auto rotation is supported even in clamshell when
  803. // kSupportsClamshellAutoRotation is set.
  804. TEST_F(SupportsClamshellAutoRotation, ScreenRotation) {
  805. TabletModeControllerTestApi tablet_mode_controller_test_api;
  806. ASSERT_FALSE(tablet_mode_controller_test_api.IsTabletModeStarted());
  807. // Test rotating in all directions are supported.
  808. TriggerLidUpdate(gfx::Vector3dF(kMeanGravityFloat, 0.0f, 0.0f));
  809. EXPECT_EQ(display::Display::ROTATE_90, GetCurrentInternalDisplayRotation());
  810. TriggerLidUpdate(gfx::Vector3dF(0.0f, -kMeanGravityFloat, 0.0f));
  811. EXPECT_EQ(display::Display::ROTATE_180, GetCurrentInternalDisplayRotation());
  812. TriggerLidUpdate(gfx::Vector3dF(-kMeanGravityFloat, 0.0f, 0.0f));
  813. EXPECT_EQ(display::Display::ROTATE_270, GetCurrentInternalDisplayRotation());
  814. TriggerLidUpdate(gfx::Vector3dF(0.0f, kMeanGravityFloat, 0.0f));
  815. EXPECT_EQ(display::Display::ROTATE_0, GetCurrentInternalDisplayRotation());
  816. }
  817. } // namespace ash