1 // Copyright 2016 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 "ash/system/power/power_button_controller.h"
6
7 #include "ash/accessibility/test_accessibility_controller_client.h"
8 #include "ash/display/screen_orientation_controller.h"
9 #include "ash/display/screen_orientation_controller_test_api.h"
10 #include "ash/media/media_controller_impl.h"
11 #include "ash/public/cpp/ash_switches.h"
12 #include "ash/session/session_controller_impl.h"
13 #include "ash/shell.h"
14 #include "ash/system/power/power_button_controller_test_api.h"
15 #include "ash/system/power/power_button_menu_item_view.h"
16 #include "ash/system/power/power_button_menu_view.h"
17 #include "ash/system/power/power_button_test_base.h"
18 #include "ash/test_media_client.h"
19 #include "ash/touch/touch_devices_controller.h"
20 #include "ash/wm/lock_state_controller_test_api.h"
21 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
22 #include "ash/wm/test_session_state_animator.h"
23 #include "ash/wm/window_util.h"
24 #include "base/command_line.h"
25 #include "base/json/json_writer.h"
26 #include "base/run_loop.h"
27 #include "base/test/simple_test_tick_clock.h"
28 #include "chromeos/dbus/power/fake_power_manager_client.h"
29 #include "chromeos/dbus/power_manager/suspend.pb.h"
30 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
31 #include "ui/display/test/display_manager_test_api.h"
32 #include "ui/events/event.h"
33 #include "ui/events/test/event_generator.h"
34 #include "ui/views/widget/widget.h"
35
36 using PowerManagerClient = chromeos::PowerManagerClient;
37
38 namespace ash {
39
40 namespace {
41
42 // A non-zero brightness used for test.
43 constexpr double kNonZeroBrightness = 10.;
44
45 // Width of the display.
46 constexpr int kDisplayWidth = 2000;
47
48 // Height of the display.
49 constexpr int kDisplayHeight = 1200;
50
51 // Power button position offset percentage.
52 constexpr double kPowerButtonPercentage = 0.9f;
53
54 // Shorthand for some long constants.
55 constexpr power_manager::BacklightBrightnessChange_Cause kUserCause =
56 power_manager::BacklightBrightnessChange_Cause_USER_REQUEST;
57 constexpr power_manager::BacklightBrightnessChange_Cause kOtherCause =
58 power_manager::BacklightBrightnessChange_Cause_OTHER;
59
60 } // namespace
61
62 using PowerButtonPosition = PowerButtonController::PowerButtonPosition;
63
64 class PowerButtonControllerTest : public PowerButtonTestBase {
65 public:
66 PowerButtonControllerTest() = default;
67 ~PowerButtonControllerTest() override = default;
68
SetUp()69 void SetUp() override {
70 PowerButtonTestBase::SetUp();
71 InitPowerButtonControllerMembers(PowerManagerClient::TabletMode::ON);
72
73 SendBrightnessChange(kNonZeroBrightness, kUserCause);
74 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
75
76 // Advance a duration longer than |kIgnorePowerButtonAfterResumeDelay| to
77 // avoid events being ignored.
78 tick_clock_.Advance(
79 PowerButtonController::kIgnorePowerButtonAfterResumeDelay +
80 base::TimeDelta::FromMilliseconds(2));
81
82 // Run the event loop so that PowerButtonDisplayController can receive the
83 // initial backlights-forced-off state.
84 base::RunLoop().RunUntilIdle();
85 }
86
87 protected:
SendBrightnessChange(double percent,power_manager::BacklightBrightnessChange_Cause cause)88 void SendBrightnessChange(
89 double percent,
90 power_manager::BacklightBrightnessChange_Cause cause) {
91 power_manager::BacklightBrightnessChange change;
92 change.set_percent(percent);
93 change.set_cause(cause);
94 power_manager_client()->SendScreenBrightnessChanged(change);
95 }
96
GetLockedState()97 bool GetLockedState() {
98 // LockScreen is an async mojo call.
99 GetSessionControllerClient()->FlushForTest();
100 return Shell::Get()->session_controller()->IsScreenLocked();
101 }
102
GetGlobalTouchscreenEnabled() const103 bool GetGlobalTouchscreenEnabled() const {
104 return Shell::Get()->touch_devices_controller()->GetTouchscreenEnabled(
105 TouchDeviceEnabledSource::GLOBAL);
106 }
107
108 // Tapping power button when screen is off will turn the screen on but not
109 // showing the menu.
TappingPowerButtonWhenScreenIsIdleOff()110 void TappingPowerButtonWhenScreenIsIdleOff() {
111 SendBrightnessChange(0, kUserCause);
112 PressPowerButton();
113 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
114 SendBrightnessChange(kNonZeroBrightness, kUserCause);
115 ReleasePowerButton();
116 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
117 EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
118 }
119
120 // Press the power button to show the menu.
OpenPowerButtonMenu()121 void OpenPowerButtonMenu() {
122 PressPowerButton();
123 if (Shell::Get()->tablet_mode_controller()->InTabletMode()) {
124 EXPECT_TRUE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
125 ASSERT_TRUE(power_button_test_api_->TriggerPowerButtonMenuTimeout());
126 }
127 ReleasePowerButton();
128 ASSERT_TRUE(power_button_test_api_->IsMenuOpened());
129 }
130
131 // Tap outside of the menu view to dismiss the menu.
TapToDismissPowerButtonMenu()132 void TapToDismissPowerButtonMenu() {
133 gfx::Rect menu_bounds = power_button_test_api_->GetMenuBoundsInScreen();
134 gfx::Point point = menu_bounds.bottom_right();
135 point.Offset(5, 5);
136 GetEventGenerator()->GestureTapAt(point);
137
138 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
139 }
140
PressLockButton()141 void PressLockButton() {
142 power_button_controller_->OnLockButtonEvent(true, base::TimeTicks::Now());
143 }
144
ReleaseLockButton()145 void ReleaseLockButton() {
146 power_button_controller_->OnLockButtonEvent(false, base::TimeTicks::Now());
147 }
148
149 private:
150 DISALLOW_COPY_AND_ASSIGN(PowerButtonControllerTest);
151 };
152
TEST_F(PowerButtonControllerTest,LockScreenIfRequired)153 TEST_F(PowerButtonControllerTest, LockScreenIfRequired) {
154 Initialize(ButtonType::NORMAL, LoginStatus::USER);
155 EnableTabletMode(true);
156 SetShouldLockScreenAutomatically(true);
157 ASSERT_FALSE(GetLockedState());
158
159 // On User logged in status, power-button-press-release should lock screen if
160 // automatic screen-locking was requested.
161 PressPowerButton();
162 ReleasePowerButton();
163 EXPECT_TRUE(GetLockedState());
164
165 // On locked state, power-button-press-release should do nothing.
166 PressPowerButton();
167 ReleasePowerButton();
168 EXPECT_TRUE(GetLockedState());
169
170 // Unlock the sceen.
171 UnlockScreen();
172 ASSERT_FALSE(GetLockedState());
173
174 // power-button-press-release should not lock the screen if automatic
175 // screen-locking wasn't requested.
176 SetShouldLockScreenAutomatically(false);
177 PressPowerButton();
178 ReleasePowerButton();
179 EXPECT_FALSE(GetLockedState());
180 }
181
182 // Tests tapping the power button of a clamshell device.
TEST_F(PowerButtonControllerTest,TappingPowerButtonOfClamshell)183 TEST_F(PowerButtonControllerTest, TappingPowerButtonOfClamshell) {
184 // Should not turn the screen off when screen is on.
185 InitPowerButtonControllerMembers(PowerManagerClient::TabletMode::UNSUPPORTED);
186 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
187 PressPowerButton();
188 power_button_test_api_->SetShowMenuAnimationDone(false);
189 // Start the showing power menu animation immediately as pressing the
190 // clamshell power button.
191 EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
192 EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
193 ReleasePowerButton();
194 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
195 // Start the dimissing power menu animation immediately as releasing the
196 // clamsehll power button if showing animation hasn't finished.
197 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
198
199 AdvanceClockToAvoidIgnoring();
200 // Should turn screen on if screen is off.
201 TappingPowerButtonWhenScreenIsIdleOff();
202 ASSERT_TRUE(power_button_test_api_->IsMenuOpened());
203
204 AdvanceClockToAvoidIgnoring();
205 // Should not start the dismissing menu animation if showing menu animation
206 // has finished.
207 PressPowerButton();
208 // Start the showing power menu animation immediately as pressing the
209 // clamshell power button.
210 EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
211 EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
212 power_button_test_api_->SetShowMenuAnimationDone(true);
213 ASSERT_TRUE(power_button_test_api_->TriggerPreShutdownTimeout());
214 ReleasePowerButton();
215 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
216 // Power button menu should keep opened if showing animation has finished.
217 EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
218
219 // Tapping power button when menu is already shown should keep the screen on
220 // and dismiss the power menu.
221 AdvanceClockToAvoidIgnoring();
222 PressPowerButton();
223 ReleasePowerButton();
224 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
225 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
226 }
227
228 // Tests tapping the power button of a device that has a tablet mode switch.
TEST_F(PowerButtonControllerTest,TappingPowerButtonOfTablet)229 TEST_F(PowerButtonControllerTest, TappingPowerButtonOfTablet) {
230 EnableTabletMode(true);
231 // Should turn screen off if screen is on and power button menu will not be
232 // shown.
233 PressPowerButton();
234 // Showing power menu animation hasn't started as power menu timer is running.
235 EXPECT_TRUE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
236 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
237 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
238 ReleasePowerButton();
239 EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
240 EXPECT_TRUE(power_manager_client()->backlights_forced_off());
241 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
242
243 // Should turn screen on if screen is off.
244 AdvanceClockToAvoidIgnoring();
245 TappingPowerButtonWhenScreenIsIdleOff();
246
247 // Showing power menu animation should start until power menu timer is
248 // timeout.
249 AdvanceClockToAvoidIgnoring();
250 PressPowerButton();
251 power_button_test_api_->SetShowMenuAnimationDone(false);
252 EXPECT_TRUE(power_button_test_api_->TriggerPowerButtonMenuTimeout());
253 EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
254 EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
255 ReleasePowerButton();
256 // Showing animation will continue until show the power button menu even
257 // release the power button.
258 EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
259
260 // Tapping power button when menu is already shown should still turn screen
261 // off and dismiss the menu.
262 AdvanceClockToAvoidIgnoring();
263 PressPowerButton();
264 EXPECT_TRUE(power_button_test_api_->PreShutdownTimerIsRunning());
265 ReleasePowerButton();
266 EXPECT_FALSE(power_button_test_api_->PreShutdownTimerIsRunning());
267 EXPECT_TRUE(power_manager_client()->backlights_forced_off());
268 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
269
270 // Should turn screen on if screen is off.
271 AdvanceClockToAvoidIgnoring();
272 TappingPowerButtonWhenScreenIsIdleOff();
273 }
274
275 // Tests that power button taps turn the screen off while in tablet mode but not
276 // in laptop mode.
TEST_F(PowerButtonControllerTest,ModeSpecificPowerButton)277 TEST_F(PowerButtonControllerTest, ModeSpecificPowerButton) {
278 // While the device is in tablet mode, tapping the power button should turn
279 // the display off (and then back on if pressed a second time).
280 EnableTabletMode(true);
281 PressPowerButton();
282 ReleasePowerButton();
283 EXPECT_TRUE(power_manager_client()->backlights_forced_off());
284 PressPowerButton();
285 ReleasePowerButton();
286 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
287
288 // In laptop mode, tapping the power button shouldn't turn the screen off.
289 // Instead, we should start showing the power menu animation.
290 EnableTabletMode(false);
291 AdvanceClockToAvoidIgnoring();
292 PressPowerButton();
293 EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
294 ReleasePowerButton();
295 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
296
297 // Tapping power button again in laptop mode when menu is opened should
298 // dismiss the menu but keep the screen on.
299 EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
300 AdvanceClockToAvoidIgnoring();
301 PressPowerButton();
302 EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
303 EXPECT_TRUE(power_button_test_api_->PreShutdownTimerIsRunning());
304 ReleasePowerButton();
305 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
306 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
307 }
308
309 // Tests that when the kForceTabletPowerButton flag is passed (indicating that
310 // the device is tablet-like) tapping the power button turns the screen off
311 // regardless of what the tablet mode switch reports.
TEST_F(PowerButtonControllerTest,ForceTabletPowerButton)312 TEST_F(PowerButtonControllerTest, ForceTabletPowerButton) {
313 base::CommandLine::ForCurrentProcess()->AppendSwitch(
314 switches::kForceTabletPowerButton);
315 ResetPowerButtonController();
316
317 PressPowerButton();
318 ReleasePowerButton();
319 EXPECT_TRUE(power_manager_client()->backlights_forced_off());
320 PressPowerButton();
321 ReleasePowerButton();
322 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
323
324 EnableTabletMode(false);
325 AdvanceClockToAvoidIgnoring();
326 PressPowerButton();
327 ReleasePowerButton();
328 EXPECT_TRUE(power_manager_client()->backlights_forced_off());
329 PressPowerButton();
330 ReleasePowerButton();
331 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
332 }
333
334 // Tests that release power button after menu is opened but before trigger
335 // shutdown will not turn screen off.
TEST_F(PowerButtonControllerTest,ReleasePowerButtonBeforeTriggerShutdown)336 TEST_F(PowerButtonControllerTest, ReleasePowerButtonBeforeTriggerShutdown) {
337 EnableTabletMode(true);
338 PressPowerButton();
339 EXPECT_TRUE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
340 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
341 ASSERT_TRUE(power_button_test_api_->TriggerPowerButtonMenuTimeout());
342 ASSERT_TRUE(power_button_test_api_->TriggerPreShutdownTimeout());
343 EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running());
344 ReleasePowerButton();
345 EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
346 EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running());
347 EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
348 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
349 }
350
351 // Tests that tapping the power button dismisses the menu while in laptop mode.
TEST_F(PowerButtonControllerTest,HoldPowerButtonWhileMenuShownInLaptopMode)352 TEST_F(PowerButtonControllerTest, HoldPowerButtonWhileMenuShownInLaptopMode) {
353 // Hold the power button long enough to show the menu and start the
354 // cancellable shutdown animation. The menu should remain open.
355 PressPowerButton();
356 ASSERT_TRUE(power_button_test_api_->IsMenuOpened());
357 power_button_test_api_->SetShowMenuAnimationDone(true);
358 ASSERT_TRUE(power_button_test_api_->TriggerPreShutdownTimeout());
359 ASSERT_TRUE(lock_state_test_api_->shutdown_timer_is_running());
360 ReleasePowerButton();
361 EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running());
362 EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
363
364 // Hold the power button long enough to start the cancellable shutdown
365 // animation again. The menu should remain open.
366 AdvanceClockToAvoidIgnoring();
367 PressPowerButton();
368 ASSERT_TRUE(power_button_test_api_->TriggerPreShutdownTimeout());
369 ASSERT_TRUE(lock_state_test_api_->shutdown_timer_is_running());
370 ReleasePowerButton();
371 EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running());
372 EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
373
374 // This time, just tap the power button (i.e. release it before the
375 // cancellable shutdown animation starts). The menu should be dismissed.
376 AdvanceClockToAvoidIgnoring();
377 PressPowerButton();
378 ReleasePowerButton();
379 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
380 }
381
382 // Tests press lock button and power button in sequence.
TEST_F(PowerButtonControllerTest,PressAfterAnotherReleased)383 TEST_F(PowerButtonControllerTest, PressAfterAnotherReleased) {
384 // Tap power button after press lock button should still turn screen off.
385 Initialize(ButtonType::NORMAL, LoginStatus::USER);
386 EnableTabletMode(true);
387 PressLockButton();
388 ReleaseLockButton();
389 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
390 PressPowerButton();
391 ReleasePowerButton();
392 EXPECT_TRUE(power_manager_client()->backlights_forced_off());
393
394 // Press lock button after tap power button should still lock screen.
395 PressPowerButton();
396 ReleasePowerButton();
397 PressLockButton();
398 ReleaseLockButton();
399 EXPECT_TRUE(lock_state_test_api_->is_animating_lock());
400 EXPECT_TRUE(GetLockedState());
401 }
402
403 // Tests press lock/power button before release power/lock button.
TEST_F(PowerButtonControllerTest,PressBeforeAnotherReleased)404 TEST_F(PowerButtonControllerTest, PressBeforeAnotherReleased) {
405 // Press lock button when power button is still being pressed will be ignored
406 // and continue to turn screen off.
407 Initialize(ButtonType::NORMAL, LoginStatus::USER);
408 EnableTabletMode(true);
409 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
410 PressPowerButton();
411 PressLockButton();
412 ReleaseLockButton();
413 ReleasePowerButton();
414 EXPECT_FALSE(lock_state_test_api_->is_animating_lock());
415 EXPECT_FALSE(GetLockedState());
416 EXPECT_TRUE(power_manager_client()->backlights_forced_off());
417
418 // Turn the screen on.
419 PressPowerButton();
420 ReleasePowerButton();
421 // Press power button when lock button is still being pressed. The pressing of
422 // power button will be ignored and continue to lock screen.
423 PressLockButton();
424 PressPowerButton();
425 ReleasePowerButton();
426 ReleaseLockButton();
427 EXPECT_TRUE(lock_state_test_api_->is_animating_lock());
428 EXPECT_TRUE(GetLockedState());
429 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
430 }
431
432 // Tests tapping power button when device is suspended without backlights forced
433 // off.
TEST_F(PowerButtonControllerTest,TappingPowerButtonWhenSuspendedWithoutBacklightsForcedOff)434 TEST_F(PowerButtonControllerTest,
435 TappingPowerButtonWhenSuspendedWithoutBacklightsForcedOff) {
436 EnableTabletMode(true);
437 power_manager_client()->SendSuspendImminent(
438 power_manager::SuspendImminent_Reason_OTHER);
439 SendBrightnessChange(0, kUserCause);
440 // There is a power button pressed here, but PowerButtonEvent is sent later.
441 power_manager_client()->SendSuspendDone();
442 SendBrightnessChange(kNonZeroBrightness, kUserCause);
443
444 // Send the power button event after a short delay and check that backlights
445 // are not forced off.
446 tick_clock_.Advance(base::TimeDelta::FromMilliseconds(500));
447 PressPowerButton();
448 EXPECT_TRUE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
449 ReleasePowerButton();
450 EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
451 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
452
453 // Send the power button event after a longer delay and check that backlights
454 // are forced off.
455 tick_clock_.Advance(base::TimeDelta::FromMilliseconds(1600));
456 PressPowerButton();
457 EXPECT_TRUE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
458 ReleasePowerButton();
459 SendBrightnessChange(0, kUserCause);
460 EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
461 EXPECT_TRUE(power_manager_client()->backlights_forced_off());
462 }
463
464 // Tests tapping power button when device is suspended with backlights forced
465 // off.
TEST_F(PowerButtonControllerTest,TappingPowerButtonWhenSuspendedWithBacklightsForcedOff)466 TEST_F(PowerButtonControllerTest,
467 TappingPowerButtonWhenSuspendedWithBacklightsForcedOff) {
468 EnableTabletMode(true);
469 PressPowerButton();
470 ReleasePowerButton();
471 SendBrightnessChange(0, kUserCause);
472 ASSERT_TRUE(power_manager_client()->backlights_forced_off());
473 power_manager_client()->SendSuspendImminent(
474 power_manager::SuspendImminent_Reason_OTHER);
475 // There is a power button pressed here, but PowerButtonEvent is sent later.
476 // Because of backlights forced off, resuming system will not restore
477 // brightness.
478 power_manager_client()->SendSuspendDone();
479
480 // Send the power button event after a short delay and check that backlights
481 // are not forced off.
482 tick_clock_.Advance(base::TimeDelta::FromMilliseconds(500));
483 PressPowerButton();
484 SendBrightnessChange(kNonZeroBrightness, kUserCause);
485 EXPECT_TRUE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
486 ReleasePowerButton();
487 EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
488 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
489
490 // Send the power button event after a longer delay and check that backlights
491 // are forced off.
492 tick_clock_.Advance(base::TimeDelta::FromMilliseconds(1600));
493 PressPowerButton();
494 EXPECT_TRUE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
495 ReleasePowerButton();
496 SendBrightnessChange(0, kUserCause);
497 EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
498 EXPECT_TRUE(power_manager_client()->backlights_forced_off());
499 }
500
501 // For convertible device working on tablet mode, keyboard/mouse event should
502 // not SetBacklightsForcedOff(false) when screen is off.
TEST_F(PowerButtonControllerTest,ConvertibleOnTabletMode)503 TEST_F(PowerButtonControllerTest, ConvertibleOnTabletMode) {
504 EnableTabletMode(true);
505
506 PressPowerButton();
507 ReleasePowerButton();
508 SendBrightnessChange(0, kUserCause);
509 ASSERT_TRUE(power_manager_client()->backlights_forced_off());
510 PressKey(ui::VKEY_L);
511 EXPECT_TRUE(power_manager_client()->backlights_forced_off());
512
513 GenerateMouseMoveEvent();
514 EXPECT_TRUE(power_manager_client()->backlights_forced_off());
515 }
516
517 // Tests that a single set of power button pressed-and-released operation should
518 // cause only one SetBacklightsForcedOff call.
TEST_F(PowerButtonControllerTest,IgnorePowerOnKeyEvent)519 TEST_F(PowerButtonControllerTest, IgnorePowerOnKeyEvent) {
520 ui::KeyEvent power_key_pressed(ui::ET_KEY_PRESSED, ui::VKEY_POWER,
521 ui::EF_NONE);
522 ui::KeyEvent power_key_released(ui::ET_KEY_RELEASED, ui::VKEY_POWER,
523 ui::EF_NONE);
524
525 // There are two |power_key_pressed| events and |power_key_released| events
526 // generated for each pressing and releasing, and multiple repeating pressed
527 // events depending on holding.
528 ASSERT_EQ(0, power_manager_client()->num_set_backlights_forced_off_calls());
529 EnableTabletMode(true);
530 power_button_test_api_->SendKeyEvent(&power_key_pressed);
531 power_button_test_api_->SendKeyEvent(&power_key_pressed);
532 PressPowerButton();
533 power_button_test_api_->SendKeyEvent(&power_key_pressed);
534 power_button_test_api_->SendKeyEvent(&power_key_pressed);
535 power_button_test_api_->SendKeyEvent(&power_key_pressed);
536 ReleasePowerButton();
537 power_button_test_api_->SendKeyEvent(&power_key_released);
538 power_button_test_api_->SendKeyEvent(&power_key_released);
539 EXPECT_EQ(1, power_manager_client()->num_set_backlights_forced_off_calls());
540 }
541
542 // Tests that when the power button is pressed/released in tablet mode,
543 // requesting/stopping backlights forced off should update the global
544 // touchscreen enabled status.
TEST_F(PowerButtonControllerTest,DisableTouchscreenWhileForcedOff)545 TEST_F(PowerButtonControllerTest, DisableTouchscreenWhileForcedOff) {
546 // Tests tablet power button.
547 EnableTabletMode(true);
548 ASSERT_TRUE(GetGlobalTouchscreenEnabled());
549 PressPowerButton();
550 ReleasePowerButton();
551 SendBrightnessChange(0, kUserCause);
552 EXPECT_FALSE(GetGlobalTouchscreenEnabled());
553
554 PressPowerButton();
555 SendBrightnessChange(kNonZeroBrightness, kUserCause);
556 ReleasePowerButton();
557 EXPECT_TRUE(GetGlobalTouchscreenEnabled());
558 }
559
560 // When the screen is turned off automatically, the touchscreen should also be
561 // disabled.
TEST_F(PowerButtonControllerTest,DisableTouchscreenForInactivity)562 TEST_F(PowerButtonControllerTest, DisableTouchscreenForInactivity) {
563 ASSERT_TRUE(GetGlobalTouchscreenEnabled());
564
565 // Turn screen off for automated change (e.g. user is inactive).
566 SendBrightnessChange(0, kOtherCause);
567 EXPECT_FALSE(GetGlobalTouchscreenEnabled());
568 SendBrightnessChange(kNonZeroBrightness, kUserCause);
569 EXPECT_TRUE(GetGlobalTouchscreenEnabled());
570
571 // After decreasing the brightness to zero for a user request, the touchscreen
572 // should remain enabled.
573 SendBrightnessChange(0, kUserCause);
574 EXPECT_TRUE(GetGlobalTouchscreenEnabled());
575 }
576
577 // When user switches convertible device between tablet mode and laptop mode,
578 // power button may be pressed and held, which may cause unwanted unclean
579 // shutdown.
TEST_F(PowerButtonControllerTest,LeaveTabletModeWhilePressingPowerButton)580 TEST_F(PowerButtonControllerTest, LeaveTabletModeWhilePressingPowerButton) {
581 EnableTabletMode(true);
582 PressPowerButton();
583 EXPECT_TRUE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
584 EnableTabletMode(false);
585 EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
586 tick_clock_.Advance(base::TimeDelta::FromMilliseconds(1500));
587 ReleasePowerButton();
588 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
589 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
590 }
591
592 // Tests that repeated power button releases are ignored (crbug.com/675291).
TEST_F(PowerButtonControllerTest,IgnoreRepeatedPowerButtonReleases)593 TEST_F(PowerButtonControllerTest, IgnoreRepeatedPowerButtonReleases) {
594 // Set backlights forced off for starting point.
595 EnableTabletMode(true);
596 PressPowerButton();
597 ReleasePowerButton();
598 SendBrightnessChange(0, kUserCause);
599 ASSERT_TRUE(power_manager_client()->backlights_forced_off());
600
601 // Test that a pressing-releasing operation after a short duration, backlights
602 // forced off is stopped since we don't drop request for power button pressed.
603 tick_clock_.Advance(base::TimeDelta::FromMilliseconds(200));
604 PressPowerButton();
605 SendBrightnessChange(kNonZeroBrightness, kUserCause);
606 ReleasePowerButton();
607 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
608
609 // Test that after another short duration, backlights will not be forced off
610 // since this immediately following forcing off request needs to be dropped.
611 tick_clock_.Advance(base::TimeDelta::FromMilliseconds(200));
612 PressPowerButton();
613 ReleasePowerButton();
614 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
615
616 // Test that after another long duration, backlights should be forced off.
617 tick_clock_.Advance(base::TimeDelta::FromMilliseconds(800));
618 PressPowerButton();
619 ReleasePowerButton();
620 SendBrightnessChange(0, kUserCause);
621 EXPECT_TRUE(power_manager_client()->backlights_forced_off());
622 }
623
624 // Tests that repeated power button releases of clamshell should cancel the
625 // ongoing showing menu animation.
TEST_F(PowerButtonControllerTest,ClamshellRepeatedPowerButtonReleasesCancelledAnimation)626 TEST_F(PowerButtonControllerTest,
627 ClamshellRepeatedPowerButtonReleasesCancelledAnimation) {
628 InitPowerButtonControllerMembers(PowerManagerClient::TabletMode::UNSUPPORTED);
629 EnableTabletMode(false);
630
631 // Enable animations so that we can make sure that they occur.
632 ui::ScopedAnimationDurationScaleMode regular_animations(
633 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
634
635 PressPowerButton();
636 ReleasePowerButton();
637 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
638
639 tick_clock_.Advance(base::TimeDelta::FromMilliseconds(200));
640 PressPowerButton();
641 ReleasePowerButton();
642 // Showing menu animation should be cancelled and menu is not shown.
643 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
644 EXPECT_FALSE(power_button_test_api_->PreShutdownTimerIsRunning());
645 }
646
647 // Tests that lid closed events stop forcing off backlights.
TEST_F(PowerButtonControllerTest,LidEventsStopForcingOff)648 TEST_F(PowerButtonControllerTest, LidEventsStopForcingOff) {
649 // Pressing/releasing power button to set backlights forced off.
650 EnableTabletMode(true);
651 PressPowerButton();
652 ReleasePowerButton();
653 ASSERT_TRUE(power_manager_client()->backlights_forced_off());
654
655 // A lid closed event is received, we should stop forcing off backlights.
656 power_manager_client()->SetLidState(PowerManagerClient::LidState::CLOSED,
657 tick_clock_.NowTicks());
658 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
659 }
660
661 // Tests that tablet mode events from powerd stop forcing off backlights.
TEST_F(PowerButtonControllerTest,TabletModeEventsStopForcingOff)662 TEST_F(PowerButtonControllerTest, TabletModeEventsStopForcingOff) {
663 EnableTabletMode(true);
664 PressPowerButton();
665 ReleasePowerButton();
666 ASSERT_TRUE(power_manager_client()->backlights_forced_off());
667 power_manager_client()->SetTabletMode(PowerManagerClient::TabletMode::OFF,
668 tick_clock_.NowTicks());
669 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
670
671 AdvanceClockToAvoidIgnoring();
672 PressPowerButton();
673 ReleasePowerButton();
674 ASSERT_TRUE(power_manager_client()->backlights_forced_off());
675 power_manager_client()->SetTabletMode(PowerManagerClient::TabletMode::ON,
676 tick_clock_.NowTicks());
677 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
678 }
679
680 // Tests that with system reboot, the global touchscreen enabled status should
681 // be synced with new backlights forced off state from powerd.
TEST_F(PowerButtonControllerTest,SyncTouchscreenEnabled)682 TEST_F(PowerButtonControllerTest, SyncTouchscreenEnabled) {
683 Shell::Get()->touch_devices_controller()->SetTouchscreenEnabled(
684 false, TouchDeviceEnabledSource::GLOBAL);
685 ASSERT_FALSE(GetGlobalTouchscreenEnabled());
686
687 // Simulate system reboot by resetting backlights forced off state in powerd
688 // and PowerButtonController.
689 power_manager_client()->SetBacklightsForcedOff(false);
690 ResetPowerButtonController();
691 SetTabletModeSwitchState(PowerManagerClient::TabletMode::ON);
692
693 // Run the event loop for PowerButtonDisplayController to get backlight state
694 // and check that the global touchscreen status is correct.
695 base::RunLoop().RunUntilIdle();
696 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
697 EXPECT_TRUE(GetGlobalTouchscreenEnabled());
698 }
699
700 // Tests that when backlights get forced off due to tablet power button, media
701 // sessions should be suspended.
TEST_F(PowerButtonControllerTest,SuspendMediaSessions)702 TEST_F(PowerButtonControllerTest, SuspendMediaSessions) {
703 TestMediaClient client;
704 Shell::Get()->media_controller()->SetClient(&client);
705 ASSERT_FALSE(client.media_sessions_suspended());
706
707 EnableTabletMode(true);
708 PressPowerButton();
709 ReleasePowerButton();
710 // Run the event loop for PowerButtonDisplayController to get backlight state.
711 base::RunLoop().RunUntilIdle();
712 ASSERT_TRUE(power_manager_client()->backlights_forced_off());
713 EXPECT_TRUE(client.media_sessions_suspended());
714 }
715
716 // Tests that when system is suspended with backlights forced off, and then
717 // system resumes due to power button pressed without power button event fired
718 // (crbug.com/735291), that we stop forcing off backlights.
TEST_F(PowerButtonControllerTest,SuspendDoneStopsForcingOff)719 TEST_F(PowerButtonControllerTest, SuspendDoneStopsForcingOff) {
720 EnableTabletMode(true);
721 PressPowerButton();
722 ReleasePowerButton();
723 SendBrightnessChange(0, kUserCause);
724 ASSERT_TRUE(power_manager_client()->backlights_forced_off());
725
726 // Simulate an edge case that system resumes because of tablet power button
727 // pressed, but power button event is not delivered.
728 power_manager_client()->SendSuspendDone();
729
730 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
731 }
732
733 // Tests that during the interval that the display is turning on, tablet power
734 // button should not set display off (crbug.com/735225).
TEST_F(PowerButtonControllerTest,IgnoreForcingOffWhenDisplayIsTurningOn)735 TEST_F(PowerButtonControllerTest, IgnoreForcingOffWhenDisplayIsTurningOn) {
736 EnableTabletMode(true);
737 PressPowerButton();
738 ReleasePowerButton();
739 SendBrightnessChange(0, kUserCause);
740 ASSERT_TRUE(power_manager_client()->backlights_forced_off());
741
742 // Simiulate the backlight no longer being forced off due to a key event
743 // (which we need to briefly leave tablet mode to receive). Chrome will
744 // receive a brightness changed signal, but the display may still be off.
745 EnableTabletMode(false);
746 PressKey(ui::VKEY_L);
747 SendBrightnessChange(kNonZeroBrightness, kUserCause);
748 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
749
750 // Since display could still be off, ignore additional button presses.
751 tick_clock_.Advance(PowerButtonController::kScreenStateChangeDelay -
752 base::TimeDelta::FromMilliseconds(1));
753 EnableTabletMode(true);
754 PressPowerButton();
755 ReleasePowerButton();
756 EXPECT_FALSE(power_manager_client()->backlights_forced_off());
757
758 // After waiting long enough, we should be able to force the display off.
759 AdvanceClockToAvoidIgnoring();
760 PressPowerButton();
761 ReleasePowerButton();
762 SendBrightnessChange(0, kUserCause);
763 EXPECT_TRUE(power_manager_client()->backlights_forced_off());
764 }
765
766 // Tests that a11y alert is sent on tablet power button induced screen state
767 // change.
TEST_F(PowerButtonControllerTest,A11yAlert)768 TEST_F(PowerButtonControllerTest, A11yAlert) {
769 TestAccessibilityControllerClient a11y_client;
770
771 EnableTabletMode(true);
772 PressPowerButton();
773 ReleasePowerButton();
774 SendBrightnessChange(0, kUserCause);
775 EXPECT_EQ(AccessibilityAlert::SCREEN_OFF, a11y_client.last_a11y_alert());
776
777 PressPowerButton();
778 SendBrightnessChange(kNonZeroBrightness, kUserCause);
779 EXPECT_EQ(AccessibilityAlert::SCREEN_ON, a11y_client.last_a11y_alert());
780 ReleasePowerButton();
781 }
782
783 // Tests that tap outside of the menu bounds should dismiss the menu.
TEST_F(PowerButtonControllerTest,TapToDismissMenu)784 TEST_F(PowerButtonControllerTest, TapToDismissMenu) {
785 OpenPowerButtonMenu();
786 TapToDismissPowerButtonMenu();
787 }
788
789 // Test that mouse click outside of the menu bounds should dismiss the menu.
TEST_F(PowerButtonControllerTest,MouseClickToDismissMenu)790 TEST_F(PowerButtonControllerTest, MouseClickToDismissMenu) {
791 OpenPowerButtonMenu();
792 gfx::Rect menu_bounds = power_button_test_api_->GetMenuBoundsInScreen();
793 ui::test::EventGenerator* generator = GetEventGenerator();
794 generator->MoveMouseTo(gfx::Point(menu_bounds.x() - 5, menu_bounds.y() - 5));
795 generator->ClickLeftButton();
796 generator->ReleaseLeftButton();
797 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
798 }
799
800 // Tests the menu items according to the login and screen locked status.
TEST_F(PowerButtonControllerTest,MenuItemsToLoginAndLockedStatus)801 TEST_F(PowerButtonControllerTest, MenuItemsToLoginAndLockedStatus) {
802 // Should have feedback but not sign out and lock screen items if there is no
803 // user signed in.
804 ClearLogin();
805 Shell::Get()->UpdateAfterLoginStatusChange(LoginStatus::NOT_LOGGED_IN);
806 OpenPowerButtonMenu();
807 EXPECT_FALSE(power_button_test_api_->MenuHasSignOutItem());
808 EXPECT_FALSE(power_button_test_api_->MenuHasLockScreenItem());
809 EXPECT_TRUE(power_button_test_api_->MenuHasFeedbackItem());
810 TapToDismissPowerButtonMenu();
811
812 // Should have sign out and feedback items if in guest mode (or, generally,
813 // if screen locking is disabled).
814 ClearLogin();
815 Initialize(ButtonType::NORMAL, LoginStatus::GUEST);
816 OpenPowerButtonMenu();
817 EXPECT_FALSE(GetLockedState());
818 EXPECT_TRUE(power_button_test_api_->MenuHasSignOutItem());
819 EXPECT_FALSE(power_button_test_api_->MenuHasLockScreenItem());
820 EXPECT_TRUE(power_button_test_api_->MenuHasFeedbackItem());
821 TapToDismissPowerButtonMenu();
822
823 // Should have sign out, lock screen and feedback items if user is logged in
824 // and screen is unlocked.
825 ClearLogin();
826 CreateUserSessions(1);
827 OpenPowerButtonMenu();
828 EXPECT_FALSE(GetLockedState());
829 EXPECT_TRUE(power_button_test_api_->MenuHasSignOutItem());
830 EXPECT_TRUE(power_button_test_api_->MenuHasLockScreenItem());
831 EXPECT_TRUE(power_button_test_api_->MenuHasFeedbackItem());
832 TapToDismissPowerButtonMenu();
833
834 // Should have sign out but not lock screen and feedback items if user is
835 // logged in but screen is locked.
836 LockScreen();
837 EXPECT_TRUE(GetLockedState());
838 OpenPowerButtonMenu();
839 EXPECT_TRUE(power_button_test_api_->MenuHasSignOutItem());
840 EXPECT_FALSE(power_button_test_api_->MenuHasLockScreenItem());
841 EXPECT_FALSE(power_button_test_api_->MenuHasFeedbackItem());
842 }
843
844 // Tests long-pressing the power button when the menu is open.
TEST_F(PowerButtonControllerTest,LongPressButtonWhenMenuIsOpened)845 TEST_F(PowerButtonControllerTest, LongPressButtonWhenMenuIsOpened) {
846 OpenPowerButtonMenu();
847 AdvanceClockToAvoidIgnoring();
848
849 // Long pressing the power button when menu is opened should not dismiss the
850 // menu but trigger the pre-shutdown animation instead. Menu should stay
851 // opened if releasing the button can cancel the animation.
852 PressPowerButton();
853 EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
854 ASSERT_TRUE(power_button_test_api_->TriggerPreShutdownTimeout());
855 EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running());
856 ReleasePowerButton();
857 EXPECT_FALSE(lock_state_test_api_->shutdown_timer_is_running());
858 EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
859
860 // Change focus to 'sign out'
861 PressKey(ui::VKEY_TAB);
862 EXPECT_TRUE(power_button_test_api_->GetPowerButtonMenuView()
863 ->sign_out_item_for_test()
864 ->HasFocus());
865
866 // Long press when menu is opened with focus on 'sign out' item will change
867 // the focus to 'power off' after starting the pre-shutdown animation.
868 PressPowerButton();
869 ASSERT_TRUE(power_button_test_api_->TriggerPreShutdownTimeout());
870 EXPECT_TRUE(lock_state_test_api_->shutdown_timer_is_running());
871 EXPECT_TRUE(power_button_test_api_->GetPowerButtonMenuView()
872 ->power_off_item_for_test()
873 ->HasFocus());
874 ReleasePowerButton();
875 }
876
877 // Tests that switches between laptop mode and tablet mode should dismiss the
878 // opened menu.
TEST_F(PowerButtonControllerTest,EnterOrLeaveTabletModeDismissMenu)879 TEST_F(PowerButtonControllerTest, EnterOrLeaveTabletModeDismissMenu) {
880 OpenPowerButtonMenu();
881 EnableTabletMode(true);
882 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
883
884 OpenPowerButtonMenu();
885 EnableTabletMode(false);
886 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
887 }
888
889 // Tests that screen changes to idle off will dismiss the opened menu.
TEST_F(PowerButtonControllerTest,DismissMenuWhenScreenIsIdleOff)890 TEST_F(PowerButtonControllerTest, DismissMenuWhenScreenIsIdleOff) {
891 OpenPowerButtonMenu();
892 // Mock screen idle off.
893 SendBrightnessChange(0, kUserCause);
894 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
895 }
896
897 // Tests that tapping the power button should dimiss the opened menu.
TEST_F(PowerButtonControllerTest,TappingPowerButtonWhenMenuIsOpened)898 TEST_F(PowerButtonControllerTest, TappingPowerButtonWhenMenuIsOpened) {
899 EnableTabletMode(true);
900 OpenPowerButtonMenu();
901
902 // Tapping the power button when menu is opened will dismiss the menu.
903 AdvanceClockToAvoidIgnoring();
904 PressPowerButton();
905 ReleasePowerButton();
906 SendBrightnessChange(0, kUserCause);
907 EXPECT_TRUE(power_manager_client()->backlights_forced_off());
908 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
909
910 // Long press the power button when backlights are off will show the menu.
911 PressPowerButton();
912 SendBrightnessChange(kNonZeroBrightness, kUserCause);
913 EXPECT_TRUE(power_button_test_api_->TriggerPowerButtonMenuTimeout());
914 ReleasePowerButton();
915 EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
916 // Tapping the power button will dismiss the menu.
917 AdvanceClockToAvoidIgnoring();
918 PressPowerButton();
919 ReleasePowerButton();
920 SendBrightnessChange(0, kUserCause);
921 EXPECT_TRUE(power_manager_client()->backlights_forced_off());
922 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
923 }
924
925 // Tests that suspend will dismiss the opened menu.
TEST_F(PowerButtonControllerTest,SuspendWithMenuOn)926 TEST_F(PowerButtonControllerTest, SuspendWithMenuOn) {
927 OpenPowerButtonMenu();
928 power_manager_client()->SendSuspendImminent(
929 power_manager::SuspendImminent_Reason_OTHER);
930 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
931 power_manager_client()->SendSuspendDone();
932 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
933 }
934
935 // Tests the formerly-active window state in showing power menu.
TEST_F(PowerButtonControllerTest,FormerlyActiveWindowInShowingMenu)936 TEST_F(PowerButtonControllerTest, FormerlyActiveWindowInShowingMenu) {
937 std::unique_ptr<views::Widget> widget = CreateTestWidget();
938 ASSERT_TRUE(widget->IsActive());
939
940 OpenPowerButtonMenu();
941 // The active window becomes inactive after menu is shown but it is still
942 // painted as active to avoid frame color change.
943 EXPECT_FALSE(widget->IsActive());
944 EXPECT_TRUE(widget->ShouldPaintAsActive());
945 EXPECT_TRUE(widget->non_client_view()->frame_view()->ShouldPaintAsActive());
946 EXPECT_TRUE(
947 wm::IsActiveWindow(power_button_test_api_->GetPowerButtonMenuView()
948 ->GetWidget()
949 ->GetNativeWindow()));
950 // Should reset the previous painting as active setting of the active window
951 // if dismissing the menu.
952 TapToDismissPowerButtonMenu();
953
954 // Focus may fall to the widget if it's the only remaining widget on the
955 // screen. Deactivate it to verify that it's no longer being forced to render
956 // as active.
957 widget->Deactivate();
958 EXPECT_FALSE(widget->ShouldPaintAsActive());
959
960 // A widget which is not the active widget is not affected by opening the
961 // power button menu.
962 OpenPowerButtonMenu();
963 EXPECT_FALSE(widget->ShouldPaintAsActive());
964 TapToDismissPowerButtonMenu();
965
966 // If focus didn't fall to the widget after the menu was closed, focus it.
967 widget->Activate();
968
969 // Dismiss menu should work well after the active window is closed between
970 // showing and dismissing menu.
971 OpenPowerButtonMenu();
972 widget->Close();
973 TapToDismissPowerButtonMenu();
974 }
975
976 // Tests that cursor is hidden after show the menu and should reappear if mouse
977 // moves.
TEST_F(PowerButtonControllerTest,HideCursorAfterShowMenu)978 TEST_F(PowerButtonControllerTest, HideCursorAfterShowMenu) {
979 // Cursor is hidden after show the menu.
980 ::wm::CursorManager* cursor_manager = Shell::Get()->cursor_manager();
981 EXPECT_TRUE(cursor_manager->IsCursorVisible());
982 PressPowerButton();
983 ReleasePowerButton();
984 EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
985 EXPECT_FALSE(cursor_manager->IsCursorVisible());
986
987 // Cursor reappears if mouse moves.
988 GenerateMouseMoveEvent();
989 EXPECT_TRUE(cursor_manager->IsCursorVisible());
990 }
991
992 // Tests that press VKEY_ESCAPE should dismiss the opened menu.
TEST_F(PowerButtonControllerTest,ESCDismissMenu)993 TEST_F(PowerButtonControllerTest, ESCDismissMenu) {
994 OpenPowerButtonMenu();
995
996 PressKey(ui::VKEY_VOLUME_DOWN);
997 EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
998
999 PressKey(ui::VKEY_BRIGHTNESS_UP);
1000 EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
1001
1002 PressKey(ui::VKEY_BROWSER_SEARCH);
1003 EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
1004
1005 PressKey(ui::VKEY_ESCAPE);
1006 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
1007 }
1008
1009 // Tests the navigation of the menu.
TEST_F(PowerButtonControllerTest,MenuNavigation)1010 TEST_F(PowerButtonControllerTest, MenuNavigation) {
1011 ClearLogin();
1012 Shell::Get()->UpdateAfterLoginStatusChange(LoginStatus::NOT_LOGGED_IN);
1013 OpenPowerButtonMenu();
1014 ASSERT_TRUE(power_button_test_api_->MenuHasFeedbackItem());
1015 auto* menu_view = power_button_test_api_->GetPowerButtonMenuView();
1016 PressKey(ui::VKEY_TAB);
1017 EXPECT_TRUE(menu_view->power_off_item_for_test()->HasFocus());
1018 PressKey(ui::VKEY_TAB);
1019 EXPECT_TRUE(menu_view->feedback_item_for_test()->HasFocus());
1020 TapToDismissPowerButtonMenu();
1021
1022 ClearLogin();
1023 CreateUserSessions(1);
1024 OpenPowerButtonMenu();
1025 ASSERT_TRUE(power_button_test_api_->MenuHasSignOutItem());
1026 ASSERT_TRUE(power_button_test_api_->MenuHasLockScreenItem());
1027 ASSERT_TRUE(power_button_test_api_->MenuHasFeedbackItem());
1028 menu_view = power_button_test_api_->GetPowerButtonMenuView();
1029 PressKey(ui::VKEY_TAB);
1030 EXPECT_TRUE(menu_view->power_off_item_for_test()->HasFocus());
1031
1032 PressKey(ui::VKEY_RIGHT);
1033 EXPECT_TRUE(menu_view->sign_out_item_for_test()->HasFocus());
1034
1035 PressKey(ui::VKEY_DOWN);
1036 EXPECT_TRUE(menu_view->lock_screen_item_for_test()->HasFocus());
1037
1038 PressKey(ui::VKEY_TAB);
1039 EXPECT_TRUE(menu_view->feedback_item_for_test()->HasFocus());
1040
1041 PressKey(ui::VKEY_TAB);
1042 EXPECT_TRUE(menu_view->power_off_item_for_test()->HasFocus());
1043
1044 PressKey(ui::VKEY_UP);
1045 EXPECT_TRUE(menu_view->feedback_item_for_test()->HasFocus());
1046
1047 PressKey(ui::VKEY_UP);
1048 EXPECT_TRUE(menu_view->lock_screen_item_for_test()->HasFocus());
1049
1050 PressKey(ui::VKEY_LEFT);
1051 EXPECT_TRUE(menu_view->sign_out_item_for_test()->HasFocus());
1052
1053 PressKey(ui::VKEY_UP);
1054 EXPECT_TRUE(menu_view->power_off_item_for_test()->HasFocus());
1055 }
1056
1057 // Tests that the partially shown menu will be dismissed by power button up in
1058 // tablet mode, and screen will be turned off at the same time.
TEST_F(PowerButtonControllerTest,PartiallyShownMenuInTabletMode)1059 TEST_F(PowerButtonControllerTest, PartiallyShownMenuInTabletMode) {
1060 EnableTabletMode(true);
1061
1062 // Enable animations so that we can make sure that they occur.
1063 ui::ScopedAnimationDurationScaleMode regular_animations(
1064 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
1065
1066 PressPowerButton();
1067 EXPECT_TRUE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
1068 EXPECT_TRUE(power_button_test_api_->TriggerPowerButtonMenuTimeout());
1069 EXPECT_FALSE(power_button_test_api_->PowerButtonMenuTimerIsRunning());
1070 // Power menu is in the partially shown state.
1071 EXPECT_TRUE(power_button_test_api_->IsMenuOpened());
1072 EXPECT_FALSE(power_button_test_api_->ShowMenuAnimationDone());
1073 ReleasePowerButton();
1074 EXPECT_FALSE(power_button_test_api_->ShowMenuAnimationDone());
1075 // The partially shown menu should be dismissed by power button up.
1076 EXPECT_FALSE(power_button_test_api_->IsMenuOpened());
1077 EXPECT_TRUE(power_manager_client()->backlights_forced_off());
1078 }
1079
1080 class PowerButtonControllerWithPositionTest
1081 : public PowerButtonControllerTest,
1082 public testing::WithParamInterface<PowerButtonPosition> {
1083 public:
PowerButtonControllerWithPositionTest()1084 PowerButtonControllerWithPositionTest() : power_button_position_(GetParam()) {
1085 base::DictionaryValue position_info;
1086 switch (power_button_position_) {
1087 case PowerButtonPosition::LEFT:
1088 position_info.SetString(PowerButtonController::kEdgeField,
1089 PowerButtonController::kLeftEdge);
1090 break;
1091 case PowerButtonPosition::RIGHT:
1092 position_info.SetString(PowerButtonController::kEdgeField,
1093 PowerButtonController::kRightEdge);
1094 break;
1095 case PowerButtonPosition::TOP:
1096 position_info.SetString(PowerButtonController::kEdgeField,
1097 PowerButtonController::kTopEdge);
1098 break;
1099 case PowerButtonPosition::BOTTOM:
1100 position_info.SetString(PowerButtonController::kEdgeField,
1101 PowerButtonController::kBottomEdge);
1102 break;
1103 default:
1104 return;
1105 }
1106 position_info.SetDouble(PowerButtonController::kPositionField,
1107 kPowerButtonPercentage);
1108
1109 std::string json_position_info;
1110 base::JSONWriter::Write(position_info, &json_position_info);
1111 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
1112 switches::kAshPowerButtonPosition, json_position_info);
1113 }
1114
IsLeftOrRightPosition() const1115 bool IsLeftOrRightPosition() const {
1116 return power_button_position_ == PowerButtonPosition::LEFT ||
1117 power_button_position_ == PowerButtonPosition::RIGHT;
1118 }
1119
1120 // Returns true if it is in tablet mode.
IsTabletMode() const1121 bool IsTabletMode() const {
1122 return Shell::Get()->tablet_mode_controller()->InTabletMode();
1123 }
1124
1125 // Returns true if the menu is at the center of the display.
IsMenuCentered() const1126 bool IsMenuCentered() const {
1127 return power_button_test_api_->GetMenuBoundsInScreen().CenterPoint() ==
1128 display::Screen::GetScreen()
1129 ->GetPrimaryDisplay()
1130 .bounds()
1131 .CenterPoint();
1132 }
1133
power_button_position() const1134 PowerButtonPosition power_button_position() const {
1135 return power_button_position_;
1136 }
1137
1138 private:
1139 PowerButtonPosition power_button_position_;
1140
1141 DISALLOW_COPY_AND_ASSIGN(PowerButtonControllerWithPositionTest);
1142 };
1143
1144 // TODO(crbug.com/1010194).
TEST_P(PowerButtonControllerWithPositionTest,DISABLED_MenuNextToPowerButtonInTabletMode)1145 TEST_P(PowerButtonControllerWithPositionTest,
1146 DISABLED_MenuNextToPowerButtonInTabletMode) {
1147 std::string display =
1148 std::to_string(kDisplayWidth) + "x" + std::to_string(kDisplayHeight);
1149 UpdateDisplay(display);
1150 display::test::ScopedSetInternalDisplayId set_internal(
1151 display_manager(), GetPrimaryDisplay().id());
1152
1153 ScreenOrientationControllerTestApi test_api(
1154 Shell::Get()->screen_orientation_controller());
1155 // Set the screen orientation to LANDSCAPE_PRIMARY.
1156 test_api.SetDisplayRotation(display::Display::ROTATE_0,
1157 display::Display::RotationSource::ACTIVE);
1158 EXPECT_EQ(test_api.GetCurrentOrientation(),
1159 OrientationLockType::kLandscapePrimary);
1160
1161 // Menu is set at the center of the display if it is not in tablet mode.
1162 OpenPowerButtonMenu();
1163 ASSERT_FALSE(IsTabletMode());
1164 EXPECT_TRUE(IsMenuCentered());
1165 TapToDismissPowerButtonMenu();
1166
1167 int animation_transform = PowerButtonMenuView::kMenuViewTransformDistanceDp;
1168 EnableTabletMode(true);
1169 EXPECT_TRUE(IsTabletMode());
1170 OpenPowerButtonMenu();
1171 EXPECT_FALSE(IsMenuCentered());
1172 if (power_button_position() == PowerButtonPosition::LEFT) {
1173 EXPECT_EQ(animation_transform,
1174 power_button_test_api_->GetMenuBoundsInScreen().x());
1175 } else if (power_button_position() == PowerButtonPosition::RIGHT) {
1176 EXPECT_EQ(animation_transform,
1177 kDisplayWidth -
1178 power_button_test_api_->GetMenuBoundsInScreen().right());
1179 } else if (power_button_position() == PowerButtonPosition::TOP) {
1180 EXPECT_EQ(animation_transform,
1181 power_button_test_api_->GetMenuBoundsInScreen().y());
1182 } else if (power_button_position() == PowerButtonPosition::BOTTOM) {
1183 EXPECT_EQ(animation_transform,
1184 kDisplayHeight -
1185 power_button_test_api_->GetMenuBoundsInScreen().bottom());
1186 }
1187
1188 // Rotate the screen by 270 degree.
1189 test_api.SetDisplayRotation(display::Display::ROTATE_270,
1190 display::Display::RotationSource::ACTIVE);
1191 EXPECT_EQ(test_api.GetCurrentOrientation(),
1192 OrientationLockType::kPortraitPrimary);
1193 EXPECT_FALSE(IsMenuCentered());
1194 if (power_button_position() == PowerButtonPosition::LEFT) {
1195 EXPECT_EQ(animation_transform,
1196 power_button_test_api_->GetMenuBoundsInScreen().y());
1197 } else if (power_button_position() == PowerButtonPosition::RIGHT) {
1198 EXPECT_EQ(animation_transform,
1199 kDisplayWidth -
1200 power_button_test_api_->GetMenuBoundsInScreen().bottom());
1201 } else if (power_button_position() == PowerButtonPosition::TOP) {
1202 EXPECT_EQ(animation_transform,
1203 kDisplayHeight -
1204 power_button_test_api_->GetMenuBoundsInScreen().right());
1205 } else if (power_button_position() == PowerButtonPosition::BOTTOM) {
1206 EXPECT_EQ(animation_transform,
1207 power_button_test_api_->GetMenuBoundsInScreen().x());
1208 }
1209
1210 // Rotate the screen by 180 degree.
1211 test_api.SetDisplayRotation(display::Display::ROTATE_180,
1212 display::Display::RotationSource::ACTIVE);
1213 EXPECT_EQ(test_api.GetCurrentOrientation(),
1214 OrientationLockType::kLandscapeSecondary);
1215 EXPECT_FALSE(IsMenuCentered());
1216 if (power_button_position() == PowerButtonPosition::LEFT) {
1217 EXPECT_EQ(animation_transform,
1218 kDisplayWidth -
1219 power_button_test_api_->GetMenuBoundsInScreen().right());
1220 } else if (power_button_position() == PowerButtonPosition::RIGHT) {
1221 EXPECT_EQ(animation_transform,
1222 power_button_test_api_->GetMenuBoundsInScreen().x());
1223 } else if (power_button_position() == PowerButtonPosition::TOP) {
1224 EXPECT_EQ(animation_transform,
1225 kDisplayHeight -
1226 power_button_test_api_->GetMenuBoundsInScreen().bottom());
1227 } else if (power_button_position() == PowerButtonPosition::BOTTOM) {
1228 EXPECT_EQ(animation_transform,
1229 power_button_test_api_->GetMenuBoundsInScreen().y());
1230 }
1231
1232 // Rotate the screen by 90 degree.
1233 test_api.SetDisplayRotation(display::Display::ROTATE_90,
1234 display::Display::RotationSource::ACTIVE);
1235 EXPECT_EQ(test_api.GetCurrentOrientation(),
1236 OrientationLockType::kPortraitSecondary);
1237 EXPECT_FALSE(IsMenuCentered());
1238 if (power_button_position() == PowerButtonPosition::LEFT) {
1239 EXPECT_EQ(animation_transform,
1240 kDisplayWidth -
1241 power_button_test_api_->GetMenuBoundsInScreen().bottom());
1242 } else if (power_button_position() == PowerButtonPosition::RIGHT) {
1243 EXPECT_EQ(animation_transform,
1244 power_button_test_api_->GetMenuBoundsInScreen().y());
1245 } else if (power_button_position() == PowerButtonPosition::TOP) {
1246 EXPECT_EQ(animation_transform,
1247 power_button_test_api_->GetMenuBoundsInScreen().x());
1248 } else if (power_button_position() == PowerButtonPosition::BOTTOM) {
1249 EXPECT_EQ(animation_transform,
1250 kDisplayHeight -
1251 power_button_test_api_->GetMenuBoundsInScreen().right());
1252 }
1253 }
1254
1255 // Tests that the menu is always shown at the percentage of position when
1256 // display has different scale factors.
TEST_P(PowerButtonControllerWithPositionTest,MenuShownAtPercentageOfPosition)1257 TEST_P(PowerButtonControllerWithPositionTest, MenuShownAtPercentageOfPosition) {
1258 const int scale_factor = 2;
1259 std::string display = "8000x2400*" + std::to_string(scale_factor);
1260 UpdateDisplay(display);
1261 int64_t primary_id = GetPrimaryDisplay().id();
1262 display::test::ScopedSetInternalDisplayId set_internal(display_manager(),
1263 primary_id);
1264 ASSERT_EQ(scale_factor, GetPrimaryDisplay().device_scale_factor());
1265
1266 EnableTabletMode(true);
1267 OpenPowerButtonMenu();
1268 EXPECT_FALSE(IsMenuCentered());
1269 gfx::Point menu_center_point =
1270 power_button_test_api_->GetMenuBoundsInScreen().CenterPoint();
1271 gfx::Rect display_bounds = GetPrimaryDisplay().bounds();
1272 int original_width = display_bounds.width();
1273 int original_height = display_bounds.height();
1274 if (IsLeftOrRightPosition()) {
1275 EXPECT_EQ(menu_center_point.y(), static_cast<int>(display_bounds.height() *
1276 kPowerButtonPercentage));
1277 } else {
1278 EXPECT_EQ(menu_center_point.x(), static_cast<int>(display_bounds.width() *
1279 kPowerButtonPercentage));
1280 }
1281 TapToDismissPowerButtonMenu();
1282
1283 display_manager()->UpdateZoomFactor(primary_id, 1.f / scale_factor);
1284 ASSERT_EQ(1.0f, GetPrimaryDisplay().device_scale_factor());
1285 display_bounds = GetPrimaryDisplay().bounds();
1286 int scale_up_width = display_bounds.width();
1287 int scale_up_height = display_bounds.height();
1288 EXPECT_EQ(scale_up_width, original_width * scale_factor);
1289 EXPECT_EQ(scale_up_height, original_height * scale_factor);
1290 OpenPowerButtonMenu();
1291 menu_center_point =
1292 power_button_test_api_->GetMenuBoundsInScreen().CenterPoint();
1293 // Menu is still at the kPowerButtonPercentage position after scale up screen.
1294 if (IsLeftOrRightPosition()) {
1295 EXPECT_EQ(menu_center_point.y(), static_cast<int>(display_bounds.height() *
1296 kPowerButtonPercentage));
1297 } else {
1298 EXPECT_EQ(menu_center_point.x(), static_cast<int>(display_bounds.width() *
1299 kPowerButtonPercentage));
1300 }
1301 }
1302
TEST_P(PowerButtonControllerWithPositionTest,AdjustMenuShownForDisplaySize)1303 TEST_P(PowerButtonControllerWithPositionTest, AdjustMenuShownForDisplaySize) {
1304 OpenPowerButtonMenu();
1305 gfx::Rect menu_bounds = power_button_test_api_->GetMenuBoundsInScreen();
1306 TapToDismissPowerButtonMenu();
1307
1308 // (1 - kPowerButtonPercentage) * display_height < 0.5 * menu_height makes
1309 // sure menu will be cut off by display when button is on LEFT/RIGHT, and (1 -
1310 // kPowerButtonPercentage) * display_width < 0.5 * menu_width makes sure menu
1311 // will be cut off by display when button is on TOP/BOTTOM.
1312 int display_width =
1313 0.5 / (1.0f - kPowerButtonPercentage) * menu_bounds.width() - 5;
1314 int display_height =
1315 0.5 / (1.0f - kPowerButtonPercentage) * menu_bounds.height() - 5;
1316 std::string display =
1317 std::to_string(display_width) + "x" + std::to_string(display_height);
1318 UpdateDisplay(display);
1319 display::test::ScopedSetInternalDisplayId set_internal(
1320 display_manager(), GetPrimaryDisplay().id());
1321
1322 ScreenOrientationControllerTestApi test_api(
1323 Shell::Get()->screen_orientation_controller());
1324 // Set the screen orientation to LANDSCAPE_PRIMARY.
1325 test_api.SetDisplayRotation(display::Display::ROTATE_0,
1326 display::Display::RotationSource::ACTIVE);
1327 EXPECT_EQ(test_api.GetCurrentOrientation(),
1328 OrientationLockType::kLandscapePrimary);
1329 EnableTabletMode(true);
1330 OpenPowerButtonMenu();
1331 // Menu's bounds is always inside the display.
1332 EXPECT_TRUE(GetPrimaryDisplay().bounds().Contains(
1333 power_button_test_api_->GetMenuBoundsInScreen()));
1334
1335 // Rotate the screen by 270 degrees.
1336 test_api.SetDisplayRotation(display::Display::ROTATE_270,
1337 display::Display::RotationSource::ACTIVE);
1338 EXPECT_EQ(test_api.GetCurrentOrientation(),
1339 OrientationLockType::kPortraitPrimary);
1340 EXPECT_TRUE(GetPrimaryDisplay().bounds().Contains(
1341 power_button_test_api_->GetMenuBoundsInScreen()));
1342
1343 // Rotate the screen by 180 degrees.
1344 test_api.SetDisplayRotation(display::Display::ROTATE_180,
1345 display::Display::RotationSource::ACTIVE);
1346 EXPECT_EQ(test_api.GetCurrentOrientation(),
1347 OrientationLockType::kLandscapeSecondary);
1348 EXPECT_TRUE(GetPrimaryDisplay().bounds().Contains(
1349 power_button_test_api_->GetMenuBoundsInScreen()));
1350
1351 // Rotate the screen by 90 degrees.
1352 test_api.SetDisplayRotation(display::Display::ROTATE_90,
1353 display::Display::RotationSource::ACTIVE);
1354 EXPECT_EQ(test_api.GetCurrentOrientation(),
1355 OrientationLockType::kPortraitSecondary);
1356 EXPECT_TRUE(GetPrimaryDisplay().bounds().Contains(
1357 power_button_test_api_->GetMenuBoundsInScreen()));
1358 }
1359
1360 // Tests that a power button press before the menu is fully shown will not
1361 // create a new menu.
TEST_F(PowerButtonControllerTest,LegacyPowerButtonIgnoreExtraPress)1362 TEST_F(PowerButtonControllerTest, LegacyPowerButtonIgnoreExtraPress) {
1363 Initialize(ButtonType::LEGACY, LoginStatus::USER);
1364
1365 // Enable animations so that we can make sure that they occur.
1366 ui::ScopedAnimationDurationScaleMode regular_animations(
1367 ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
1368 PressPowerButton();
1369 // Power menu is in the partially shown state.
1370 ASSERT_TRUE(power_button_test_api_->IsMenuOpened());
1371 ASSERT_FALSE(power_button_test_api_->ShowMenuAnimationDone());
1372 PowerButtonMenuView* menu_view_before =
1373 power_button_test_api_->GetPowerButtonMenuView();
1374 // Press power button again and make sure new PowerButtonMenuView is not
1375 // created. This makes sure that we do not create a new menu while we are in
1376 // the process of creating one for an old power button press.
1377 PressPowerButton();
1378 EXPECT_EQ(menu_view_before, power_button_test_api_->GetPowerButtonMenuView());
1379 // This is needed to simulate the shutdown sound having been played,
1380 // which blocks the shutdown timer.
1381 // Make sure that the second press did not trigger a shutdown.
1382 EXPECT_FALSE(lock_state_test_api_->real_shutdown_timer_is_running());
1383 // Make sure that power menu is still in partially shown state.
1384 ASSERT_TRUE(power_button_test_api_->IsMenuOpened());
1385 ASSERT_FALSE(power_button_test_api_->ShowMenuAnimationDone());
1386 }
1387
1388 INSTANTIATE_TEST_SUITE_P(AshPowerButtonPosition,
1389 PowerButtonControllerWithPositionTest,
1390 testing::Values(PowerButtonPosition::LEFT,
1391 PowerButtonPosition::RIGHT,
1392 PowerButtonPosition::TOP,
1393 PowerButtonPosition::BOTTOM));
1394
1395 } // namespace ash
1396