• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 "content/browser/device_orientation/data_fetcher_impl_android.h"
6 
7 #include <string.h>
8 
9 #include "base/android/jni_android.h"
10 #include "base/memory/singleton.h"
11 #include "base/metrics/histogram.h"
12 #include "content/browser/device_orientation/inertial_sensor_consts.h"
13 #include "jni/DeviceMotionAndOrientation_jni.h"
14 
15 using base::android::AttachCurrentThread;
16 
17 namespace {
18 
updateRotationVectorHistogram(bool value)19 static void updateRotationVectorHistogram(bool value) {
20   UMA_HISTOGRAM_BOOLEAN("InertialSensor.RotationVectorAndroidAvailable", value);
21 }
22 
23 }
24 
25 namespace content {
26 
DataFetcherImplAndroid()27 DataFetcherImplAndroid::DataFetcherImplAndroid()
28     : number_active_device_motion_sensors_(0),
29       device_motion_buffer_(NULL),
30       device_orientation_buffer_(NULL),
31       is_motion_buffer_ready_(false),
32       is_orientation_buffer_ready_(false) {
33   memset(received_motion_data_, 0, sizeof(received_motion_data_));
34   device_orientation_.Reset(
35       Java_DeviceMotionAndOrientation_getInstance(AttachCurrentThread()));
36 }
37 
~DataFetcherImplAndroid()38 DataFetcherImplAndroid::~DataFetcherImplAndroid() {
39 }
40 
Register(JNIEnv * env)41 bool DataFetcherImplAndroid::Register(JNIEnv* env) {
42   return RegisterNativesImpl(env);
43 }
44 
GetInstance()45 DataFetcherImplAndroid* DataFetcherImplAndroid::GetInstance() {
46   return Singleton<DataFetcherImplAndroid,
47                    LeakySingletonTraits<DataFetcherImplAndroid> >::get();
48 }
49 
GotOrientation(JNIEnv *,jobject,double alpha,double beta,double gamma)50 void DataFetcherImplAndroid::GotOrientation(
51     JNIEnv*, jobject, double alpha, double beta, double gamma) {
52   base::AutoLock autolock(orientation_buffer_lock_);
53 
54   if (!device_orientation_buffer_)
55     return;
56 
57   device_orientation_buffer_->seqlock.WriteBegin();
58   device_orientation_buffer_->data.alpha = alpha;
59   device_orientation_buffer_->data.hasAlpha = true;
60   device_orientation_buffer_->data.beta = beta;
61   device_orientation_buffer_->data.hasBeta = true;
62   device_orientation_buffer_->data.gamma = gamma;
63   device_orientation_buffer_->data.hasGamma = true;
64   device_orientation_buffer_->seqlock.WriteEnd();
65 
66   if (!is_orientation_buffer_ready_) {
67     SetOrientationBufferReadyStatus(true);
68     updateRotationVectorHistogram(true);
69   }
70 }
71 
GotAcceleration(JNIEnv *,jobject,double x,double y,double z)72 void DataFetcherImplAndroid::GotAcceleration(
73     JNIEnv*, jobject, double x, double y, double z) {
74   base::AutoLock autolock(motion_buffer_lock_);
75 
76   if (!device_motion_buffer_)
77     return;
78 
79   device_motion_buffer_->seqlock.WriteBegin();
80   device_motion_buffer_->data.accelerationX = x;
81   device_motion_buffer_->data.hasAccelerationX = true;
82   device_motion_buffer_->data.accelerationY = y;
83   device_motion_buffer_->data.hasAccelerationY = true;
84   device_motion_buffer_->data.accelerationZ = z;
85   device_motion_buffer_->data.hasAccelerationZ = true;
86   device_motion_buffer_->seqlock.WriteEnd();
87 
88   if (!is_motion_buffer_ready_) {
89     received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION] = 1;
90     CheckMotionBufferReadyToRead();
91   }
92 }
93 
GotAccelerationIncludingGravity(JNIEnv *,jobject,double x,double y,double z)94 void DataFetcherImplAndroid::GotAccelerationIncludingGravity(
95     JNIEnv*, jobject, double x, double y, double z) {
96   base::AutoLock autolock(motion_buffer_lock_);
97 
98   if (!device_motion_buffer_)
99     return;
100 
101   device_motion_buffer_->seqlock.WriteBegin();
102   device_motion_buffer_->data.accelerationIncludingGravityX = x;
103   device_motion_buffer_->data.hasAccelerationIncludingGravityX = true;
104   device_motion_buffer_->data.accelerationIncludingGravityY = y;
105   device_motion_buffer_->data.hasAccelerationIncludingGravityY = true;
106   device_motion_buffer_->data.accelerationIncludingGravityZ = z;
107   device_motion_buffer_->data.hasAccelerationIncludingGravityZ = true;
108   device_motion_buffer_->seqlock.WriteEnd();
109 
110   if (!is_motion_buffer_ready_) {
111     received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY] = 1;
112     CheckMotionBufferReadyToRead();
113   }
114 }
115 
GotRotationRate(JNIEnv *,jobject,double alpha,double beta,double gamma)116 void DataFetcherImplAndroid::GotRotationRate(
117     JNIEnv*, jobject, double alpha, double beta, double gamma) {
118   base::AutoLock autolock(motion_buffer_lock_);
119 
120   if (!device_motion_buffer_)
121     return;
122 
123   device_motion_buffer_->seqlock.WriteBegin();
124   device_motion_buffer_->data.rotationRateAlpha = alpha;
125   device_motion_buffer_->data.hasRotationRateAlpha = true;
126   device_motion_buffer_->data.rotationRateBeta = beta;
127   device_motion_buffer_->data.hasRotationRateBeta = true;
128   device_motion_buffer_->data.rotationRateGamma = gamma;
129   device_motion_buffer_->data.hasRotationRateGamma = true;
130   device_motion_buffer_->seqlock.WriteEnd();
131 
132   if (!is_motion_buffer_ready_) {
133     received_motion_data_[RECEIVED_MOTION_DATA_ROTATION_RATE] = 1;
134     CheckMotionBufferReadyToRead();
135   }
136 }
137 
Start(DeviceData::Type event_type)138 bool DataFetcherImplAndroid::Start(DeviceData::Type event_type) {
139   DCHECK(!device_orientation_.is_null());
140   return Java_DeviceMotionAndOrientation_start(
141       AttachCurrentThread(), device_orientation_.obj(),
142       reinterpret_cast<intptr_t>(this), static_cast<jint>(event_type),
143       kInertialSensorIntervalMillis);
144 }
145 
Stop(DeviceData::Type event_type)146 void DataFetcherImplAndroid::Stop(DeviceData::Type event_type) {
147   DCHECK(!device_orientation_.is_null());
148   Java_DeviceMotionAndOrientation_stop(
149       AttachCurrentThread(), device_orientation_.obj(),
150       static_cast<jint>(event_type));
151 }
152 
GetNumberActiveDeviceMotionSensors()153 int DataFetcherImplAndroid::GetNumberActiveDeviceMotionSensors() {
154   DCHECK(!device_orientation_.is_null());
155   return Java_DeviceMotionAndOrientation_getNumberActiveDeviceMotionSensors(
156       AttachCurrentThread(), device_orientation_.obj());
157 }
158 
159 
160 // ----- Shared memory API methods
161 
162 // --- Device Motion
163 
StartFetchingDeviceMotionData(DeviceMotionHardwareBuffer * buffer)164 bool DataFetcherImplAndroid::StartFetchingDeviceMotionData(
165     DeviceMotionHardwareBuffer* buffer) {
166   DCHECK(buffer);
167   {
168     base::AutoLock autolock(motion_buffer_lock_);
169     device_motion_buffer_ = buffer;
170     ClearInternalMotionBuffers();
171   }
172   bool success = Start(DeviceData::kTypeMotion);
173 
174   // If no motion data can ever be provided, the number of active device motion
175   // sensors will be zero. In that case flag the shared memory buffer
176   // as ready to read, as it will not change anyway.
177   number_active_device_motion_sensors_ = GetNumberActiveDeviceMotionSensors();
178   {
179     base::AutoLock autolock(motion_buffer_lock_);
180     CheckMotionBufferReadyToRead();
181   }
182   return success;
183 }
184 
StopFetchingDeviceMotionData()185 void DataFetcherImplAndroid::StopFetchingDeviceMotionData() {
186   Stop(DeviceData::kTypeMotion);
187   {
188     base::AutoLock autolock(motion_buffer_lock_);
189     if (device_motion_buffer_) {
190       ClearInternalMotionBuffers();
191       device_motion_buffer_ = NULL;
192     }
193   }
194 }
195 
CheckMotionBufferReadyToRead()196 void DataFetcherImplAndroid::CheckMotionBufferReadyToRead() {
197   if (received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION] +
198       received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY] +
199       received_motion_data_[RECEIVED_MOTION_DATA_ROTATION_RATE] ==
200       number_active_device_motion_sensors_) {
201     device_motion_buffer_->seqlock.WriteBegin();
202     device_motion_buffer_->data.interval = kInertialSensorIntervalMillis;
203     device_motion_buffer_->seqlock.WriteEnd();
204     SetMotionBufferReadyStatus(true);
205 
206     UMA_HISTOGRAM_BOOLEAN("InertialSensor.AccelerometerAndroidAvailable",
207         received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION] > 0);
208     UMA_HISTOGRAM_BOOLEAN(
209         "InertialSensor.AccelerometerIncGravityAndroidAvailable",
210         received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY]
211         > 0);
212     UMA_HISTOGRAM_BOOLEAN("InertialSensor.GyroscopeAndroidAvailable",
213         received_motion_data_[RECEIVED_MOTION_DATA_ROTATION_RATE] > 0);
214   }
215 }
216 
SetMotionBufferReadyStatus(bool ready)217 void DataFetcherImplAndroid::SetMotionBufferReadyStatus(bool ready) {
218   device_motion_buffer_->seqlock.WriteBegin();
219   device_motion_buffer_->data.allAvailableSensorsAreActive = ready;
220   device_motion_buffer_->seqlock.WriteEnd();
221   is_motion_buffer_ready_ = ready;
222 }
223 
ClearInternalMotionBuffers()224 void DataFetcherImplAndroid::ClearInternalMotionBuffers() {
225   memset(received_motion_data_, 0, sizeof(received_motion_data_));
226   number_active_device_motion_sensors_ = 0;
227   SetMotionBufferReadyStatus(false);
228 }
229 
230 // --- Device Orientation
231 
SetOrientationBufferReadyStatus(bool ready)232 void DataFetcherImplAndroid::SetOrientationBufferReadyStatus(bool ready) {
233   device_orientation_buffer_->seqlock.WriteBegin();
234   device_orientation_buffer_->data.absolute = ready;
235   device_orientation_buffer_->data.hasAbsolute = ready;
236   device_orientation_buffer_->data.allAvailableSensorsAreActive = ready;
237   device_orientation_buffer_->seqlock.WriteEnd();
238   is_orientation_buffer_ready_ = ready;
239 }
240 
StartFetchingDeviceOrientationData(DeviceOrientationHardwareBuffer * buffer)241 bool DataFetcherImplAndroid::StartFetchingDeviceOrientationData(
242     DeviceOrientationHardwareBuffer* buffer) {
243   DCHECK(buffer);
244   {
245     base::AutoLock autolock(orientation_buffer_lock_);
246     device_orientation_buffer_ = buffer;
247   }
248   bool success = Start(DeviceData::kTypeOrientation);
249 
250   {
251     base::AutoLock autolock(orientation_buffer_lock_);
252     // If Start() was unsuccessful then set the buffer ready flag to true
253     // to start firing all-null events.
254     SetOrientationBufferReadyStatus(!success);
255   }
256 
257   if (!success)
258     updateRotationVectorHistogram(false);
259 
260   return success;
261 }
262 
StopFetchingDeviceOrientationData()263 void DataFetcherImplAndroid::StopFetchingDeviceOrientationData() {
264   Stop(DeviceData::kTypeOrientation);
265   {
266     base::AutoLock autolock(orientation_buffer_lock_);
267     if (device_orientation_buffer_) {
268       SetOrientationBufferReadyStatus(false);
269       device_orientation_buffer_ = NULL;
270     }
271   }
272 }
273 
274 }  // namespace content
275