1 // Copyright 2014 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.
5 #include "athena/screen/public/screen_manager.h"
6 #include "athena/system/orientation_controller.h"
8 #include "base/file_util.h"
9 #include "base/files/file_path_watcher.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/task_runner.h"
17 // Path of the socket which the sensor daemon creates.
18 const char kSocketPath
[] = "/dev/sensors/orientation";
20 // Threshold after which to rotate in a given direction.
21 const int kGravityThreshold
= 6.0f
;
23 // Minimum delay before triggering another orientation change.
24 const int kOrientationChangeDelayNS
= 500000000;
32 // A sensor event from the device.
33 struct DeviceSensorEvent
{
34 // The type of event from the SensorType enum above.
37 // The time in nanoseconds at which the event happened.
41 // Accelerometer X,Y,Z values in SI units (m/s^2) including gravity.
42 // The orientation is described at
43 // http://www.html5rocks.com/en/tutorials/device/orientation/.
46 // Ambient (room) temperature in degrees Celcius.
49 // Proximity sensor distance in centimeters.
52 // Ambient light level in SI lux units.
59 OrientationController::OrientationController()
60 : DeviceSocketListener(kSocketPath
, sizeof(DeviceSensorEvent
)),
61 last_orientation_change_time_(0),
63 CHECK(base::MessageLoopForUI::current());
64 ui_task_runner_
= base::MessageLoopForUI::current()->task_runner();
67 void OrientationController::InitWith(
68 scoped_refptr
<base::TaskRunner
> file_task_runner
) {
69 file_task_runner_
= file_task_runner
;
70 file_task_runner
->PostTask(
72 base::Bind(&OrientationController::WatchForSocketPathOnFILE
, this));
75 OrientationController::~OrientationController() {
78 void OrientationController::Shutdown() {
79 CHECK(file_task_runner_
);
81 file_task_runner_
->PostTask(
83 base::Bind(&OrientationController::ShutdownOnFILE
, this));
86 void OrientationController::ShutdownOnFILE() {
91 void OrientationController::WatchForSocketPathOnFILE() {
92 CHECK(base::MessageLoopForIO::current());
93 if (base::PathExists(base::FilePath(kSocketPath
))) {
94 ui_task_runner_
->PostTask(FROM_HERE
,
95 base::Bind(&OrientationController::StartListening
, this));
97 watcher_
.reset(new base::FilePathWatcher
);
99 base::FilePath(kSocketPath
),
101 base::Bind(&OrientationController::OnFilePathChangedOnFILE
, this));
105 void OrientationController::OnFilePathChangedOnFILE(const base::FilePath
& path
,
108 if (error
|| shutdown_
)
111 ui_task_runner_
->PostTask(FROM_HERE
,
112 base::Bind(&OrientationController::StartListening
, this));
115 void OrientationController::OnDataAvailableOnFILE(const void* data
) {
116 const DeviceSensorEvent
* event
=
117 static_cast<const DeviceSensorEvent
*>(data
);
118 if (event
->type
!= SENSOR_ACCELEROMETER
)
121 float gravity_x
= event
->data
[0];
122 float gravity_y
= event
->data
[1];
123 gfx::Display::Rotation rotation
;
124 if (gravity_x
< -kGravityThreshold
) {
125 rotation
= gfx::Display::ROTATE_270
;
126 } else if (gravity_x
> kGravityThreshold
) {
127 rotation
= gfx::Display::ROTATE_90
;
128 } else if (gravity_y
< -kGravityThreshold
) {
129 rotation
= gfx::Display::ROTATE_180
;
130 } else if (gravity_y
> kGravityThreshold
) {
131 rotation
= gfx::Display::ROTATE_0
;
133 // No rotation as gravity threshold was not hit.
137 if (rotation
== current_rotation_
||
138 event
->timestamp
- last_orientation_change_time_
<
139 kOrientationChangeDelayNS
) {
143 last_orientation_change_time_
= event
->timestamp
;
144 current_rotation_
= rotation
;
145 ui_task_runner_
->PostTask(FROM_HERE
,
146 base::Bind(&OrientationController::RotateOnUI
, this, rotation
));
149 void OrientationController::RotateOnUI(gfx::Display::Rotation rotation
) {
150 ScreenManager
* screen_manager
= ScreenManager::Get();
151 // Since this is called from the FILE thread, the screen manager may no longer
154 screen_manager
->SetRotation(rotation
);
157 } // namespace athena