OLD | NEW |
---|---|
(Empty) | |
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 { | |
oshima
2014/08/13 22:46:34
SensorType ? I know it's not necessary, but it's i
flackr
2014/08/14 17:29:51
Done.
| |
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 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::MessageLoop::current()->task_runner(); | |
oshima
2014/08/13 22:46:34
nit: base::MessageLoopForUI::current()
flackr
2014/08/14 17:29:51
Done.
| |
66 if (base::PathExists(base::FilePath(kSocketPath))) { | |
oshima
2014/08/13 22:46:34
Sorry I missed that in the previous review, but th
flackr
2014/08/14 17:29:51
Done.
| |
67 StartListening(); | |
68 } else { | |
69 io_task_runner->PostTask(FROM_HERE, base::Bind( | |
70 &OrientationController::WatchForSocketPathOnIO, | |
71 make_scoped_refptr<OrientationController>(this))); | |
72 } | |
73 } | |
74 | |
75 OrientationController::~OrientationController() { | |
76 } | |
77 | |
78 void OrientationController::WatchForSocketPathOnIO() { | |
79 CHECK(base::MessageLoopForIO::current()); | |
80 watcher_.reset(new base::FilePathWatcher); | |
81 watcher_->Watch(base::FilePath(kSocketPath), false, | |
82 base::Bind(&OrientationController::OnFilePathChangedOnIO, | |
83 make_scoped_refptr<OrientationController>(this))); | |
84 } | |
85 | |
86 void OrientationController::OnFilePathChangedOnIO(const base::FilePath& path, | |
87 bool error) { | |
88 watcher_.reset(); | |
89 if (error) { | |
90 return; | |
91 } | |
oshima
2014/08/13 22:46:34
nuke {}
flackr
2014/08/14 17:29:51
Done.
| |
92 | |
93 ui_task_runner_->PostTask(FROM_HERE, | |
94 base::Bind(&OrientationController::StartListening, | |
95 make_scoped_refptr<OrientationController>(this))); | |
96 } | |
97 | |
98 void OrientationController::OnDataAvailableOnIO(const void* data) { | |
99 const DeviceSensorEvent* event = | |
100 static_cast<const DeviceSensorEvent*>(data); | |
101 if (event->type != SENSOR_ACCELEROMETER) | |
102 return; | |
103 | |
104 float gravity_x = event->data[0]; | |
105 float gravity_y = event->data[1]; | |
106 gfx::Display::Rotation rotation; | |
107 if (gravity_x < -kGravityThreshold) { | |
108 rotation = gfx::Display::ROTATE_270; | |
109 } else if (gravity_x > kGravityThreshold) { | |
110 rotation = gfx::Display::ROTATE_90; | |
111 } else if (gravity_y < -kGravityThreshold) { | |
112 rotation = gfx::Display::ROTATE_180; | |
113 } else if (gravity_y > kGravityThreshold) { | |
114 rotation = gfx::Display::ROTATE_0; | |
115 } else { | |
116 // No rotation as gravity threshold was not hit. | |
117 return; | |
118 } | |
119 | |
120 if (rotation == current_rotation_ || | |
121 event->timestamp - last_orientation_change_time_ < | |
122 kOrientationChangeDelayNS) { | |
123 return; | |
124 } | |
125 | |
126 last_orientation_change_time_ = event->timestamp; | |
127 current_rotation_ = rotation; | |
128 ui_task_runner_->PostTask(FROM_HERE, | |
129 base::Bind(&OrientationController::RotateOnUI, | |
130 make_scoped_refptr<OrientationController>(this), rotation)); | |
131 } | |
132 | |
133 void OrientationController::RotateOnUI(gfx::Display::Rotation rotation) { | |
134 ScreenManager* screen_manager = ScreenManager::Get(); | |
135 // Since this is called from the IO thread, the screen manager may no longer | |
136 // exist. | |
137 if (screen_manager) | |
138 screen_manager->SetRotation(rotation); | |
139 } | |
140 | |
141 } // namespace athena | |
OLD | NEW |