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
5#include <math.h>
6
7#include "ash/wm/maximize_mode/maximize_mode_controller.h"
8
9#include "ash/accelerometer/accelerometer_controller.h"
10#include "ash/display/display_manager.h"
11#include "ash/shell.h"
12#include "ash/system/tray/system_tray_delegate.h"
13#include "ash/test/ash_test_base.h"
14#include "ash/test/display_manager_test_api.h"
15#include "ash/test/test_system_tray_delegate.h"
16#include "ash/test/test_volume_control_delegate.h"
17#include "base/test/simple_test_tick_clock.h"
18#include "ui/accelerometer/accelerometer_types.h"
19#include "ui/events/event_handler.h"
20#include "ui/events/test/event_generator.h"
21#include "ui/gfx/vector3d_f.h"
22#include "ui/message_center/message_center.h"
23
24#if defined(USE_X11)
25#include "ui/events/test/events_test_utils_x11.h"
26#endif
27
28namespace ash {
29
30namespace {
31
32const float kDegreesToRadians = 3.1415926f / 180.0f;
33const float kMeanGravity = 9.8066f;
34
35}  // namespace
36
37// Test accelerometer data taken with the lid at less than 180 degrees while
38// shaking the device around. The data is to be interpreted in groups of 6 where
39// each 6 values corresponds to the X, Y, and Z readings from the base and lid
40// accelerometers in this order.
41extern const float kAccelerometerLaptopModeTestData[];
42extern const size_t kAccelerometerLaptopModeTestDataLength;
43
44// Test accelerometer data taken with the lid open 360 degrees while
45// shaking the device around. The data is to be interpreted in groups of 6 where
46// each 6 values corresponds to the X, Y, and Z readings from the base and lid
47// accelerometers in this order.
48extern const float kAccelerometerFullyOpenTestData[];
49extern const size_t kAccelerometerFullyOpenTestDataLength;
50
51class MaximizeModeControllerTest : public test::AshTestBase {
52 public:
53  MaximizeModeControllerTest() {}
54  virtual ~MaximizeModeControllerTest() {}
55
56  virtual void SetUp() OVERRIDE {
57    test::AshTestBase::SetUp();
58    Shell::GetInstance()->accelerometer_controller()->RemoveObserver(
59        maximize_mode_controller());
60
61    // Set the first display to be the internal display for the accelerometer
62    // screen rotation tests.
63    test::DisplayManagerTestApi(Shell::GetInstance()->display_manager()).
64        SetFirstDisplayAsInternalDisplay();
65  }
66
67  virtual void TearDown() OVERRIDE {
68    Shell::GetInstance()->accelerometer_controller()->AddObserver(
69        maximize_mode_controller());
70    test::AshTestBase::TearDown();
71  }
72
73  MaximizeModeController* maximize_mode_controller() {
74    return Shell::GetInstance()->maximize_mode_controller();
75  }
76
77  void TriggerAccelerometerUpdate(const gfx::Vector3dF& base,
78                                  const gfx::Vector3dF& lid) {
79    ui::AccelerometerUpdate update;
80    update.Set(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD,
81        base.x(), base.y(), base.z());
82    update.Set(ui::ACCELEROMETER_SOURCE_SCREEN,
83        lid.x(), lid.y(), lid.z());
84    maximize_mode_controller()->OnAccelerometerUpdated(update);
85  }
86
87  bool IsMaximizeModeStarted() {
88    return maximize_mode_controller()->IsMaximizeModeWindowManagerEnabled();
89  }
90
91  gfx::Display::Rotation GetInternalDisplayRotation() const {
92    return Shell::GetInstance()->display_manager()->GetDisplayInfo(
93        gfx::Display::InternalDisplayId()).rotation();
94  }
95
96  void SetInternalDisplayRotation(gfx::Display::Rotation rotation) const {
97    Shell::GetInstance()->display_manager()->
98        SetDisplayRotation(gfx::Display::InternalDisplayId(), rotation);
99  }
100
101  // Attaches a SimpleTestTickClock to the MaximizeModeController with a non
102  // null value initial value.
103  void AttachTickClockForTest() {
104    scoped_ptr<base::TickClock> tick_clock(
105        test_tick_clock_ = new base::SimpleTestTickClock());
106    test_tick_clock_->Advance(base::TimeDelta::FromSeconds(1));
107    maximize_mode_controller()->SetTickClockForTest(tick_clock.Pass());
108  }
109
110  void AdvanceTickClock(const base::TimeDelta& delta) {
111    DCHECK(test_tick_clock_);
112    test_tick_clock_->Advance(delta);
113  }
114
115  void OpenLidToAngle(float degrees) {
116    DCHECK(degrees >= 0.0f);
117    DCHECK(degrees <= 360.0f);
118
119    float radians = degrees * kDegreesToRadians;
120    gfx::Vector3dF base_vector(0.0f, -kMeanGravity, 0.0f);
121    gfx::Vector3dF lid_vector(0.0f,
122                              kMeanGravity * cos(radians),
123                              kMeanGravity * sin(radians));
124    TriggerAccelerometerUpdate(base_vector, lid_vector);
125  }
126
127#if defined(OS_CHROMEOS)
128  void OpenLid() {
129    maximize_mode_controller()->LidEventReceived(true /* open */,
130        maximize_mode_controller()->tick_clock_->NowTicks());
131  }
132
133  void CloseLid() {
134    maximize_mode_controller()->LidEventReceived(false /* open */,
135        maximize_mode_controller()->tick_clock_->NowTicks());
136  }
137#endif  // OS_CHROMEOS
138
139  bool WasLidOpenedRecently() {
140    return maximize_mode_controller()->WasLidOpenedRecently();
141  }
142
143 private:
144  base::SimpleTestTickClock* test_tick_clock_;
145
146  DISALLOW_COPY_AND_ASSIGN(MaximizeModeControllerTest);
147};
148
149#if defined(OS_CHROMEOS)
150
151// Verify that closing the lid will exit maximize mode.
152TEST_F(MaximizeModeControllerTest, CloseLidWhileInMaximizeMode) {
153  OpenLidToAngle(315.0f);
154  ASSERT_TRUE(IsMaximizeModeStarted());
155
156  CloseLid();
157  EXPECT_FALSE(IsMaximizeModeStarted());
158}
159
160// Verify that maximize mode will not be entered when the lid is closed.
161TEST_F(MaximizeModeControllerTest,
162    HingeAnglesWithLidClosed) {
163  AttachTickClockForTest();
164
165  CloseLid();
166
167  OpenLidToAngle(270.0f);
168  EXPECT_FALSE(IsMaximizeModeStarted());
169
170  OpenLidToAngle(315.0f);
171  EXPECT_FALSE(IsMaximizeModeStarted());
172
173  OpenLidToAngle(355.0f);
174  EXPECT_FALSE(IsMaximizeModeStarted());
175}
176
177// Verify the maximize mode state for unstable hinge angles when the lid was
178// recently open.
179TEST_F(MaximizeModeControllerTest,
180    UnstableHingeAnglesWhenLidRecentlyOpened) {
181  AttachTickClockForTest();
182
183  OpenLid();
184  ASSERT_TRUE(WasLidOpenedRecently());
185
186  OpenLidToAngle(5.0f);
187  EXPECT_FALSE(IsMaximizeModeStarted());
188
189  OpenLidToAngle(355.0f);
190  EXPECT_FALSE(IsMaximizeModeStarted());
191
192  // This is a stable reading and should clear the last lid opened time.
193  OpenLidToAngle(45.0f);
194  EXPECT_FALSE(IsMaximizeModeStarted());
195  EXPECT_FALSE(WasLidOpenedRecently());
196
197  OpenLidToAngle(355.0f);
198  EXPECT_TRUE(IsMaximizeModeStarted());
199}
200
201#endif  // OS_CHROMEOS
202
203// Verify the WasLidOpenedRecently signal with respect to time.
204TEST_F(MaximizeModeControllerTest, WasLidOpenedRecentlyOverTime) {
205#if defined(OS_CHROMEOS)
206
207  AttachTickClockForTest();
208
209  // No lid open time initially.
210  ASSERT_FALSE(WasLidOpenedRecently());
211
212  CloseLid();
213  EXPECT_FALSE(WasLidOpenedRecently());
214
215  OpenLid();
216  EXPECT_TRUE(WasLidOpenedRecently());
217
218  // 1 second after lid open.
219  AdvanceTickClock(base::TimeDelta::FromSeconds(1));
220  EXPECT_TRUE(WasLidOpenedRecently());
221
222  // 3 seconds after lid open.
223  AdvanceTickClock(base::TimeDelta::FromSeconds(2));
224  EXPECT_FALSE(WasLidOpenedRecently());
225
226#else
227
228  EXPECT_FALSE(WasLidOpenedRecently());
229
230#endif  // OS_CHROMEOS
231}
232
233// Verify the maximize mode enter/exit thresholds for stable angles.
234TEST_F(MaximizeModeControllerTest, StableHingeAnglesWithLidOpened) {
235  ASSERT_FALSE(IsMaximizeModeStarted());
236  ASSERT_FALSE(WasLidOpenedRecently());
237
238  OpenLidToAngle(180.0f);
239  EXPECT_FALSE(IsMaximizeModeStarted());
240
241  OpenLidToAngle(315.0f);
242  EXPECT_TRUE(IsMaximizeModeStarted());
243
244  OpenLidToAngle(180.0f);
245  EXPECT_TRUE(IsMaximizeModeStarted());
246
247  OpenLidToAngle(45.0f);
248  EXPECT_FALSE(IsMaximizeModeStarted());
249
250  OpenLidToAngle(270.0f);
251  EXPECT_TRUE(IsMaximizeModeStarted());
252
253  OpenLidToAngle(90.0f);
254  EXPECT_FALSE(IsMaximizeModeStarted());
255}
256
257// Verify the maximize mode state for unstable hinge angles when the lid is open
258// but not recently.
259TEST_F(MaximizeModeControllerTest, UnstableHingeAnglesWithLidOpened) {
260  AttachTickClockForTest();
261
262  ASSERT_FALSE(WasLidOpenedRecently());
263  ASSERT_FALSE(IsMaximizeModeStarted());
264
265  OpenLidToAngle(5.0f);
266  EXPECT_FALSE(IsMaximizeModeStarted());
267
268  OpenLidToAngle(355.0f);
269  EXPECT_TRUE(IsMaximizeModeStarted());
270
271  OpenLidToAngle(5.0f);
272  EXPECT_TRUE(IsMaximizeModeStarted());
273}
274
275// Tests that when the hinge is nearly vertically aligned, the current state
276// persists as the computed angle is highly inaccurate in this orientation.
277TEST_F(MaximizeModeControllerTest, HingeAligned) {
278  // Laptop in normal orientation lid open 90 degrees.
279  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, -kMeanGravity),
280                             gfx::Vector3dF(0.0f, -kMeanGravity, 0.0f));
281  EXPECT_FALSE(IsMaximizeModeStarted());
282
283  // Completely vertical.
284  TriggerAccelerometerUpdate(gfx::Vector3dF(kMeanGravity, 0.0f, 0.0f),
285                             gfx::Vector3dF(kMeanGravity, 0.0f, 0.0f));
286  EXPECT_FALSE(IsMaximizeModeStarted());
287
288  // Close to vertical but with hinge appearing to be open 270 degrees.
289  TriggerAccelerometerUpdate(gfx::Vector3dF(kMeanGravity, 0.0f, -0.1f),
290                             gfx::Vector3dF(kMeanGravity, 0.1f, 0.0f));
291  EXPECT_FALSE(IsMaximizeModeStarted());
292
293  // Flat and open 270 degrees should start maximize mode.
294  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, -kMeanGravity),
295                             gfx::Vector3dF(0.0f, kMeanGravity, 0.0f));
296  EXPECT_TRUE(IsMaximizeModeStarted());
297
298  // Normal 90 degree orientation but near vertical should stay in maximize
299  // mode.
300  TriggerAccelerometerUpdate(gfx::Vector3dF(kMeanGravity, 0.0f, -0.1f),
301                             gfx::Vector3dF(kMeanGravity, -0.1f, 0.0f));
302  EXPECT_TRUE(IsMaximizeModeStarted());
303}
304
305// Tests that accelerometer readings in each of the screen angles will trigger a
306// rotation of the internal display.
307TEST_F(MaximizeModeControllerTest, DisplayRotation) {
308  // Trigger maximize mode by opening to 270.
309  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, kMeanGravity),
310                             gfx::Vector3dF(0.0f, -kMeanGravity, 0.0f));
311  ASSERT_TRUE(IsMaximizeModeStarted());
312
313  // Now test rotating in all directions.
314  TriggerAccelerometerUpdate(gfx::Vector3dF(-kMeanGravity, 0.0f, 0.0f),
315                             gfx::Vector3dF(-kMeanGravity, 0.0f, 0.0f));
316  EXPECT_EQ(gfx::Display::ROTATE_90, GetInternalDisplayRotation());
317  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, -kMeanGravity, 0.0f),
318                             gfx::Vector3dF(0.0f, kMeanGravity, 0.0f));
319  EXPECT_EQ(gfx::Display::ROTATE_180, GetInternalDisplayRotation());
320  TriggerAccelerometerUpdate(gfx::Vector3dF(kMeanGravity, 0.0f, 0.0f),
321                             gfx::Vector3dF(kMeanGravity, 0.0f, 0.0f));
322  EXPECT_EQ(gfx::Display::ROTATE_270, GetInternalDisplayRotation());
323  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, kMeanGravity, 0.0f),
324                             gfx::Vector3dF(0.0f, -kMeanGravity, 0.0f));
325  EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
326}
327
328// Tests that low angles are ignored by the accelerometer (i.e. when the device
329// is almost laying flat).
330TEST_F(MaximizeModeControllerTest, RotationIgnoresLowAngles) {
331  // Trigger maximize mode by opening to 270.
332  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, kMeanGravity),
333                             gfx::Vector3dF(0.0f, -kMeanGravity, 0.0f));
334  ASSERT_TRUE(IsMaximizeModeStarted());
335
336  TriggerAccelerometerUpdate(
337      gfx::Vector3dF(0.0f, kMeanGravity, kMeanGravity),
338      gfx::Vector3dF(0.0f, -kMeanGravity, -kMeanGravity));
339  EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
340  TriggerAccelerometerUpdate(gfx::Vector3dF(-2.0f, 0.0f, kMeanGravity),
341                             gfx::Vector3dF(-2.0f, 0.0f, -kMeanGravity));
342  EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
343  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, -2.0f, kMeanGravity),
344                             gfx::Vector3dF(0.0f, 2.0f, -kMeanGravity));
345  EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
346  TriggerAccelerometerUpdate(gfx::Vector3dF(2.0f, 0.0f, kMeanGravity),
347                             gfx::Vector3dF(2.0f, 0.0f, -kMeanGravity));
348  EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
349  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 2.0f, kMeanGravity),
350                             gfx::Vector3dF(0.0f, -2.0f, -kMeanGravity));
351  EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
352}
353
354// Tests that the display will stick to the current orientation beyond the
355// halfway point, preventing frequent updates back and forth.
356TEST_F(MaximizeModeControllerTest, RotationSticky) {
357  // Trigger maximize mode by opening to 270.
358  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, kMeanGravity),
359                             gfx::Vector3dF(0.0f, -kMeanGravity, 0.0f));
360  ASSERT_TRUE(IsMaximizeModeStarted());
361
362  gfx::Vector3dF gravity(0.0f, -kMeanGravity, 0.0f);
363  TriggerAccelerometerUpdate(gravity, gravity);
364  EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
365
366  // Turn past half-way point to next direction and rotation should remain
367  // the same.
368  float degrees = 50.0;
369  gravity.set_x(-sin(degrees * kDegreesToRadians) * kMeanGravity);
370  gravity.set_y(-cos(degrees * kDegreesToRadians) * kMeanGravity);
371  TriggerAccelerometerUpdate(gravity, gravity);
372  EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
373
374  // Turn more and the screen should rotate.
375  degrees = 70.0;
376  gravity.set_x(-sin(degrees * kDegreesToRadians) * kMeanGravity);
377  gravity.set_y(-cos(degrees * kDegreesToRadians) * kMeanGravity);
378  TriggerAccelerometerUpdate(gravity, gravity);
379  EXPECT_EQ(gfx::Display::ROTATE_90, GetInternalDisplayRotation());
380
381  // Turn back just beyond the half-way point and the new rotation should
382  // still be in effect.
383  degrees = 40.0;
384  gravity.set_x(-sin(degrees * kDegreesToRadians) * kMeanGravity);
385  gravity.set_y(-cos(degrees * kDegreesToRadians) * kMeanGravity);
386  TriggerAccelerometerUpdate(gravity, gravity);
387  EXPECT_EQ(gfx::Display::ROTATE_90, GetInternalDisplayRotation());
388}
389
390// Tests that the screen only rotates when maximize mode is engaged, and will
391// return to the standard orientation on exiting maximize mode.
392TEST_F(MaximizeModeControllerTest, RotationOnlyInMaximizeMode) {
393  // Rotate on side with lid only open 90 degrees.
394  TriggerAccelerometerUpdate(gfx::Vector3dF(-9.5f, 0.0f, -3.5f),
395                             gfx::Vector3dF(-9.5f, -3.5f, 0.0f));
396  ASSERT_FALSE(IsMaximizeModeStarted());
397  EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
398
399  // Open lid, screen should now rotate to match orientation.
400  TriggerAccelerometerUpdate(gfx::Vector3dF(-9.5f, 0.0f, 3.5f),
401                             gfx::Vector3dF(-9.5f, -3.5f, 0.0f));
402  ASSERT_TRUE(IsMaximizeModeStarted());
403  EXPECT_EQ(gfx::Display::ROTATE_90, GetInternalDisplayRotation());
404
405  // Close lid back to 90, screen should rotate back.
406  TriggerAccelerometerUpdate(gfx::Vector3dF(-9.5f, 0.0f, -3.5f),
407                             gfx::Vector3dF(-9.5f, -3.5f, 0.0f));
408  ASSERT_FALSE(IsMaximizeModeStarted());
409  EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
410}
411
412
413TEST_F(MaximizeModeControllerTest, LaptopTest) {
414  // Feeds in sample accelerometer data and verifies that there are no
415  // transitions into touchview / maximize mode while shaking the device around
416  // with the hinge at less than 180 degrees. Note the conversion from device
417  // data to accelerometer updates consistent with accelerometer_reader.cc.
418  ASSERT_EQ(0u, kAccelerometerLaptopModeTestDataLength % 6);
419  for (size_t i = 0; i < kAccelerometerLaptopModeTestDataLength / 6; ++i) {
420    gfx::Vector3dF base(-kAccelerometerLaptopModeTestData[i * 6 + 1],
421                        -kAccelerometerLaptopModeTestData[i * 6],
422                        -kAccelerometerLaptopModeTestData[i * 6 + 2]);
423    base.Scale(kMeanGravity);
424    gfx::Vector3dF lid(-kAccelerometerLaptopModeTestData[i * 6 + 4],
425                       kAccelerometerLaptopModeTestData[i * 6 + 3],
426                       kAccelerometerLaptopModeTestData[i * 6 + 5]);
427    lid.Scale(kMeanGravity);
428    TriggerAccelerometerUpdate(base, lid);
429    // There are a lot of samples, so ASSERT rather than EXPECT to only generate
430    // one failure rather than potentially hundreds.
431    ASSERT_FALSE(IsMaximizeModeStarted());
432  }
433}
434
435TEST_F(MaximizeModeControllerTest, MaximizeModeTest) {
436  // Trigger maximize mode by opening to 270 to begin the test in maximize mode.
437  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, kMeanGravity),
438                             gfx::Vector3dF(0.0f, -kMeanGravity, 0.0f));
439  ASSERT_TRUE(IsMaximizeModeStarted());
440
441  // Feeds in sample accelerometer data and verifies that there are no
442  // transitions out of touchview / maximize mode while shaking the device
443  // around. Note the conversion from device data to accelerometer updates
444  // consistent with accelerometer_reader.cc.
445  ASSERT_EQ(0u, kAccelerometerFullyOpenTestDataLength % 6);
446  for (size_t i = 0; i < kAccelerometerFullyOpenTestDataLength / 6; ++i) {
447    gfx::Vector3dF base(-kAccelerometerFullyOpenTestData[i * 6 + 1],
448                        -kAccelerometerFullyOpenTestData[i * 6],
449                        -kAccelerometerFullyOpenTestData[i * 6 + 2]);
450    base.Scale(kMeanGravity);
451    gfx::Vector3dF lid(-kAccelerometerFullyOpenTestData[i * 6 + 4],
452                       kAccelerometerFullyOpenTestData[i * 6 + 3],
453                       kAccelerometerFullyOpenTestData[i * 6 + 5]);
454    lid.Scale(kMeanGravity);
455    TriggerAccelerometerUpdate(base, lid);
456    // There are a lot of samples, so ASSERT rather than EXPECT to only generate
457    // one failure rather than potentially hundreds.
458    ASSERT_TRUE(IsMaximizeModeStarted());
459  }
460}
461
462// Tests that the display will stick to its current orientation when the
463// rotation lock has been set.
464TEST_F(MaximizeModeControllerTest, RotationLockPreventsRotation) {
465  // Trigger maximize mode by opening to 270.
466  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, kMeanGravity),
467                             gfx::Vector3dF(0.0f, -kMeanGravity, 0.0f));
468  ASSERT_TRUE(IsMaximizeModeStarted());
469
470  gfx::Vector3dF gravity(-kMeanGravity, 0.0f, 0.0f);
471
472  maximize_mode_controller()->SetRotationLocked(true);
473
474  // Turn past the threshold for rotation.
475  float degrees = 90.0;
476  gravity.set_x(-sin(degrees * kDegreesToRadians) * kMeanGravity);
477  gravity.set_y(-cos(degrees * kDegreesToRadians) * kMeanGravity);
478  TriggerAccelerometerUpdate(gravity, gravity);
479  EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
480
481  maximize_mode_controller()->SetRotationLocked(false);
482  TriggerAccelerometerUpdate(gravity, gravity);
483  EXPECT_EQ(gfx::Display::ROTATE_90, GetInternalDisplayRotation());
484}
485
486// Tests that when MaximizeModeController turns off MaximizeMode that on the
487// next accelerometer update the rotation lock is cleared.
488TEST_F(MaximizeModeControllerTest, ExitingMaximizeModeClearRotationLock) {
489  // Trigger maximize mode by opening to 270.
490  OpenLidToAngle(270.0f);
491  ASSERT_TRUE(IsMaximizeModeStarted());
492
493  maximize_mode_controller()->SetRotationLocked(true);
494
495  OpenLidToAngle(90.0f);
496  EXPECT_FALSE(IsMaximizeModeStarted());
497
498  // Send an update that would not relaunch MaximizeMode.
499  OpenLidToAngle(90.0f);
500  EXPECT_FALSE(maximize_mode_controller()->rotation_locked());
501}
502
503// The TrayDisplay class that is responsible for adding/updating MessageCenter
504// notifications is only added to the SystemTray on ChromeOS.
505#if defined(OS_CHROMEOS)
506// Tests that the screen rotation notifications are suppressed when
507// triggered by the accelerometer.
508TEST_F(MaximizeModeControllerTest, BlockRotationNotifications) {
509  test::TestSystemTrayDelegate* tray_delegate =
510      static_cast<test::TestSystemTrayDelegate*>(
511          Shell::GetInstance()->system_tray_delegate());
512  tray_delegate->set_should_show_display_notification(true);
513
514  message_center::MessageCenter* message_center =
515      message_center::MessageCenter::Get();
516
517  // Make sure notifications are still displayed when
518  // adjusting the screen rotation directly when not in maximize mode
519  ASSERT_FALSE(IsMaximizeModeStarted());
520  ASSERT_NE(gfx::Display::ROTATE_180, GetInternalDisplayRotation());
521  ASSERT_EQ(0u, message_center->NotificationCount());
522  ASSERT_FALSE(message_center->HasPopupNotifications());
523  SetInternalDisplayRotation(gfx::Display::ROTATE_180);
524  EXPECT_EQ(gfx::Display::ROTATE_180, GetInternalDisplayRotation());
525  EXPECT_EQ(1u, message_center->NotificationCount());
526  EXPECT_TRUE(message_center->HasPopupNotifications());
527
528  // Reset the screen rotation.
529  SetInternalDisplayRotation(gfx::Display::ROTATE_0);
530  // Clear all notifications
531  message_center->RemoveAllNotifications(false);
532  // Trigger maximize mode by opening to 270.
533  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, kMeanGravity),
534                             gfx::Vector3dF(0.0f, -kMeanGravity, 0.0f));
535  EXPECT_TRUE(IsMaximizeModeStarted());
536  EXPECT_EQ(0u, message_center->NotificationCount());
537  EXPECT_FALSE(message_center->HasPopupNotifications());
538
539  // Make sure notifications are still displayed when
540  // adjusting the screen rotation directly when in maximize mode
541  ASSERT_NE(gfx::Display::ROTATE_270, GetInternalDisplayRotation());
542  SetInternalDisplayRotation(gfx::Display::ROTATE_270);
543  maximize_mode_controller()->SetRotationLocked(false);
544  EXPECT_EQ(gfx::Display::ROTATE_270, GetInternalDisplayRotation());
545  EXPECT_EQ(1u, message_center->NotificationCount());
546  EXPECT_TRUE(message_center->HasPopupNotifications());
547
548  // Clear all notifications
549  message_center->RemoveAllNotifications(false);
550  EXPECT_EQ(0u, message_center->NotificationCount());
551  EXPECT_FALSE(message_center->HasPopupNotifications());
552
553  // Make sure notifications are blocked when adjusting the screen rotation
554  // via the accelerometer while in maximize mode
555  // Rotate the screen 90 degrees
556  ASSERT_NE(gfx::Display::ROTATE_90, GetInternalDisplayRotation());
557  TriggerAccelerometerUpdate(gfx::Vector3dF(-kMeanGravity, 0.0f, 0.0f),
558                             gfx::Vector3dF(-kMeanGravity, 0.0f, 0.0f));
559  ASSERT_EQ(gfx::Display::ROTATE_90, GetInternalDisplayRotation());
560  EXPECT_EQ(0u, message_center->NotificationCount());
561  EXPECT_FALSE(message_center->HasPopupNotifications());
562}
563#endif
564
565// Tests that if a user has set a display rotation that it is restored upon
566// exiting maximize mode.
567TEST_F(MaximizeModeControllerTest, ResetUserRotationUponExit) {
568  DisplayManager* display_manager = Shell::GetInstance()->display_manager();
569  display_manager->SetDisplayRotation(gfx::Display::InternalDisplayId(),
570                                      gfx::Display::ROTATE_90);
571
572  // Trigger maximize mode
573  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, kMeanGravity),
574                             gfx::Vector3dF(0.0f, -kMeanGravity, 0.0f));
575  ASSERT_TRUE(IsMaximizeModeStarted());
576
577  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, -kMeanGravity, 0.0f),
578                             gfx::Vector3dF(0.0f, kMeanGravity, 0.0f));
579  EXPECT_EQ(gfx::Display::ROTATE_180, GetInternalDisplayRotation());
580
581  // Exit maximize mode
582  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, -kMeanGravity),
583                             gfx::Vector3dF(0.0f, -kMeanGravity, 0.0f));
584  EXPECT_FALSE(IsMaximizeModeStarted());
585  EXPECT_EQ(gfx::Display::ROTATE_90, GetInternalDisplayRotation());
586}
587
588// Tests that if a user sets a display rotation that accelerometer rotation
589// becomes locked.
590TEST_F(MaximizeModeControllerTest,
591       NonAccelerometerRotationChangesLockRotation) {
592  // Trigger maximize mode by opening to 270.
593  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, kMeanGravity),
594                             gfx::Vector3dF(0.0f, -kMeanGravity, 0.0f));
595  ASSERT_FALSE(maximize_mode_controller()->rotation_locked());
596  SetInternalDisplayRotation(gfx::Display::ROTATE_270);
597  EXPECT_TRUE(maximize_mode_controller()->rotation_locked());
598}
599
600// Tests that if a user changes the display rotation, while rotation is locked,
601// that the updates are recorded. Upon exiting maximize mode the latest user
602// rotation should be applied.
603TEST_F(MaximizeModeControllerTest, UpdateUserRotationWhileRotationLocked) {
604  // Trigger maximize mode by opening to 270.
605  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, kMeanGravity),
606                             gfx::Vector3dF(0.0f, -kMeanGravity, 0.0f));
607  SetInternalDisplayRotation(gfx::Display::ROTATE_270);
608  // User sets rotation to the same rotation that the display was at when
609  // maximize mode was activated.
610  SetInternalDisplayRotation(gfx::Display::ROTATE_0);
611  // Exit maximize mode
612  TriggerAccelerometerUpdate(gfx::Vector3dF(0.0f, 0.0f, -kMeanGravity),
613                             gfx::Vector3dF(0.0f, -kMeanGravity, 0.0f));
614  EXPECT_EQ(gfx::Display::ROTATE_0, GetInternalDisplayRotation());
615}
616
617}  // namespace ash
618