Index: ash/system/chromeos/power/tablet_power_button_controller.cc |
diff --git a/ash/system/chromeos/power/tablet_power_button_controller.cc b/ash/system/chromeos/power/tablet_power_button_controller.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a07475764a9c034cf8bb6ade5993e81a36a0dd75 |
--- /dev/null |
+++ b/ash/system/chromeos/power/tablet_power_button_controller.cc |
@@ -0,0 +1,216 @@ |
+// Copyright 2016 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "ash/system/chromeos/power/tablet_power_button_controller.h" |
+ |
+#include "ash/common/session/session_state_delegate.h" |
+#include "ash/common/wm/maximize_mode/maximize_mode_controller.h" |
+#include "ash/common/wm_shell.h" |
+#include "ash/shell.h" |
+#include "ash/wm/lock_state_controller.h" |
+#include "chromeos/dbus/dbus_thread_manager.h" |
+#include "ui/events/devices/input_device_manager.h" |
+#include "ui/events/devices/stylus_state.h" |
+#include "ui/events/event.h" |
+ |
+namespace ash { |
+ |
+namespace { |
+ |
+// Amount of time the power button must be held to start the pre-shutdown |
+// animation when in tablet mode. |
+constexpr int kShutdownTimeoutMs = 1000; |
+ |
+// Amount of time since last SuspendDone() that power button event needs to be |
+// ignored. |
+constexpr int kWaitSuspendDoneDurationMs = 2000; |
Daniel Erat
2016/11/10 22:48:55
nit: kIgnorePowerButtonAfterResumeMs?
Qiang(Joe) Xu
2016/11/11 04:39:22
Done.
|
+ |
+TabletPowerButtonController* instance = nullptr; |
+ |
+// Returns true if device is a convertible/tablet device or has |
+// kAshEnableTouchViewTesting in test, otherwise false. |
+bool IsTabletModeSupported() { |
+ MaximizeModeController* maximize_mode_controller = |
+ WmShell::Get()->maximize_mode_controller(); |
+ return maximize_mode_controller && |
+ maximize_mode_controller->CanEnterMaximizeMode(); |
+} |
+ |
+// Returns true if device is currently in tablet/maximize mode, otherwise false. |
+bool IsTabletModeActive() { |
+ MaximizeModeController* maximize_mode_controller = |
+ WmShell::Get()->maximize_mode_controller(); |
+ return maximize_mode_controller && |
+ maximize_mode_controller->IsMaximizeModeWindowManagerEnabled(); |
+} |
+ |
+} // namespace |
+ |
+TabletPowerButtonController::TestApi::TestApi( |
+ TabletPowerButtonController* controller) |
+ : controller_(controller) {} |
+ |
+TabletPowerButtonController::TestApi::~TestApi() {} |
+ |
+bool TabletPowerButtonController::TestApi::ShutdownTimerIsRunning() const { |
+ return controller_->shutdown_timer_.IsRunning(); |
+} |
+ |
+void TabletPowerButtonController::TestApi::TriggerShutdownTimeout() { |
+ DCHECK(ShutdownTimerIsRunning()); |
Daniel Erat
2016/11/10 22:48:54
how about making this method return false if the t
Qiang(Joe) Xu
2016/11/11 04:39:22
EXPECT_FALSE(TriggerShutdownTimeout) can represent
|
+ controller_->OnShutdownTimeout(); |
+ controller_->shutdown_timer_.Stop(); |
+} |
+ |
+// static |
+TabletPowerButtonController* TabletPowerButtonController::GetInstance() { |
+ DCHECK(instance); |
+ return instance; |
+} |
+ |
+TabletPowerButtonController::TabletPowerButtonController( |
+ LockStateController* controller) |
+ : controller_(controller) { |
+ DCHECK(!instance); |
+ instance = this; |
+ |
+ chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver( |
+ this); |
+ ui::InputDeviceManager::GetInstance()->AddObserver(this); |
+ Shell::GetInstance()->PrependPreTargetHandler(this); |
+ GetInitialBacklightsForcedOff(); |
+} |
+ |
+TabletPowerButtonController::~TabletPowerButtonController() { |
+ Shell::GetInstance()->RemovePreTargetHandler(this); |
+ ui::InputDeviceManager::GetInstance()->RemoveObserver(this); |
+ chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver( |
+ this); |
+ |
+ DCHECK_EQ(instance, this); |
+ instance = nullptr; |
+} |
+ |
+bool TabletPowerButtonController::ShouldHandlePowerButtonEvents() const { |
+ return IsTabletModeSupported(); |
+} |
+ |
+void TabletPowerButtonController::OnPowerButtonEvent( |
+ bool down, |
+ const base::TimeTicks& timestamp) { |
+ // When pressing power button causing SuspendDone, chrome side will first |
Daniel Erat
2016/11/10 22:48:55
how about this?
// When the system resumes in res
Qiang(Joe) Xu
2016/11/11 04:39:22
It is much better. Thanks!
|
+ // receive SuspendDone signal and then power button events. The resumed |
+ // brightness could make chrome think it is pressed on brightness-on-state, |
+ // but actually it is pressed on suspended-state (brightness-off-state). |
+ if (!last_resume_time_.is_null() && |
+ timestamp - last_resume_time_ <= |
+ base::TimeDelta::FromMilliseconds(kWaitSuspendDoneDurationMs)) { |
+ return; |
+ } |
+ |
+ if (down) { |
+ screen_off_when_power_button_down_ = brightness_level_is_zero_; |
+ SetBacklightsForcedOff(false); |
+ StartShutdownTimer(); |
+ } else { |
+ if (shutdown_timer_.IsRunning()) { |
+ shutdown_timer_.Stop(); |
+ if (!screen_off_when_power_button_down_) { |
+ SetBacklightsForcedOff(true); |
+ LockScreenIfRequired(); |
+ } |
+ } |
+ screen_off_when_power_button_down_ = false; |
+ |
+ // When power button is released, cancel shutdown animation whenever it is |
+ // still cancellable. |
+ if (controller_->CanCancelShutdownAnimation()) |
+ controller_->CancelShutdownAnimation(); |
+ } |
+} |
+ |
+void TabletPowerButtonController::PowerManagerRestarted() { |
+ chromeos::DBusThreadManager::Get() |
+ ->GetPowerManagerClient() |
+ ->SetBacklightsForcedOff(backlights_forced_off_); |
+} |
+ |
+void TabletPowerButtonController::BrightnessChanged(int level, |
+ bool user_initiated) { |
+ brightness_level_is_zero_ = level == 0; |
+} |
+ |
+void TabletPowerButtonController::SuspendDone( |
+ const base::TimeDelta& sleep_duration) { |
+ last_resume_time_ = base::TimeTicks::Now(); |
Daniel Erat
2016/11/10 22:48:54
i'd suggest using base::TickClock instead so you c
Qiang(Joe) Xu
2016/11/11 04:39:22
Done.
|
+} |
+ |
+void TabletPowerButtonController::OnKeyEvent(ui::KeyEvent* event) { |
+ if (!IsTabletModeActive() && backlights_forced_off_) |
+ SetBacklightsForcedOff(false); |
+} |
+ |
+void TabletPowerButtonController::OnMouseEvent(ui::MouseEvent* event) { |
+ ui::EventPointerType pointer_type = event->pointer_details().pointer_type; |
+ if (pointer_type != ui::EventPointerType::POINTER_TYPE_MOUSE && |
+ pointer_type != ui::EventPointerType::POINTER_TYPE_TOUCH) { |
+ return; |
+ } |
+ |
+ if (!IsTabletModeActive() && backlights_forced_off_) |
+ SetBacklightsForcedOff(false); |
+} |
+ |
+void TabletPowerButtonController::OnStylusStateChanged(ui::StylusState state) { |
+ if (IsTabletModeSupported() && state == ui::StylusState::REMOVED && |
+ backlights_forced_off_) { |
+ SetBacklightsForcedOff(false); |
+ } |
+} |
+ |
+void TabletPowerButtonController::SetBacklightsForcedOff(bool forced_off) { |
+ if (backlights_forced_off_ == forced_off) |
+ return; |
+ |
+ chromeos::DBusThreadManager::Get() |
+ ->GetPowerManagerClient() |
+ ->SetBacklightsForcedOff(forced_off); |
+ backlights_forced_off_ = forced_off; |
+} |
+ |
+void TabletPowerButtonController::GetInitialBacklightsForcedOff() { |
+ chromeos::DBusThreadManager::Get() |
+ ->GetPowerManagerClient() |
+ ->GetBacklightsForcedOff(base::Bind( |
+ &TabletPowerButtonController::OnGotInitialBacklightsForcedOff, |
+ base::Unretained(this))); |
+} |
+ |
+void TabletPowerButtonController::OnGotInitialBacklightsForcedOff( |
+ bool is_forced_off) { |
+ backlights_forced_off_ = is_forced_off; |
+} |
+ |
+void TabletPowerButtonController::StartShutdownTimer() { |
+ shutdown_timer_.Start(FROM_HERE, |
+ base::TimeDelta::FromMilliseconds(kShutdownTimeoutMs), |
+ this, &TabletPowerButtonController::OnShutdownTimeout); |
+} |
+ |
+void TabletPowerButtonController::OnShutdownTimeout() { |
+ controller_->StartShutdownAnimation(); |
+} |
+ |
+void TabletPowerButtonController::LockScreenIfRequired() { |
+ SessionStateDelegate* session_state_delegate = |
+ WmShell::Get()->GetSessionStateDelegate(); |
+ if (session_state_delegate->ShouldLockScreenAutomatically() && |
+ session_state_delegate->CanLockScreen() && |
+ !session_state_delegate->IsUserSessionBlocked() && |
+ !controller_->LockRequested()) { |
+ session_state_delegate->LockScreen(); |
+ } |
+} |
+ |
+} // namespace ash |