Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / device_sensors / sensor_manager_android.cc
blobc31a98864c086869db2f85a6aa53086a4c9f56e4
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 base::Singleton<
64 SensorManagerAndroid,
65 base::LeakySingletonTraits<SensorManagerAndroid>>::get();
68 void SensorManagerAndroid::GotOrientation(
69 JNIEnv*, jobject, double alpha, double beta, double gamma) {
70 base::AutoLock autolock(orientation_buffer_lock_);
72 if (!device_orientation_buffer_)
73 return;
75 device_orientation_buffer_->seqlock.WriteBegin();
76 device_orientation_buffer_->data.alpha = alpha;
77 device_orientation_buffer_->data.hasAlpha = true;
78 device_orientation_buffer_->data.beta = beta;
79 device_orientation_buffer_->data.hasBeta = true;
80 device_orientation_buffer_->data.gamma = gamma;
81 device_orientation_buffer_->data.hasGamma = true;
82 device_orientation_buffer_->seqlock.WriteEnd();
84 if (!orientation_buffer_initialized_) {
85 OrientationSensorType type =
86 static_cast<OrientationSensorType>(GetOrientationSensorTypeUsed());
87 SetOrientationBufferStatus(true, type != GAME_ROTATION_VECTOR);
88 UpdateDeviceOrientationHistogram(type);
92 void SensorManagerAndroid::GotAcceleration(
93 JNIEnv*, jobject, double x, double y, double z) {
94 base::AutoLock autolock(motion_buffer_lock_);
96 if (!device_motion_buffer_)
97 return;
99 device_motion_buffer_->seqlock.WriteBegin();
100 device_motion_buffer_->data.accelerationX = x;
101 device_motion_buffer_->data.hasAccelerationX = true;
102 device_motion_buffer_->data.accelerationY = y;
103 device_motion_buffer_->data.hasAccelerationY = true;
104 device_motion_buffer_->data.accelerationZ = z;
105 device_motion_buffer_->data.hasAccelerationZ = true;
106 device_motion_buffer_->seqlock.WriteEnd();
108 if (!motion_buffer_initialized_) {
109 received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION] = 1;
110 CheckMotionBufferReadyToRead();
114 void SensorManagerAndroid::GotAccelerationIncludingGravity(
115 JNIEnv*, jobject, double x, double y, double z) {
116 base::AutoLock autolock(motion_buffer_lock_);
118 if (!device_motion_buffer_)
119 return;
121 device_motion_buffer_->seqlock.WriteBegin();
122 device_motion_buffer_->data.accelerationIncludingGravityX = x;
123 device_motion_buffer_->data.hasAccelerationIncludingGravityX = true;
124 device_motion_buffer_->data.accelerationIncludingGravityY = y;
125 device_motion_buffer_->data.hasAccelerationIncludingGravityY = true;
126 device_motion_buffer_->data.accelerationIncludingGravityZ = z;
127 device_motion_buffer_->data.hasAccelerationIncludingGravityZ = true;
128 device_motion_buffer_->seqlock.WriteEnd();
130 if (!motion_buffer_initialized_) {
131 received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY] = 1;
132 CheckMotionBufferReadyToRead();
136 void SensorManagerAndroid::GotRotationRate(
137 JNIEnv*, jobject, double alpha, double beta, double gamma) {
138 base::AutoLock autolock(motion_buffer_lock_);
140 if (!device_motion_buffer_)
141 return;
143 device_motion_buffer_->seqlock.WriteBegin();
144 device_motion_buffer_->data.rotationRateAlpha = alpha;
145 device_motion_buffer_->data.hasRotationRateAlpha = true;
146 device_motion_buffer_->data.rotationRateBeta = beta;
147 device_motion_buffer_->data.hasRotationRateBeta = true;
148 device_motion_buffer_->data.rotationRateGamma = gamma;
149 device_motion_buffer_->data.hasRotationRateGamma = true;
150 device_motion_buffer_->seqlock.WriteEnd();
152 if (!motion_buffer_initialized_) {
153 received_motion_data_[RECEIVED_MOTION_DATA_ROTATION_RATE] = 1;
154 CheckMotionBufferReadyToRead();
158 void SensorManagerAndroid::GotLight(JNIEnv*, jobject, double value) {
159 base::AutoLock autolock(light_buffer_lock_);
161 if (!device_light_buffer_)
162 return;
164 device_light_buffer_->seqlock.WriteBegin();
165 device_light_buffer_->data.value = value;
166 device_light_buffer_->seqlock.WriteEnd();
169 bool SensorManagerAndroid::Start(EventType event_type) {
170 DCHECK(!device_sensors_.is_null());
171 int rate_in_microseconds = (event_type == kTypeLight)
172 ? kLightSensorIntervalMicroseconds
173 : kInertialSensorIntervalMicroseconds;
174 return Java_DeviceSensors_start(AttachCurrentThread(),
175 device_sensors_.obj(),
176 reinterpret_cast<intptr_t>(this),
177 static_cast<jint>(event_type),
178 rate_in_microseconds);
181 void SensorManagerAndroid::Stop(EventType event_type) {
182 DCHECK(!device_sensors_.is_null());
183 Java_DeviceSensors_stop(AttachCurrentThread(),
184 device_sensors_.obj(),
185 static_cast<jint>(event_type));
188 int SensorManagerAndroid::GetNumberActiveDeviceMotionSensors() {
189 DCHECK(!device_sensors_.is_null());
190 return Java_DeviceSensors_getNumberActiveDeviceMotionSensors(
191 AttachCurrentThread(), device_sensors_.obj());
194 int SensorManagerAndroid::GetOrientationSensorTypeUsed() {
195 DCHECK(!device_sensors_.is_null());
196 return Java_DeviceSensors_getOrientationSensorTypeUsed(
197 AttachCurrentThread(), device_sensors_.obj());
200 // ----- Shared memory API methods
202 // --- Device Light
204 bool SensorManagerAndroid::StartFetchingDeviceLightData(
205 DeviceLightHardwareBuffer* buffer) {
206 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
207 StartFetchingLightDataOnUI(buffer);
208 } else {
209 BrowserThread::PostTask(
210 BrowserThread::UI, FROM_HERE,
211 base::Bind(&SensorManagerAndroid::StartFetchingLightDataOnUI,
212 base::Unretained(this),
213 buffer));
215 return true;
218 void SensorManagerAndroid::StartFetchingLightDataOnUI(
219 DeviceLightHardwareBuffer* buffer) {
220 DCHECK_CURRENTLY_ON(BrowserThread::UI);
221 DCHECK(buffer);
222 if (is_shutdown_)
223 return;
226 base::AutoLock autolock(light_buffer_lock_);
227 device_light_buffer_ = buffer;
228 SetLightBufferValue(-1);
230 bool success = Start(kTypeLight);
231 if (!success) {
232 base::AutoLock autolock(light_buffer_lock_);
233 SetLightBufferValue(std::numeric_limits<double>::infinity());
237 void SensorManagerAndroid::StopFetchingDeviceLightData() {
238 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
239 StopFetchingLightDataOnUI();
240 return;
243 BrowserThread::PostTask(
244 BrowserThread::UI, FROM_HERE,
245 base::Bind(&SensorManagerAndroid::StopFetchingLightDataOnUI,
246 base::Unretained(this)));
249 void SensorManagerAndroid::StopFetchingLightDataOnUI() {
250 DCHECK_CURRENTLY_ON(BrowserThread::UI);
251 if (is_shutdown_)
252 return;
254 Stop(kTypeLight);
256 base::AutoLock autolock(light_buffer_lock_);
257 if (device_light_buffer_) {
258 SetLightBufferValue(-1);
259 device_light_buffer_ = nullptr;
264 void SensorManagerAndroid::SetLightBufferValue(double lux) {
265 device_light_buffer_->seqlock.WriteBegin();
266 device_light_buffer_->data.value = lux;
267 device_light_buffer_->seqlock.WriteEnd();
270 // --- Device Motion
272 bool SensorManagerAndroid::StartFetchingDeviceMotionData(
273 DeviceMotionHardwareBuffer* buffer) {
274 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
275 StartFetchingMotionDataOnUI(buffer);
276 } else {
277 BrowserThread::PostTask(
278 BrowserThread::UI, FROM_HERE,
279 base::Bind(&SensorManagerAndroid::StartFetchingMotionDataOnUI,
280 base::Unretained(this),
281 buffer));
283 return true;
286 void SensorManagerAndroid::StartFetchingMotionDataOnUI(
287 DeviceMotionHardwareBuffer* buffer) {
288 DCHECK_CURRENTLY_ON(BrowserThread::UI);
289 DCHECK(buffer);
290 if (is_shutdown_)
291 return;
294 base::AutoLock autolock(motion_buffer_lock_);
295 device_motion_buffer_ = buffer;
296 ClearInternalMotionBuffers();
298 Start(kTypeMotion);
300 // If no motion data can ever be provided, the number of active device motion
301 // sensors will be zero. In that case flag the shared memory buffer
302 // as ready to read, as it will not change anyway.
303 number_active_device_motion_sensors_ = GetNumberActiveDeviceMotionSensors();
305 base::AutoLock autolock(motion_buffer_lock_);
306 CheckMotionBufferReadyToRead();
310 void SensorManagerAndroid::StopFetchingDeviceMotionData() {
311 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
312 StopFetchingMotionDataOnUI();
313 return;
316 BrowserThread::PostTask(
317 BrowserThread::UI, FROM_HERE,
318 base::Bind(&SensorManagerAndroid::StopFetchingMotionDataOnUI,
319 base::Unretained(this)));
322 void SensorManagerAndroid::StopFetchingMotionDataOnUI() {
323 DCHECK_CURRENTLY_ON(BrowserThread::UI);
324 if (is_shutdown_)
325 return;
327 Stop(kTypeMotion);
329 base::AutoLock autolock(motion_buffer_lock_);
330 if (device_motion_buffer_) {
331 ClearInternalMotionBuffers();
332 device_motion_buffer_ = nullptr;
337 void SensorManagerAndroid::CheckMotionBufferReadyToRead() {
338 if (received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION] +
339 received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY] +
340 received_motion_data_[RECEIVED_MOTION_DATA_ROTATION_RATE] ==
341 number_active_device_motion_sensors_) {
342 device_motion_buffer_->seqlock.WriteBegin();
343 device_motion_buffer_->data.interval =
344 kInertialSensorIntervalMicroseconds / 1000.;
345 device_motion_buffer_->seqlock.WriteEnd();
346 SetMotionBufferReadyStatus(true);
348 UMA_HISTOGRAM_BOOLEAN("InertialSensor.AccelerometerAndroidAvailable",
349 received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION] > 0);
350 UMA_HISTOGRAM_BOOLEAN(
351 "InertialSensor.AccelerometerIncGravityAndroidAvailable",
352 received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY]
353 > 0);
354 UMA_HISTOGRAM_BOOLEAN("InertialSensor.GyroscopeAndroidAvailable",
355 received_motion_data_[RECEIVED_MOTION_DATA_ROTATION_RATE] > 0);
359 void SensorManagerAndroid::SetMotionBufferReadyStatus(bool ready) {
360 device_motion_buffer_->seqlock.WriteBegin();
361 device_motion_buffer_->data.allAvailableSensorsAreActive = ready;
362 device_motion_buffer_->seqlock.WriteEnd();
363 motion_buffer_initialized_ = ready;
366 void SensorManagerAndroid::ClearInternalMotionBuffers() {
367 memset(received_motion_data_, 0, sizeof(received_motion_data_));
368 number_active_device_motion_sensors_ = 0;
369 SetMotionBufferReadyStatus(false);
372 // --- Device Orientation
374 void SensorManagerAndroid::SetOrientationBufferStatus(bool ready,
375 bool absolute) {
376 device_orientation_buffer_->seqlock.WriteBegin();
377 device_orientation_buffer_->data.absolute = absolute;
378 device_orientation_buffer_->data.hasAbsolute = ready;
379 device_orientation_buffer_->data.allAvailableSensorsAreActive = ready;
380 device_orientation_buffer_->seqlock.WriteEnd();
381 orientation_buffer_initialized_ = ready;
384 bool SensorManagerAndroid::StartFetchingDeviceOrientationData(
385 DeviceOrientationHardwareBuffer* buffer) {
386 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
387 StartFetchingOrientationDataOnUI(buffer);
388 } else {
389 BrowserThread::PostTask(
390 BrowserThread::UI, FROM_HERE,
391 base::Bind(&SensorManagerAndroid::StartFetchingOrientationDataOnUI,
392 base::Unretained(this),
393 buffer));
395 return true;
398 void SensorManagerAndroid::StartFetchingOrientationDataOnUI(
399 DeviceOrientationHardwareBuffer* buffer) {
400 DCHECK_CURRENTLY_ON(BrowserThread::UI);
401 DCHECK(buffer);
402 if (is_shutdown_)
403 return;
406 base::AutoLock autolock(orientation_buffer_lock_);
407 device_orientation_buffer_ = buffer;
409 bool success = Start(kTypeOrientation);
412 base::AutoLock autolock(orientation_buffer_lock_);
413 // If Start() was unsuccessful then set the buffer ready flag to true
414 // to start firing all-null events.
415 SetOrientationBufferStatus(!success /* ready */, false /* absolute */);
418 if (!success)
419 UpdateDeviceOrientationHistogram(NOT_AVAILABLE);
422 void SensorManagerAndroid::StopFetchingDeviceOrientationData() {
423 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
424 StopFetchingOrientationDataOnUI();
425 return;
428 BrowserThread::PostTask(
429 BrowserThread::UI, FROM_HERE,
430 base::Bind(&SensorManagerAndroid::StopFetchingOrientationDataOnUI,
431 base::Unretained(this)));
434 void SensorManagerAndroid::StopFetchingOrientationDataOnUI() {
435 DCHECK_CURRENTLY_ON(BrowserThread::UI);
436 if (is_shutdown_)
437 return;
439 Stop(kTypeOrientation);
441 base::AutoLock autolock(orientation_buffer_lock_);
442 if (device_orientation_buffer_) {
443 SetOrientationBufferStatus(false, false);
444 device_orientation_buffer_ = nullptr;
449 void SensorManagerAndroid::Shutdown() {
450 DCHECK_CURRENTLY_ON(BrowserThread::UI);
451 is_shutdown_ = true;
454 } // namespace content