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.
7 #include "ash/wm/maximize_mode/maximize_mode_controller.h"
9 #include "ash/ash_switches.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 "ash/wm/overview/window_selector_controller.h"
18 #include "base/command_line.h"
19 #include "base/test/simple_test_tick_clock.h"
20 #include "base/test/user_action_tester.h"
21 #include "chromeos/accelerometer/accelerometer_reader.h"
22 #include "chromeos/accelerometer/accelerometer_types.h"
23 #include "ui/events/event_handler.h"
24 #include "ui/events/test/event_generator.h"
25 #include "ui/gfx/geometry/vector3d_f.h"
26 #include "ui/message_center/message_center.h"
29 #include "ui/events/test/events_test_utils_x11.h"
36 const float kDegreesToRadians
= 3.1415926f
/ 180.0f
;
37 const float kMeanGravity
= 9.8066f
;
39 const char kTouchViewInitiallyDisabled
[] = "Touchview_Initially_Disabled";
40 const char kTouchViewEnabled
[] = "Touchview_Enabled";
41 const char kTouchViewDisabled
[] = "Touchview_Disabled";
45 // Test accelerometer data taken with the lid at less than 180 degrees while
46 // shaking the device around. The data is to be interpreted in groups of 6 where
47 // each 6 values corresponds to the base accelerometer (-y / g, -x / g, -z / g)
48 // followed by the lid accelerometer (-y / g , x / g, z / g).
49 extern const float kAccelerometerLaptopModeTestData
[];
50 extern const size_t kAccelerometerLaptopModeTestDataLength
;
52 // Test accelerometer data taken with the lid open 360 degrees while
53 // shaking the device around. The data is to be interpreted in groups of 6 where
54 // each 6 values corresponds to the base accelerometer (-y / g, -x / g, -z / g)
55 // followed by the lid accelerometer (-y / g , x / g, z / g).
56 extern const float kAccelerometerFullyOpenTestData
[];
57 extern const size_t kAccelerometerFullyOpenTestDataLength
;
59 // Test accelerometer data taken with the lid open 360 degrees while the device
60 // hinge was nearly vertical, while shaking the device around. The data is to be
61 // interpreted in groups of 6 where each 6 values corresponds to the X, Y, and Z
62 // readings from the base and lid accelerometers in this order.
63 extern const float kAccelerometerVerticalHingeTestData
[];
64 extern const size_t kAccelerometerVerticalHingeTestDataLength
;
66 class MaximizeModeControllerTest
: public test::AshTestBase
{
68 MaximizeModeControllerTest() {}
69 ~MaximizeModeControllerTest() override
{}
71 void SetUp() override
{
72 test::AshTestBase::SetUp();
73 chromeos::AccelerometerReader::GetInstance()->RemoveObserver(
74 maximize_mode_controller());
76 // Set the first display to be the internal display for the accelerometer
77 // screen rotation tests.
78 test::DisplayManagerTestApi(Shell::GetInstance()->display_manager()).
79 SetFirstDisplayAsInternalDisplay();
82 void TearDown() override
{
83 chromeos::AccelerometerReader::GetInstance()->AddObserver(
84 maximize_mode_controller());
85 test::AshTestBase::TearDown();
88 MaximizeModeController
* maximize_mode_controller() {
89 return Shell::GetInstance()->maximize_mode_controller();
92 void TriggerLidUpdate(const gfx::Vector3dF
& lid
) {
93 scoped_refptr
<chromeos::AccelerometerUpdate
> update(
94 new chromeos::AccelerometerUpdate());
95 update
->Set(chromeos::ACCELEROMETER_SOURCE_SCREEN
, lid
.x(), lid
.y(),
97 maximize_mode_controller()->OnAccelerometerUpdated(update
);
100 void TriggerBaseAndLidUpdate(const gfx::Vector3dF
& base
,
101 const gfx::Vector3dF
& lid
) {
102 scoped_refptr
<chromeos::AccelerometerUpdate
> update(
103 new chromeos::AccelerometerUpdate());
104 update
->Set(chromeos::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD
, base
.x(),
106 update
->Set(chromeos::ACCELEROMETER_SOURCE_SCREEN
, lid
.x(), lid
.y(),
108 maximize_mode_controller()->OnAccelerometerUpdated(update
);
111 bool IsMaximizeModeStarted() {
112 return maximize_mode_controller()->IsMaximizeModeWindowManagerEnabled();
115 // Attaches a SimpleTestTickClock to the MaximizeModeController with a non
116 // null value initial value.
117 void AttachTickClockForTest() {
118 scoped_ptr
<base::TickClock
> tick_clock(
119 test_tick_clock_
= new base::SimpleTestTickClock());
120 test_tick_clock_
->Advance(base::TimeDelta::FromSeconds(1));
121 maximize_mode_controller()->SetTickClockForTest(tick_clock
.Pass());
124 void AdvanceTickClock(const base::TimeDelta
& delta
) {
125 DCHECK(test_tick_clock_
);
126 test_tick_clock_
->Advance(delta
);
129 void OpenLidToAngle(float degrees
) {
130 DCHECK(degrees
>= 0.0f
);
131 DCHECK(degrees
<= 360.0f
);
133 float radians
= degrees
* kDegreesToRadians
;
134 gfx::Vector3dF
base_vector(0.0f
, -kMeanGravity
, 0.0f
);
135 gfx::Vector3dF
lid_vector(0.0f
,
136 kMeanGravity
* cos(radians
),
137 kMeanGravity
* sin(radians
));
138 TriggerBaseAndLidUpdate(base_vector
, lid_vector
);
142 maximize_mode_controller()->LidEventReceived(true /* open */,
143 maximize_mode_controller()->tick_clock_
->NowTicks());
147 maximize_mode_controller()->LidEventReceived(false /* open */,
148 maximize_mode_controller()->tick_clock_
->NowTicks());
151 bool WasLidOpenedRecently() {
152 return maximize_mode_controller()->WasLidOpenedRecently();
155 base::UserActionTester
* user_action_tester() { return &user_action_tester_
; }
158 base::SimpleTestTickClock
* test_tick_clock_
;
160 // Tracks user action counts.
161 base::UserActionTester user_action_tester_
;
163 DISALLOW_COPY_AND_ASSIGN(MaximizeModeControllerTest
);
166 // Verify TouchView enabled/disabled user action metrics are recorded.
167 TEST_F(MaximizeModeControllerTest
, VerifyTouchViewEnabledDisabledCounts
) {
169 user_action_tester()->GetActionCount(kTouchViewInitiallyDisabled
));
170 ASSERT_EQ(0, user_action_tester()->GetActionCount(kTouchViewEnabled
));
171 ASSERT_EQ(0, user_action_tester()->GetActionCount(kTouchViewDisabled
));
173 user_action_tester()->ResetCounts();
174 maximize_mode_controller()->EnableMaximizeModeWindowManager(true);
175 EXPECT_EQ(1, user_action_tester()->GetActionCount(kTouchViewEnabled
));
176 EXPECT_EQ(0, user_action_tester()->GetActionCount(kTouchViewDisabled
));
177 maximize_mode_controller()->EnableMaximizeModeWindowManager(true);
178 EXPECT_EQ(1, user_action_tester()->GetActionCount(kTouchViewEnabled
));
179 EXPECT_EQ(0, user_action_tester()->GetActionCount(kTouchViewDisabled
));
181 user_action_tester()->ResetCounts();
182 maximize_mode_controller()->EnableMaximizeModeWindowManager(false);
183 EXPECT_EQ(0, user_action_tester()->GetActionCount(kTouchViewEnabled
));
184 EXPECT_EQ(1, user_action_tester()->GetActionCount(kTouchViewDisabled
));
185 maximize_mode_controller()->EnableMaximizeModeWindowManager(false);
186 EXPECT_EQ(0, user_action_tester()->GetActionCount(kTouchViewEnabled
));
187 EXPECT_EQ(1, user_action_tester()->GetActionCount(kTouchViewDisabled
));
190 // Verify that closing the lid will exit maximize mode.
191 TEST_F(MaximizeModeControllerTest
, CloseLidWhileInMaximizeMode
) {
192 OpenLidToAngle(315.0f
);
193 ASSERT_TRUE(IsMaximizeModeStarted());
196 EXPECT_FALSE(IsMaximizeModeStarted());
199 // Verify that maximize mode will not be entered when the lid is closed.
200 TEST_F(MaximizeModeControllerTest
,
201 HingeAnglesWithLidClosed
) {
202 AttachTickClockForTest();
206 OpenLidToAngle(270.0f
);
207 EXPECT_FALSE(IsMaximizeModeStarted());
209 OpenLidToAngle(315.0f
);
210 EXPECT_FALSE(IsMaximizeModeStarted());
212 OpenLidToAngle(355.0f
);
213 EXPECT_FALSE(IsMaximizeModeStarted());
216 // Verify the maximize mode state for unstable hinge angles when the lid was
218 TEST_F(MaximizeModeControllerTest
,
219 UnstableHingeAnglesWhenLidRecentlyOpened
) {
220 AttachTickClockForTest();
223 ASSERT_TRUE(WasLidOpenedRecently());
225 OpenLidToAngle(5.0f
);
226 EXPECT_FALSE(IsMaximizeModeStarted());
228 OpenLidToAngle(355.0f
);
229 EXPECT_FALSE(IsMaximizeModeStarted());
231 // This is a stable reading and should clear the last lid opened time.
232 OpenLidToAngle(45.0f
);
233 EXPECT_FALSE(IsMaximizeModeStarted());
234 EXPECT_FALSE(WasLidOpenedRecently());
236 OpenLidToAngle(355.0f
);
237 EXPECT_TRUE(IsMaximizeModeStarted());
240 // Verify the WasLidOpenedRecently signal with respect to time.
241 TEST_F(MaximizeModeControllerTest
, WasLidOpenedRecentlyOverTime
) {
242 AttachTickClockForTest();
244 // No lid open time initially.
245 ASSERT_FALSE(WasLidOpenedRecently());
248 EXPECT_FALSE(WasLidOpenedRecently());
251 EXPECT_TRUE(WasLidOpenedRecently());
253 // 1 second after lid open.
254 AdvanceTickClock(base::TimeDelta::FromSeconds(1));
255 EXPECT_TRUE(WasLidOpenedRecently());
257 // 3 seconds after lid open.
258 AdvanceTickClock(base::TimeDelta::FromSeconds(2));
259 EXPECT_FALSE(WasLidOpenedRecently());
262 // Verify the maximize mode enter/exit thresholds for stable angles.
263 TEST_F(MaximizeModeControllerTest
, StableHingeAnglesWithLidOpened
) {
264 ASSERT_FALSE(IsMaximizeModeStarted());
265 ASSERT_FALSE(WasLidOpenedRecently());
267 OpenLidToAngle(180.0f
);
268 EXPECT_FALSE(IsMaximizeModeStarted());
270 OpenLidToAngle(315.0f
);
271 EXPECT_TRUE(IsMaximizeModeStarted());
273 OpenLidToAngle(180.0f
);
274 EXPECT_TRUE(IsMaximizeModeStarted());
276 OpenLidToAngle(45.0f
);
277 EXPECT_FALSE(IsMaximizeModeStarted());
279 OpenLidToAngle(270.0f
);
280 EXPECT_TRUE(IsMaximizeModeStarted());
282 OpenLidToAngle(90.0f
);
283 EXPECT_FALSE(IsMaximizeModeStarted());
286 // Verify the maximize mode state for unstable hinge angles when the lid is open
288 TEST_F(MaximizeModeControllerTest
, UnstableHingeAnglesWithLidOpened
) {
289 AttachTickClockForTest();
291 ASSERT_FALSE(WasLidOpenedRecently());
292 ASSERT_FALSE(IsMaximizeModeStarted());
294 OpenLidToAngle(5.0f
);
295 EXPECT_FALSE(IsMaximizeModeStarted());
297 OpenLidToAngle(355.0f
);
298 EXPECT_TRUE(IsMaximizeModeStarted());
300 OpenLidToAngle(5.0f
);
301 EXPECT_TRUE(IsMaximizeModeStarted());
304 // Tests that when the hinge is nearly vertically aligned, the current state
305 // persists as the computed angle is highly inaccurate in this orientation.
306 TEST_F(MaximizeModeControllerTest
, HingeAligned
) {
307 // Laptop in normal orientation lid open 90 degrees.
308 TriggerBaseAndLidUpdate(gfx::Vector3dF(0.0f
, 0.0f
, -kMeanGravity
),
309 gfx::Vector3dF(0.0f
, -kMeanGravity
, 0.0f
));
310 EXPECT_FALSE(IsMaximizeModeStarted());
312 // Completely vertical.
313 TriggerBaseAndLidUpdate(gfx::Vector3dF(kMeanGravity
, 0.0f
, 0.0f
),
314 gfx::Vector3dF(kMeanGravity
, 0.0f
, 0.0f
));
315 EXPECT_FALSE(IsMaximizeModeStarted());
317 // Close to vertical but with hinge appearing to be open 270 degrees.
318 TriggerBaseAndLidUpdate(gfx::Vector3dF(kMeanGravity
, 0.0f
, -0.1f
),
319 gfx::Vector3dF(kMeanGravity
, 0.1f
, 0.0f
));
320 EXPECT_FALSE(IsMaximizeModeStarted());
322 // Flat and open 270 degrees should start maximize mode.
323 TriggerBaseAndLidUpdate(gfx::Vector3dF(0.0f
, 0.0f
, -kMeanGravity
),
324 gfx::Vector3dF(0.0f
, kMeanGravity
, 0.0f
));
325 EXPECT_TRUE(IsMaximizeModeStarted());
327 // Normal 90 degree orientation but near vertical should stay in maximize
329 TriggerBaseAndLidUpdate(gfx::Vector3dF(kMeanGravity
, 0.0f
, -0.1f
),
330 gfx::Vector3dF(kMeanGravity
, -0.1f
, 0.0f
));
331 EXPECT_TRUE(IsMaximizeModeStarted());
334 TEST_F(MaximizeModeControllerTest
, LaptopTest
) {
335 // Feeds in sample accelerometer data and verifies that there are no
336 // transitions into touchview / maximize mode while shaking the device around
337 // with the hinge at less than 180 degrees. Note the conversion from device
338 // data to accelerometer updates consistent with accelerometer_reader.cc.
339 ASSERT_EQ(0u, kAccelerometerLaptopModeTestDataLength
% 6);
340 for (size_t i
= 0; i
< kAccelerometerLaptopModeTestDataLength
/ 6; ++i
) {
341 gfx::Vector3dF
base(-kAccelerometerLaptopModeTestData
[i
* 6 + 1],
342 -kAccelerometerLaptopModeTestData
[i
* 6],
343 -kAccelerometerLaptopModeTestData
[i
* 6 + 2]);
344 base
.Scale(kMeanGravity
);
345 gfx::Vector3dF
lid(-kAccelerometerLaptopModeTestData
[i
* 6 + 4],
346 kAccelerometerLaptopModeTestData
[i
* 6 + 3],
347 kAccelerometerLaptopModeTestData
[i
* 6 + 5]);
348 lid
.Scale(kMeanGravity
);
349 TriggerBaseAndLidUpdate(base
, lid
);
350 // There are a lot of samples, so ASSERT rather than EXPECT to only generate
351 // one failure rather than potentially hundreds.
352 ASSERT_FALSE(IsMaximizeModeStarted());
356 TEST_F(MaximizeModeControllerTest
, MaximizeModeTest
) {
357 // Trigger maximize mode by opening to 270 to begin the test in maximize mode.
358 TriggerBaseAndLidUpdate(gfx::Vector3dF(0.0f
, 0.0f
, kMeanGravity
),
359 gfx::Vector3dF(0.0f
, -kMeanGravity
, 0.0f
));
360 ASSERT_TRUE(IsMaximizeModeStarted());
362 // Feeds in sample accelerometer data and verifies that there are no
363 // transitions out of touchview / maximize mode while shaking the device
364 // around. Note the conversion from device data to accelerometer updates
365 // consistent with accelerometer_reader.cc.
366 ASSERT_EQ(0u, kAccelerometerFullyOpenTestDataLength
% 6);
367 for (size_t i
= 0; i
< kAccelerometerFullyOpenTestDataLength
/ 6; ++i
) {
368 gfx::Vector3dF
base(-kAccelerometerFullyOpenTestData
[i
* 6 + 1],
369 -kAccelerometerFullyOpenTestData
[i
* 6],
370 -kAccelerometerFullyOpenTestData
[i
* 6 + 2]);
371 base
.Scale(kMeanGravity
);
372 gfx::Vector3dF
lid(-kAccelerometerFullyOpenTestData
[i
* 6 + 4],
373 kAccelerometerFullyOpenTestData
[i
* 6 + 3],
374 kAccelerometerFullyOpenTestData
[i
* 6 + 5]);
375 lid
.Scale(kMeanGravity
);
376 TriggerBaseAndLidUpdate(base
, lid
);
377 // There are a lot of samples, so ASSERT rather than EXPECT to only generate
378 // one failure rather than potentially hundreds.
379 ASSERT_TRUE(IsMaximizeModeStarted());
383 TEST_F(MaximizeModeControllerTest
, VerticalHingeTest
) {
384 // Feeds in sample accelerometer data and verifies that there are no
385 // transitions out of touchview / maximize mode while shaking the device
386 // around, while the hinge is nearly vertical. The data was captured from
387 // maxmimize_mode_controller.cc and does not require conversion.
388 ASSERT_EQ(0u, kAccelerometerVerticalHingeTestDataLength
% 6);
389 for (size_t i
= 0; i
< kAccelerometerVerticalHingeTestDataLength
/ 6; ++i
) {
390 gfx::Vector3dF
base(kAccelerometerVerticalHingeTestData
[i
* 6],
391 kAccelerometerVerticalHingeTestData
[i
* 6 + 1],
392 kAccelerometerVerticalHingeTestData
[i
* 6 + 2]);
393 gfx::Vector3dF
lid(kAccelerometerVerticalHingeTestData
[i
* 6 + 3],
394 kAccelerometerVerticalHingeTestData
[i
* 6 + 4],
395 kAccelerometerVerticalHingeTestData
[i
* 6 + 5]);
396 TriggerBaseAndLidUpdate(base
, lid
);
397 // There are a lot of samples, so ASSERT rather than EXPECT to only generate
398 // one failure rather than potentially hundreds.
399 ASSERT_TRUE(IsMaximizeModeStarted());
403 // Tests that CanEnterMaximizeMode returns false until a valid accelerometer
404 // event has been received, and that it returns true afterwards.
405 TEST_F(MaximizeModeControllerTest
,
406 CanEnterMaximizeModeRequiresValidAccelerometerUpdate
) {
407 // Should be false until an accelerometer event is sent.
408 ASSERT_FALSE(maximize_mode_controller()->CanEnterMaximizeMode());
409 OpenLidToAngle(90.0f
);
410 EXPECT_TRUE(maximize_mode_controller()->CanEnterMaximizeMode());
413 // Tests that when an accelerometer event is received which has no keyboard that
414 // we enter maximize mode.
415 TEST_F(MaximizeModeControllerTest
,
416 NoKeyboardAccelerometerTriggersMaximizeMode
) {
417 ASSERT_FALSE(IsMaximizeModeStarted());
418 TriggerLidUpdate(gfx::Vector3dF(0.0f
, 0.0f
, kMeanGravity
));
419 ASSERT_TRUE(IsMaximizeModeStarted());
422 // Test if this case does not crash. See http://crbug.com/462806
423 TEST_F(MaximizeModeControllerTest
, DisplayDisconnectionDuringOverview
) {
424 if (!SupportsMultipleDisplays())
427 UpdateDisplay("800x600,800x600");
428 scoped_ptr
<aura::Window
> w1(
429 CreateTestWindowInShellWithBounds(gfx::Rect(0, 0, 100, 100)));
430 scoped_ptr
<aura::Window
> w2(
431 CreateTestWindowInShellWithBounds(gfx::Rect(800, 0, 100, 100)));
432 ASSERT_NE(w1
->GetRootWindow(), w2
->GetRootWindow());
434 maximize_mode_controller()->EnableMaximizeModeWindowManager(true);
435 Shell::GetInstance()->window_selector_controller()->ToggleOverview();
437 UpdateDisplay("800x600");
439 Shell::GetInstance()->window_selector_controller()->IsSelecting());
440 EXPECT_EQ(w1
->GetRootWindow(), w2
->GetRootWindow());
443 class MaximizeModeControllerSwitchesTest
: public MaximizeModeControllerTest
{
445 MaximizeModeControllerSwitchesTest() {}
446 ~MaximizeModeControllerSwitchesTest() override
{}
448 void SetUp() override
{
449 base::CommandLine::ForCurrentProcess()->AppendSwitch(
450 switches::kAshEnableTouchViewTesting
);
451 MaximizeModeControllerTest::SetUp();
454 DISALLOW_COPY_AND_ASSIGN(MaximizeModeControllerSwitchesTest
);
457 // Tests that when the command line switch for testing maximize mode is on, that
458 // accelerometer updates which would normally cause it to exit do not.
459 TEST_F(MaximizeModeControllerSwitchesTest
, IgnoreHingeAngles
) {
460 maximize_mode_controller()->EnableMaximizeModeWindowManager(true);
462 // Would normally trigger an exit from maximize mode.
463 OpenLidToAngle(90.0f
);
464 EXPECT_TRUE(IsMaximizeModeStarted());