Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / athena / system / orientation_controller.cc
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.
4
5 #include "athena/screen/public/screen_manager.h"
6 #include "athena/system/orientation_controller.h"
7 #include "base/bind.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"
12
13 namespace athena {
14
15 namespace {
16
17 // Path of the socket which the sensor daemon creates.
18 const char kSocketPath[] = "/dev/sensors/orientation";
19
20 // Threshold after which to rotate in a given direction.
21 const int kGravityThreshold = 6.0f;
22
23 // Minimum delay before triggering another orientation change.
24 const int kOrientationChangeDelayNS = 500000000;
25
26 enum SensorType {
27   SENSOR_ACCELEROMETER,
28   SENSOR_LIGHT,
29   SENSOR_PROXIMITY
30 };
31
32 // A sensor event from the device.
33 struct DeviceSensorEvent {
34   // The type of event from the SensorType enum above.
35   int32_t type;
36
37   // The time in nanoseconds at which the event happened.
38   int64_t timestamp;
39
40   union {
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/.
44     float data[3];
45
46     // Ambient (room) temperature in degrees Celcius.
47     float temperature;
48
49     // Proximity sensor distance in centimeters.
50     float distance;
51
52     // Ambient light level in SI lux units.
53     float light;
54   };
55 };
56
57 }  // namespace
58
59 OrientationController::OrientationController(
60     scoped_refptr<base::TaskRunner> io_task_runner)
61     : DeviceSocketListener(kSocketPath, sizeof(DeviceSensorEvent)),
62       last_orientation_change_time_(0),
63       weak_factory_(this) {
64   CHECK(base::MessageLoopForUI::current());
65   ui_task_runner_ = base::MessageLoopForUI::current()->task_runner();
66   io_task_runner->PostTask(FROM_HERE, base::Bind(
67       &OrientationController::WatchForSocketPathOnIO,
68       make_scoped_refptr<OrientationController>(this)));
69 }
70
71 OrientationController::~OrientationController() {
72 }
73
74 void OrientationController::WatchForSocketPathOnIO() {
75   CHECK(base::MessageLoopForIO::current());
76   if (base::PathExists(base::FilePath(kSocketPath))) {
77     ui_task_runner_->PostTask(FROM_HERE,
78         base::Bind(&OrientationController::StartListening,
79                    make_scoped_refptr<OrientationController>(this)));
80   } else {
81     watcher_.reset(new base::FilePathWatcher);
82     watcher_->Watch(
83         base::FilePath(kSocketPath), false,
84         base::Bind(&OrientationController::OnFilePathChangedOnIO,
85                    make_scoped_refptr<OrientationController>(this)));
86   }
87 }
88
89 void OrientationController::OnFilePathChangedOnIO(const base::FilePath& path,
90                                                   bool error) {
91   watcher_.reset();
92   if (error)
93     return;
94
95   ui_task_runner_->PostTask(FROM_HERE,
96       base::Bind(&OrientationController::StartListening,
97                  make_scoped_refptr<OrientationController>(this)));
98 }
99
100 void OrientationController::OnDataAvailableOnIO(const void* data) {
101   const DeviceSensorEvent* event =
102       static_cast<const DeviceSensorEvent*>(data);
103   if (event->type != SENSOR_ACCELEROMETER)
104     return;
105
106   float gravity_x = event->data[0];
107   float gravity_y = event->data[1];
108   gfx::Display::Rotation rotation;
109   if (gravity_x < -kGravityThreshold) {
110     rotation = gfx::Display::ROTATE_270;
111   } else if (gravity_x > kGravityThreshold) {
112     rotation = gfx::Display::ROTATE_90;
113   } else if (gravity_y < -kGravityThreshold) {
114     rotation = gfx::Display::ROTATE_180;
115   } else if (gravity_y > kGravityThreshold) {
116     rotation = gfx::Display::ROTATE_0;
117   } else {
118     // No rotation as gravity threshold was not hit.
119     return;
120   }
121
122   if (rotation == current_rotation_ ||
123       event->timestamp - last_orientation_change_time_ <
124           kOrientationChangeDelayNS) {
125     return;
126   }
127
128   last_orientation_change_time_ = event->timestamp;
129   current_rotation_ = rotation;
130   ui_task_runner_->PostTask(FROM_HERE,
131       base::Bind(&OrientationController::RotateOnUI,
132                  make_scoped_refptr<OrientationController>(this), rotation));
133 }
134
135 void OrientationController::RotateOnUI(gfx::Display::Rotation rotation) {
136   ScreenManager* screen_manager = ScreenManager::Get();
137   // Since this is called from the IO thread, the screen manager may no longer
138   // exist.
139   if (screen_manager)
140     screen_manager->SetRotation(rotation);
141 }
142
143 }  // namespace athena