1 // Copyright 2018 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/tablet_mode/tablet_mode_controller_test_api.h"
6 
7 #include "ash/public/cpp/ash_switches.h"
8 #include "ash/shell.h"
9 #include "base/command_line.h"
10 #include "base/numerics/math_constants.h"
11 #include "base/run_loop.h"
12 #include "base/time/default_tick_clock.h"
13 #include "ui/events/devices/device_data_manager_test_api.h"
14 #include "ui/events/devices/input_device.h"
15 
16 namespace ash {
17 
18 namespace {
19 
IsTabletModeControllerInitialized()20 bool IsTabletModeControllerInitialized() {
21   return base::CommandLine::ForCurrentProcess()->HasSwitch(
22       switches::kAshEnableTabletMode);
23 }
24 
25 }  // namespace
26 
TabletModeControllerTestApi()27 TabletModeControllerTestApi::TabletModeControllerTestApi()
28     : tablet_mode_controller_(Shell::Get()->tablet_mode_controller()) {
29   tablet_mode_controller_->OnDeviceListsComplete();
30 }
31 
32 TabletModeControllerTestApi::~TabletModeControllerTestApi() = default;
33 
EnterTabletMode()34 void TabletModeControllerTestApi::EnterTabletMode() {
35   tablet_mode_controller_->SetEnabledForTest(true);
36 }
37 
LeaveTabletMode()38 void TabletModeControllerTestApi::LeaveTabletMode() {
39   tablet_mode_controller_->SetEnabledForTest(false);
40 }
41 
AttachExternalMouse()42 void TabletModeControllerTestApi::AttachExternalMouse() {
43   // Calling RunUntilIdle() here is necessary before setting the mouse devices
44   // to prevent the callback from evdev thread to overwrite whatever we set
45   // here below. See `InputDeviceFactoryEvdevProxy::OnStartupScanComplete()`.
46   base::RunLoop().RunUntilIdle();
47   ui::DeviceDataManagerTestApi().SetMouseDevices(
48       {ui::InputDevice(3, ui::InputDeviceType::INPUT_DEVICE_USB, "mouse")});
49   if (!IsTabletModeControllerInitialized()) {
50     // The controller is not observing the DeviceDataManager, hence we need to
51     // notify it ourselves.
52     tablet_mode_controller_->OnInputDeviceConfigurationChanged(
53         ui::InputDeviceEventObserver::kMouse);
54   }
55 }
56 
AttachExternalTouchpad()57 void TabletModeControllerTestApi::AttachExternalTouchpad() {
58   // Similar to |AttachExternalMouse|.
59   base::RunLoop().RunUntilIdle();
60   ui::DeviceDataManagerTestApi().SetTouchpadDevices(
61       {ui::InputDevice(4, ui::InputDeviceType::INPUT_DEVICE_USB, "touchpad")});
62   if (!IsTabletModeControllerInitialized()) {
63     tablet_mode_controller_->OnInputDeviceConfigurationChanged(
64         ui::InputDeviceEventObserver::kTouchpad);
65   }
66 }
67 
DetachAllMice()68 void TabletModeControllerTestApi::DetachAllMice() {
69   // See comment in |AttachExternalMouse| for why we need to call
70   // |base::RunLoop::RunUntilIdle|.
71   base::RunLoop().RunUntilIdle();
72   ui::DeviceDataManagerTestApi().SetMouseDevices({});
73   if (!IsTabletModeControllerInitialized()) {
74     // The controller is not observing the DeviceDataManager, hence we need to
75     // notify it ourselves.
76     tablet_mode_controller_->OnInputDeviceConfigurationChanged(
77         ui::InputDeviceEventObserver::kMouse);
78   }
79 }
80 
DetachAllTouchpads()81 void TabletModeControllerTestApi::DetachAllTouchpads() {
82   // Similar to |DetachAllMice|.
83   base::RunLoop().RunUntilIdle();
84   ui::DeviceDataManagerTestApi().SetTouchpadDevices({});
85   if (!IsTabletModeControllerInitialized()) {
86     tablet_mode_controller_->OnInputDeviceConfigurationChanged(
87         ui::InputDeviceEventObserver::kTouchpad);
88   }
89 }
90 
TriggerLidUpdate(const gfx::Vector3dF & lid)91 void TabletModeControllerTestApi::TriggerLidUpdate(const gfx::Vector3dF& lid) {
92   scoped_refptr<AccelerometerUpdate> update(new AccelerometerUpdate());
93   update->Set(ACCELEROMETER_SOURCE_SCREEN, lid.x(), lid.y(), lid.z());
94   tablet_mode_controller_->OnAccelerometerUpdated(update);
95 }
96 
TriggerBaseAndLidUpdate(const gfx::Vector3dF & base,const gfx::Vector3dF & lid)97 void TabletModeControllerTestApi::TriggerBaseAndLidUpdate(
98     const gfx::Vector3dF& base,
99     const gfx::Vector3dF& lid) {
100   scoped_refptr<AccelerometerUpdate> update(new AccelerometerUpdate());
101   update->Set(ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD, base.x(), base.y(),
102               base.z());
103   update->Set(ACCELEROMETER_SOURCE_SCREEN, lid.x(), lid.y(), lid.z());
104   tablet_mode_controller_->OnAccelerometerUpdated(update);
105 }
106 
OpenLidToAngle(float degrees)107 void TabletModeControllerTestApi::OpenLidToAngle(float degrees) {
108   DCHECK(degrees >= 0.0f);
109   DCHECK(degrees <= 360.0f);
110 
111   float radians = degrees * kDegreesToRadians;
112   gfx::Vector3dF base_vector(0.0f, -base::kMeanGravityFloat, 0.0f);
113   gfx::Vector3dF lid_vector(0.0f, base::kMeanGravityFloat * cos(radians),
114                             base::kMeanGravityFloat * sin(radians));
115   TriggerBaseAndLidUpdate(base_vector, lid_vector);
116 }
117 
HoldDeviceVertical()118 void TabletModeControllerTestApi::HoldDeviceVertical() {
119   gfx::Vector3dF base_vector(9.8f, 0.0f, 0.0f);
120   gfx::Vector3dF lid_vector(9.8f, 0.0f, 0.0f);
121   TriggerBaseAndLidUpdate(base_vector, lid_vector);
122 }
123 
OpenLid()124 void TabletModeControllerTestApi::OpenLid() {
125   tablet_mode_controller_->LidEventReceived(
126       chromeos::PowerManagerClient::LidState::OPEN, tick_clock()->NowTicks());
127 }
128 
CloseLid()129 void TabletModeControllerTestApi::CloseLid() {
130   tablet_mode_controller_->LidEventReceived(
131       chromeos::PowerManagerClient::LidState::CLOSED, tick_clock()->NowTicks());
132 }
133 
SetTabletMode(bool on)134 void TabletModeControllerTestApi::SetTabletMode(bool on) {
135   tablet_mode_controller_->TabletModeEventReceived(
136       on ? chromeos::PowerManagerClient::TabletMode::ON
137          : chromeos::PowerManagerClient::TabletMode::OFF,
138       tick_clock()->NowTicks());
139 }
140 
SuspendImminent()141 void TabletModeControllerTestApi::SuspendImminent() {
142   tablet_mode_controller_->SuspendImminent(
143       power_manager::SuspendImminent::Reason::SuspendImminent_Reason_IDLE);
144 }
145 
SuspendDone(base::TimeDelta sleep_duration)146 void TabletModeControllerTestApi::SuspendDone(base::TimeDelta sleep_duration) {
147   tablet_mode_controller_->SuspendDone(sleep_duration);
148 }
149 
150 }  // namespace ash
151