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 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_
)
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_
)
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_
)
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_
)
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_
)
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
203 bool SensorManagerAndroid::StartFetchingDeviceLightData(
204 DeviceLightHardwareBuffer
* buffer
) {
205 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
206 StartFetchingLightDataOnUI(buffer
);
208 BrowserThread::PostTask(
209 BrowserThread::UI
, FROM_HERE
,
210 base::Bind(&SensorManagerAndroid::StartFetchingLightDataOnUI
,
211 base::Unretained(this),
217 void SensorManagerAndroid::StartFetchingLightDataOnUI(
218 DeviceLightHardwareBuffer
* buffer
) {
219 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
225 base::AutoLock
autolock(light_buffer_lock_
);
226 device_light_buffer_
= buffer
;
227 SetLightBufferValue(-1);
229 bool success
= Start(kTypeLight
);
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();
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
);
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();
271 bool SensorManagerAndroid::StartFetchingDeviceMotionData(
272 DeviceMotionHardwareBuffer
* buffer
) {
273 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
274 StartFetchingMotionDataOnUI(buffer
);
276 BrowserThread::PostTask(
277 BrowserThread::UI
, FROM_HERE
,
278 base::Bind(&SensorManagerAndroid::StartFetchingMotionDataOnUI
,
279 base::Unretained(this),
285 void SensorManagerAndroid::StartFetchingMotionDataOnUI(
286 DeviceMotionHardwareBuffer
* buffer
) {
287 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
293 base::AutoLock
autolock(motion_buffer_lock_
);
294 device_motion_buffer_
= buffer
;
295 ClearInternalMotionBuffers();
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();
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
);
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
]
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
,
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
);
388 BrowserThread::PostTask(
389 BrowserThread::UI
, FROM_HERE
,
390 base::Bind(&SensorManagerAndroid::StartFetchingOrientationDataOnUI
,
391 base::Unretained(this),
397 void SensorManagerAndroid::StartFetchingOrientationDataOnUI(
398 DeviceOrientationHardwareBuffer
* buffer
) {
399 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
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 */);
418 UpdateDeviceOrientationHistogram(NOT_AVAILABLE
);
421 void SensorManagerAndroid::StopFetchingDeviceOrientationData() {
422 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
423 StopFetchingOrientationDataOnUI();
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
);
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
);
453 } // namespace content