1// Copyright (c) 2012 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/wm/power_button_controller.h"
6
7#include "ash/ash_switches.h"
8#include "ash/session/session_state_delegate.h"
9#include "ash/shell.h"
10#include "ash/shell_window_ids.h"
11#include "ash/wm/lock_state_controller.h"
12#include "ash/wm/maximize_mode/maximize_mode_controller.h"
13#include "ash/wm/session_state_animator.h"
14#include "base/command_line.h"
15#include "ui/aura/window_event_dispatcher.h"
16#include "ui/display/types/display_snapshot.h"
17#include "ui/events/event_handler.h"
18#include "ui/wm/core/compound_event_filter.h"
19
20namespace ash {
21
22PowerButtonController::PowerButtonController(
23    LockStateController* controller)
24    : power_button_down_(false),
25      lock_button_down_(false),
26      volume_down_pressed_(false),
27      brightness_is_zero_(false),
28      internal_display_off_and_external_display_on_(false),
29      has_legacy_power_button_(
30          CommandLine::ForCurrentProcess()->HasSwitch(
31              switches::kAuraLegacyPowerButton)),
32      enable_quick_lock_(CommandLine::ForCurrentProcess()->HasSwitch(
33          switches::kAshEnablePowerButtonQuickLock)),
34      controller_(controller) {
35#if defined(OS_CHROMEOS)
36  Shell::GetInstance()->display_configurator()->AddObserver(this);
37#endif
38  Shell::GetInstance()->PrependPreTargetHandler(this);
39}
40
41PowerButtonController::~PowerButtonController() {
42#if defined(OS_CHROMEOS)
43  Shell::GetInstance()->display_configurator()->RemoveObserver(this);
44#endif
45  Shell::GetInstance()->RemovePreTargetHandler(this);
46}
47
48void PowerButtonController::OnScreenBrightnessChanged(double percent) {
49  brightness_is_zero_ = percent <= 0.001;
50}
51
52void PowerButtonController::OnPowerButtonEvent(
53    bool down, const base::TimeTicks& timestamp) {
54  power_button_down_ = down;
55
56  if (controller_->ShutdownRequested())
57    return;
58
59  // Avoid starting the lock/shutdown sequence if the power button is pressed
60  // while the screen is off (http://crbug.com/128451), unless an external
61  // display is still on (http://crosbug.com/p/24912).
62  if (brightness_is_zero_ && !internal_display_off_and_external_display_on_)
63    return;
64
65  if (volume_down_pressed_ && down &&
66      Shell::GetInstance()->maximize_mode_controller()->
67        IsMaximizeModeWindowManagerEnabled()) {
68    Shell::GetInstance()->accelerator_controller()->PerformAction(
69        ash::TAKE_SCREENSHOT, ui::Accelerator());
70    return;
71  }
72
73  const SessionStateDelegate* session_state_delegate =
74      Shell::GetInstance()->session_state_delegate();
75  if (has_legacy_power_button_) {
76    // If power button releases won't get reported correctly because we're not
77    // running on official hardware, just lock the screen or shut down
78    // immediately.
79    if (down) {
80      if (session_state_delegate->CanLockScreen() &&
81          !session_state_delegate->IsScreenLocked() &&
82          !controller_->LockRequested()) {
83        controller_->StartLockAnimationAndLockImmediately(false);
84      } else {
85        controller_->RequestShutdown();
86      }
87    }
88  } else {  // !has_legacy_power_button_
89    if (down) {
90      // If we already have a pending request to lock the screen, wait.
91      if (controller_->LockRequested())
92        return;
93
94      if (session_state_delegate->CanLockScreen() &&
95          !session_state_delegate->IsScreenLocked()) {
96        if (Shell::GetInstance()->maximize_mode_controller()->
97            IsMaximizeModeWindowManagerEnabled() && enable_quick_lock_)
98          controller_->StartLockAnimationAndLockImmediately(true);
99        else
100          controller_->StartLockAnimation(true);
101      } else {
102        controller_->StartShutdownAnimation();
103      }
104    } else {  // Button is up.
105      if (controller_->CanCancelLockAnimation())
106        controller_->CancelLockAnimation();
107      else if (controller_->CanCancelShutdownAnimation())
108        controller_->CancelShutdownAnimation();
109    }
110  }
111}
112
113void PowerButtonController::OnLockButtonEvent(
114    bool down, const base::TimeTicks& timestamp) {
115  lock_button_down_ = down;
116
117  const SessionStateDelegate* session_state_delegate =
118      Shell::GetInstance()->session_state_delegate();
119  if (!session_state_delegate->CanLockScreen() ||
120      session_state_delegate->IsScreenLocked() ||
121      controller_->LockRequested() ||
122      controller_->ShutdownRequested()) {
123    return;
124  }
125
126  // Give the power button precedence over the lock button.
127  if (power_button_down_)
128    return;
129
130  if (down)
131    controller_->StartLockAnimation(false);
132  else
133    controller_->CancelLockAnimation();
134}
135
136void PowerButtonController::OnKeyEvent(ui::KeyEvent* event) {
137  if (event->key_code() == ui::VKEY_VOLUME_DOWN) {
138    volume_down_pressed_ = event->type() == ui::ET_KEY_PRESSED ||
139                           event->type() == ui::ET_TRANSLATED_KEY_PRESS;
140  }
141}
142
143#if defined(OS_CHROMEOS)
144void PowerButtonController::OnDisplayModeChanged(
145    const ui::DisplayConfigurator::DisplayStateList& display_states) {
146  bool internal_display_off = false;
147  bool external_display_on = false;
148  for (size_t i = 0; i < display_states.size(); ++i) {
149    const ui::DisplayConfigurator::DisplayState& state = display_states[i];
150    if (state.display->type() == ui::DISPLAY_CONNECTION_TYPE_INTERNAL) {
151      if (!state.display->current_mode())
152        internal_display_off = true;
153    } else if (state.display->current_mode()) {
154      external_display_on = true;
155    }
156  }
157  internal_display_off_and_external_display_on_ =
158      internal_display_off && external_display_on;
159}
160#endif
161
162}  // namespace ash
163