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