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"
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
;
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
{
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
);
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),
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
<
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_
)
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_
)
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_
)
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_
)
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_
)
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
204 bool SensorManagerAndroid::StartFetchingDeviceLightData(
205 DeviceLightHardwareBuffer
* buffer
) {
206 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
207 StartFetchingLightDataOnUI(buffer
);
209 BrowserThread::PostTask(
210 BrowserThread::UI
, FROM_HERE
,
211 base::Bind(&SensorManagerAndroid::StartFetchingLightDataOnUI
,
212 base::Unretained(this),
218 void SensorManagerAndroid::StartFetchingLightDataOnUI(
219 DeviceLightHardwareBuffer
* buffer
) {
220 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
226 base::AutoLock
autolock(light_buffer_lock_
);
227 device_light_buffer_
= buffer
;
228 SetLightBufferValue(-1);
230 bool success
= Start(kTypeLight
);
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();
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
);
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();
272 bool SensorManagerAndroid::StartFetchingDeviceMotionData(
273 DeviceMotionHardwareBuffer
* buffer
) {
274 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
275 StartFetchingMotionDataOnUI(buffer
);
277 BrowserThread::PostTask(
278 BrowserThread::UI
, FROM_HERE
,
279 base::Bind(&SensorManagerAndroid::StartFetchingMotionDataOnUI
,
280 base::Unretained(this),
286 void SensorManagerAndroid::StartFetchingMotionDataOnUI(
287 DeviceMotionHardwareBuffer
* buffer
) {
288 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
294 base::AutoLock
autolock(motion_buffer_lock_
);
295 device_motion_buffer_
= buffer
;
296 ClearInternalMotionBuffers();
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();
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
);
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
]
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
,
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
);
389 BrowserThread::PostTask(
390 BrowserThread::UI
, FROM_HERE
,
391 base::Bind(&SensorManagerAndroid::StartFetchingOrientationDataOnUI
,
392 base::Unretained(this),
398 void SensorManagerAndroid::StartFetchingOrientationDataOnUI(
399 DeviceOrientationHardwareBuffer
* buffer
) {
400 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
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 */);
419 UpdateDeviceOrientationHistogram(NOT_AVAILABLE
);
422 void SensorManagerAndroid::StopFetchingDeviceOrientationData() {
423 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
424 StopFetchingOrientationDataOnUI();
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
);
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
);
454 } // namespace content