Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / content / browser / device_sensors / sensor_manager_android.cc
blobf69144caf49ce2f3fecfe8cc9c7d73cb39aeba29
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 "content/browser/device_sensors/sensor_manager_android.h"
7 #include <string.h>
9 #include "base/android/jni_android.h"
10 #include "base/bind.h"
11 #include "base/memory/singleton.h"
12 #include "base/metrics/histogram.h"
13 #include "content/browser/device_sensors/inertial_sensor_consts.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "jni/DeviceSensors_jni.h"
17 using base::android::AttachCurrentThread;
19 namespace {
21 // These constants should match ORIENTATION_* constants in content/public/
22 // android/java/src/org/chromium/content/browser/DeviceSensors.java.
23 // When adding new constants don't modify the order as they are used for UMA.
24 // TODO(timvolodine): make this a shared enum, crbug.com/522571.
25 enum OrientationSensorType {
26 NOT_AVAILABLE = 0,
27 ROTATION_VECTOR = 1,
28 ACCELEROMETER_MAGNETIC = 2,
29 GAME_ROTATION_VECTOR = 3,
30 ORIENTATION_SENSOR_MAX = 4,
33 void UpdateDeviceOrientationHistogram(OrientationSensorType type) {
34 UMA_HISTOGRAM_ENUMERATION("InertialSensor.DeviceOrientationSensorAndroid",
35 type, ORIENTATION_SENSOR_MAX);
38 } // namespace
40 namespace content {
42 SensorManagerAndroid::SensorManagerAndroid()
43 : number_active_device_motion_sensors_(0),
44 device_light_buffer_(nullptr),
45 device_motion_buffer_(nullptr),
46 device_orientation_buffer_(nullptr),
47 motion_buffer_initialized_(false),
48 orientation_buffer_initialized_(false),
49 is_shutdown_(false) {
50 memset(received_motion_data_, 0, sizeof(received_motion_data_));
51 device_sensors_.Reset(Java_DeviceSensors_getInstance(
52 AttachCurrentThread(), base::android::GetApplicationContext()));
55 SensorManagerAndroid::~SensorManagerAndroid() {
58 bool SensorManagerAndroid::Register(JNIEnv* env) {
59 return RegisterNativesImpl(env);
62 SensorManagerAndroid* SensorManagerAndroid::GetInstance() {
63 return Singleton<SensorManagerAndroid,
64 LeakySingletonTraits<SensorManagerAndroid> >::get();
67 void SensorManagerAndroid::GotOrientation(
68 JNIEnv*, jobject, double alpha, double beta, double gamma) {
69 base::AutoLock autolock(orientation_buffer_lock_);
71 if (!device_orientation_buffer_)
72 return;
74 device_orientation_buffer_->seqlock.WriteBegin();
75 device_orientation_buffer_->data.alpha = alpha;
76 device_orientation_buffer_->data.hasAlpha = true;
77 device_orientation_buffer_->data.beta = beta;
78 device_orientation_buffer_->data.hasBeta = true;
79 device_orientation_buffer_->data.gamma = gamma;
80 device_orientation_buffer_->data.hasGamma = true;
81 device_orientation_buffer_->seqlock.WriteEnd();
83 if (!orientation_buffer_initialized_) {
84 OrientationSensorType type =
85 static_cast<OrientationSensorType>(GetOrientationSensorTypeUsed());
86 SetOrientationBufferStatus(true, type != GAME_ROTATION_VECTOR);
87 UpdateDeviceOrientationHistogram(type);
91 void SensorManagerAndroid::GotAcceleration(
92 JNIEnv*, jobject, double x, double y, double z) {
93 base::AutoLock autolock(motion_buffer_lock_);
95 if (!device_motion_buffer_)
96 return;
98 device_motion_buffer_->seqlock.WriteBegin();
99 device_motion_buffer_->data.accelerationX = x;
100 device_motion_buffer_->data.hasAccelerationX = true;
101 device_motion_buffer_->data.accelerationY = y;
102 device_motion_buffer_->data.hasAccelerationY = true;
103 device_motion_buffer_->data.accelerationZ = z;
104 device_motion_buffer_->data.hasAccelerationZ = true;
105 device_motion_buffer_->seqlock.WriteEnd();
107 if (!motion_buffer_initialized_) {
108 received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION] = 1;
109 CheckMotionBufferReadyToRead();
113 void SensorManagerAndroid::GotAccelerationIncludingGravity(
114 JNIEnv*, jobject, double x, double y, double z) {
115 base::AutoLock autolock(motion_buffer_lock_);
117 if (!device_motion_buffer_)
118 return;
120 device_motion_buffer_->seqlock.WriteBegin();
121 device_motion_buffer_->data.accelerationIncludingGravityX = x;
122 device_motion_buffer_->data.hasAccelerationIncludingGravityX = true;
123 device_motion_buffer_->data.accelerationIncludingGravityY = y;
124 device_motion_buffer_->data.hasAccelerationIncludingGravityY = true;
125 device_motion_buffer_->data.accelerationIncludingGravityZ = z;
126 device_motion_buffer_->data.hasAccelerationIncludingGravityZ = true;
127 device_motion_buffer_->seqlock.WriteEnd();
129 if (!motion_buffer_initialized_) {
130 received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY] = 1;
131 CheckMotionBufferReadyToRead();
135 void SensorManagerAndroid::GotRotationRate(
136 JNIEnv*, jobject, double alpha, double beta, double gamma) {
137 base::AutoLock autolock(motion_buffer_lock_);
139 if (!device_motion_buffer_)
140 return;
142 device_motion_buffer_->seqlock.WriteBegin();
143 device_motion_buffer_->data.rotationRateAlpha = alpha;
144 device_motion_buffer_->data.hasRotationRateAlpha = true;
145 device_motion_buffer_->data.rotationRateBeta = beta;
146 device_motion_buffer_->data.hasRotationRateBeta = true;
147 device_motion_buffer_->data.rotationRateGamma = gamma;
148 device_motion_buffer_->data.hasRotationRateGamma = true;
149 device_motion_buffer_->seqlock.WriteEnd();
151 if (!motion_buffer_initialized_) {
152 received_motion_data_[RECEIVED_MOTION_DATA_ROTATION_RATE] = 1;
153 CheckMotionBufferReadyToRead();
157 void SensorManagerAndroid::GotLight(JNIEnv*, jobject, double value) {
158 base::AutoLock autolock(light_buffer_lock_);
160 if (!device_light_buffer_)
161 return;
163 device_light_buffer_->seqlock.WriteBegin();
164 device_light_buffer_->data.value = value;
165 device_light_buffer_->seqlock.WriteEnd();
168 bool SensorManagerAndroid::Start(EventType event_type) {
169 DCHECK(!device_sensors_.is_null());
170 int rate_in_microseconds = (event_type == kTypeLight)
171 ? kLightSensorIntervalMicroseconds
172 : kInertialSensorIntervalMicroseconds;
173 return Java_DeviceSensors_start(AttachCurrentThread(),
174 device_sensors_.obj(),
175 reinterpret_cast<intptr_t>(this),
176 static_cast<jint>(event_type),
177 rate_in_microseconds);
180 void SensorManagerAndroid::Stop(EventType event_type) {
181 DCHECK(!device_sensors_.is_null());
182 Java_DeviceSensors_stop(AttachCurrentThread(),
183 device_sensors_.obj(),
184 static_cast<jint>(event_type));
187 int SensorManagerAndroid::GetNumberActiveDeviceMotionSensors() {
188 DCHECK(!device_sensors_.is_null());
189 return Java_DeviceSensors_getNumberActiveDeviceMotionSensors(
190 AttachCurrentThread(), device_sensors_.obj());
193 int SensorManagerAndroid::GetOrientationSensorTypeUsed() {
194 DCHECK(!device_sensors_.is_null());
195 return Java_DeviceSensors_getOrientationSensorTypeUsed(
196 AttachCurrentThread(), device_sensors_.obj());
199 // ----- Shared memory API methods
201 // --- Device Light
203 bool SensorManagerAndroid::StartFetchingDeviceLightData(
204 DeviceLightHardwareBuffer* buffer) {
205 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
206 StartFetchingLightDataOnUI(buffer);
207 } else {
208 BrowserThread::PostTask(
209 BrowserThread::UI, FROM_HERE,
210 base::Bind(&SensorManagerAndroid::StartFetchingLightDataOnUI,
211 base::Unretained(this),
212 buffer));
214 return true;
217 void SensorManagerAndroid::StartFetchingLightDataOnUI(
218 DeviceLightHardwareBuffer* buffer) {
219 DCHECK_CURRENTLY_ON(BrowserThread::UI);
220 DCHECK(buffer);
221 if (is_shutdown_)
222 return;
225 base::AutoLock autolock(light_buffer_lock_);
226 device_light_buffer_ = buffer;
227 SetLightBufferValue(-1);
229 bool success = Start(kTypeLight);
230 if (!success) {
231 base::AutoLock autolock(light_buffer_lock_);
232 SetLightBufferValue(std::numeric_limits<double>::infinity());
236 void SensorManagerAndroid::StopFetchingDeviceLightData() {
237 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
238 StopFetchingLightDataOnUI();
239 return;
242 BrowserThread::PostTask(
243 BrowserThread::UI, FROM_HERE,
244 base::Bind(&SensorManagerAndroid::StopFetchingLightDataOnUI,
245 base::Unretained(this)));
248 void SensorManagerAndroid::StopFetchingLightDataOnUI() {
249 DCHECK_CURRENTLY_ON(BrowserThread::UI);
250 if (is_shutdown_)
251 return;
253 Stop(kTypeLight);
255 base::AutoLock autolock(light_buffer_lock_);
256 if (device_light_buffer_) {
257 SetLightBufferValue(-1);
258 device_light_buffer_ = nullptr;
263 void SensorManagerAndroid::SetLightBufferValue(double lux) {
264 device_light_buffer_->seqlock.WriteBegin();
265 device_light_buffer_->data.value = lux;
266 device_light_buffer_->seqlock.WriteEnd();
269 // --- Device Motion
271 bool SensorManagerAndroid::StartFetchingDeviceMotionData(
272 DeviceMotionHardwareBuffer* buffer) {
273 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
274 StartFetchingMotionDataOnUI(buffer);
275 } else {
276 BrowserThread::PostTask(
277 BrowserThread::UI, FROM_HERE,
278 base::Bind(&SensorManagerAndroid::StartFetchingMotionDataOnUI,
279 base::Unretained(this),
280 buffer));
282 return true;
285 void SensorManagerAndroid::StartFetchingMotionDataOnUI(
286 DeviceMotionHardwareBuffer* buffer) {
287 DCHECK_CURRENTLY_ON(BrowserThread::UI);
288 DCHECK(buffer);
289 if (is_shutdown_)
290 return;
293 base::AutoLock autolock(motion_buffer_lock_);
294 device_motion_buffer_ = buffer;
295 ClearInternalMotionBuffers();
297 Start(kTypeMotion);
299 // If no motion data can ever be provided, the number of active device motion
300 // sensors will be zero. In that case flag the shared memory buffer
301 // as ready to read, as it will not change anyway.
302 number_active_device_motion_sensors_ = GetNumberActiveDeviceMotionSensors();
304 base::AutoLock autolock(motion_buffer_lock_);
305 CheckMotionBufferReadyToRead();
309 void SensorManagerAndroid::StopFetchingDeviceMotionData() {
310 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
311 StopFetchingMotionDataOnUI();
312 return;
315 BrowserThread::PostTask(
316 BrowserThread::UI, FROM_HERE,
317 base::Bind(&SensorManagerAndroid::StopFetchingMotionDataOnUI,
318 base::Unretained(this)));
321 void SensorManagerAndroid::StopFetchingMotionDataOnUI() {
322 DCHECK_CURRENTLY_ON(BrowserThread::UI);
323 if (is_shutdown_)
324 return;
326 Stop(kTypeMotion);
328 base::AutoLock autolock(motion_buffer_lock_);
329 if (device_motion_buffer_) {
330 ClearInternalMotionBuffers();
331 device_motion_buffer_ = nullptr;
336 void SensorManagerAndroid::CheckMotionBufferReadyToRead() {
337 if (received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION] +
338 received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY] +
339 received_motion_data_[RECEIVED_MOTION_DATA_ROTATION_RATE] ==
340 number_active_device_motion_sensors_) {
341 device_motion_buffer_->seqlock.WriteBegin();
342 device_motion_buffer_->data.interval =
343 kInertialSensorIntervalMicroseconds / 1000.;
344 device_motion_buffer_->seqlock.WriteEnd();
345 SetMotionBufferReadyStatus(true);
347 UMA_HISTOGRAM_BOOLEAN("InertialSensor.AccelerometerAndroidAvailable",
348 received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION] > 0);
349 UMA_HISTOGRAM_BOOLEAN(
350 "InertialSensor.AccelerometerIncGravityAndroidAvailable",
351 received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY]
352 > 0);
353 UMA_HISTOGRAM_BOOLEAN("InertialSensor.GyroscopeAndroidAvailable",
354 received_motion_data_[RECEIVED_MOTION_DATA_ROTATION_RATE] > 0);
358 void SensorManagerAndroid::SetMotionBufferReadyStatus(bool ready) {
359 device_motion_buffer_->seqlock.WriteBegin();
360 device_motion_buffer_->data.allAvailableSensorsAreActive = ready;
361 device_motion_buffer_->seqlock.WriteEnd();
362 motion_buffer_initialized_ = ready;
365 void SensorManagerAndroid::ClearInternalMotionBuffers() {
366 memset(received_motion_data_, 0, sizeof(received_motion_data_));
367 number_active_device_motion_sensors_ = 0;
368 SetMotionBufferReadyStatus(false);
371 // --- Device Orientation
373 void SensorManagerAndroid::SetOrientationBufferStatus(bool ready,
374 bool absolute) {
375 device_orientation_buffer_->seqlock.WriteBegin();
376 device_orientation_buffer_->data.absolute = absolute;
377 device_orientation_buffer_->data.hasAbsolute = ready;
378 device_orientation_buffer_->data.allAvailableSensorsAreActive = ready;
379 device_orientation_buffer_->seqlock.WriteEnd();
380 orientation_buffer_initialized_ = ready;
383 bool SensorManagerAndroid::StartFetchingDeviceOrientationData(
384 DeviceOrientationHardwareBuffer* buffer) {
385 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
386 StartFetchingOrientationDataOnUI(buffer);
387 } else {
388 BrowserThread::PostTask(
389 BrowserThread::UI, FROM_HERE,
390 base::Bind(&SensorManagerAndroid::StartFetchingOrientationDataOnUI,
391 base::Unretained(this),
392 buffer));
394 return true;
397 void SensorManagerAndroid::StartFetchingOrientationDataOnUI(
398 DeviceOrientationHardwareBuffer* buffer) {
399 DCHECK_CURRENTLY_ON(BrowserThread::UI);
400 DCHECK(buffer);
401 if (is_shutdown_)
402 return;
405 base::AutoLock autolock(orientation_buffer_lock_);
406 device_orientation_buffer_ = buffer;
408 bool success = Start(kTypeOrientation);
411 base::AutoLock autolock(orientation_buffer_lock_);
412 // If Start() was unsuccessful then set the buffer ready flag to true
413 // to start firing all-null events.
414 SetOrientationBufferStatus(!success /* ready */, false /* absolute */);
417 if (!success)
418 UpdateDeviceOrientationHistogram(NOT_AVAILABLE);
421 void SensorManagerAndroid::StopFetchingDeviceOrientationData() {
422 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
423 StopFetchingOrientationDataOnUI();
424 return;
427 BrowserThread::PostTask(
428 BrowserThread::UI, FROM_HERE,
429 base::Bind(&SensorManagerAndroid::StopFetchingOrientationDataOnUI,
430 base::Unretained(this)));
433 void SensorManagerAndroid::StopFetchingOrientationDataOnUI() {
434 DCHECK_CURRENTLY_ON(BrowserThread::UI);
435 if (is_shutdown_)
436 return;
438 Stop(kTypeOrientation);
440 base::AutoLock autolock(orientation_buffer_lock_);
441 if (device_orientation_buffer_) {
442 SetOrientationBufferStatus(false, false);
443 device_orientation_buffer_ = nullptr;
448 void SensorManagerAndroid::Shutdown() {
449 DCHECK_CURRENTLY_ON(BrowserThread::UI);
450 is_shutdown_ = true;
453 } // namespace content