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 enum OrientationSensorType
{
24 ACCELEROMETER_MAGNETIC
= 2,
25 ORIENTATION_SENSOR_MAX
= 3,
28 void UpdateDeviceOrientationHistogram(OrientationSensorType type
) {
29 UMA_HISTOGRAM_ENUMERATION("InertialSensor.DeviceOrientationSensorAndroid",
31 ORIENTATION_SENSOR_MAX
);
38 SensorManagerAndroid::SensorManagerAndroid()
39 : number_active_device_motion_sensors_(0),
40 device_light_buffer_(nullptr),
41 device_motion_buffer_(nullptr),
42 device_orientation_buffer_(nullptr),
43 is_light_buffer_ready_(false),
44 is_motion_buffer_ready_(false),
45 is_orientation_buffer_ready_(false),
46 is_using_backup_sensors_for_orientation_(false),
48 memset(received_motion_data_
, 0, sizeof(received_motion_data_
));
49 device_sensors_
.Reset(Java_DeviceSensors_getInstance(
50 AttachCurrentThread(), base::android::GetApplicationContext()));
53 SensorManagerAndroid::~SensorManagerAndroid() {
56 bool SensorManagerAndroid::Register(JNIEnv
* env
) {
57 return RegisterNativesImpl(env
);
60 SensorManagerAndroid
* SensorManagerAndroid::GetInstance() {
61 return Singleton
<SensorManagerAndroid
,
62 LeakySingletonTraits
<SensorManagerAndroid
> >::get();
65 void SensorManagerAndroid::GotOrientation(
66 JNIEnv
*, jobject
, double alpha
, double beta
, double gamma
) {
67 base::AutoLock
autolock(orientation_buffer_lock_
);
69 if (!device_orientation_buffer_
)
72 device_orientation_buffer_
->seqlock
.WriteBegin();
73 device_orientation_buffer_
->data
.alpha
= alpha
;
74 device_orientation_buffer_
->data
.hasAlpha
= true;
75 device_orientation_buffer_
->data
.beta
= beta
;
76 device_orientation_buffer_
->data
.hasBeta
= true;
77 device_orientation_buffer_
->data
.gamma
= gamma
;
78 device_orientation_buffer_
->data
.hasGamma
= true;
79 device_orientation_buffer_
->seqlock
.WriteEnd();
81 if (!is_orientation_buffer_ready_
) {
82 SetOrientationBufferReadyStatus(true);
83 UpdateDeviceOrientationHistogram(is_using_backup_sensors_for_orientation_
84 ? ACCELEROMETER_MAGNETIC
: ROTATION_VECTOR
);
88 void SensorManagerAndroid::GotAcceleration(
89 JNIEnv
*, jobject
, double x
, double y
, double z
) {
90 base::AutoLock
autolock(motion_buffer_lock_
);
92 if (!device_motion_buffer_
)
95 device_motion_buffer_
->seqlock
.WriteBegin();
96 device_motion_buffer_
->data
.accelerationX
= x
;
97 device_motion_buffer_
->data
.hasAccelerationX
= true;
98 device_motion_buffer_
->data
.accelerationY
= y
;
99 device_motion_buffer_
->data
.hasAccelerationY
= true;
100 device_motion_buffer_
->data
.accelerationZ
= z
;
101 device_motion_buffer_
->data
.hasAccelerationZ
= true;
102 device_motion_buffer_
->seqlock
.WriteEnd();
104 if (!is_motion_buffer_ready_
) {
105 received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION
] = 1;
106 CheckMotionBufferReadyToRead();
110 void SensorManagerAndroid::GotAccelerationIncludingGravity(
111 JNIEnv
*, jobject
, double x
, double y
, double z
) {
112 base::AutoLock
autolock(motion_buffer_lock_
);
114 if (!device_motion_buffer_
)
117 device_motion_buffer_
->seqlock
.WriteBegin();
118 device_motion_buffer_
->data
.accelerationIncludingGravityX
= x
;
119 device_motion_buffer_
->data
.hasAccelerationIncludingGravityX
= true;
120 device_motion_buffer_
->data
.accelerationIncludingGravityY
= y
;
121 device_motion_buffer_
->data
.hasAccelerationIncludingGravityY
= true;
122 device_motion_buffer_
->data
.accelerationIncludingGravityZ
= z
;
123 device_motion_buffer_
->data
.hasAccelerationIncludingGravityZ
= true;
124 device_motion_buffer_
->seqlock
.WriteEnd();
126 if (!is_motion_buffer_ready_
) {
127 received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY
] = 1;
128 CheckMotionBufferReadyToRead();
132 void SensorManagerAndroid::GotRotationRate(
133 JNIEnv
*, jobject
, double alpha
, double beta
, double gamma
) {
134 base::AutoLock
autolock(motion_buffer_lock_
);
136 if (!device_motion_buffer_
)
139 device_motion_buffer_
->seqlock
.WriteBegin();
140 device_motion_buffer_
->data
.rotationRateAlpha
= alpha
;
141 device_motion_buffer_
->data
.hasRotationRateAlpha
= true;
142 device_motion_buffer_
->data
.rotationRateBeta
= beta
;
143 device_motion_buffer_
->data
.hasRotationRateBeta
= true;
144 device_motion_buffer_
->data
.rotationRateGamma
= gamma
;
145 device_motion_buffer_
->data
.hasRotationRateGamma
= true;
146 device_motion_buffer_
->seqlock
.WriteEnd();
148 if (!is_motion_buffer_ready_
) {
149 received_motion_data_
[RECEIVED_MOTION_DATA_ROTATION_RATE
] = 1;
150 CheckMotionBufferReadyToRead();
154 void SensorManagerAndroid::GotLight(JNIEnv
*, jobject
, double value
) {
155 base::AutoLock
autolock(light_buffer_lock_
);
157 if (!device_light_buffer_
)
160 device_light_buffer_
->seqlock
.WriteBegin();
161 device_light_buffer_
->data
.value
= value
;
162 device_light_buffer_
->seqlock
.WriteEnd();
165 bool SensorManagerAndroid::Start(EventType event_type
) {
166 DCHECK(!device_sensors_
.is_null());
167 int rate_in_microseconds
= (event_type
== kTypeLight
)
168 ? kLightSensorIntervalMicroseconds
169 : kInertialSensorIntervalMicroseconds
;
170 return Java_DeviceSensors_start(AttachCurrentThread(),
171 device_sensors_
.obj(),
172 reinterpret_cast<intptr_t>(this),
173 static_cast<jint
>(event_type
),
174 rate_in_microseconds
);
177 void SensorManagerAndroid::Stop(EventType event_type
) {
178 DCHECK(!device_sensors_
.is_null());
179 Java_DeviceSensors_stop(AttachCurrentThread(),
180 device_sensors_
.obj(),
181 static_cast<jint
>(event_type
));
184 int SensorManagerAndroid::GetNumberActiveDeviceMotionSensors() {
185 DCHECK(!device_sensors_
.is_null());
186 return Java_DeviceSensors_getNumberActiveDeviceMotionSensors(
187 AttachCurrentThread(), device_sensors_
.obj());
190 bool SensorManagerAndroid::isUsingBackupSensorsForOrientation() {
191 DCHECK(!device_sensors_
.is_null());
192 return Java_DeviceSensors_isUsingBackupSensorsForOrientation(
193 AttachCurrentThread(), device_sensors_
.obj());
196 // ----- Shared memory API methods
200 bool SensorManagerAndroid::StartFetchingDeviceLightData(
201 DeviceLightHardwareBuffer
* buffer
) {
202 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
203 StartFetchingLightDataOnUI(buffer
);
205 BrowserThread::PostTask(
206 BrowserThread::UI
, FROM_HERE
,
207 base::Bind(&SensorManagerAndroid::StartFetchingLightDataOnUI
,
208 base::Unretained(this),
214 void SensorManagerAndroid::StartFetchingLightDataOnUI(
215 DeviceLightHardwareBuffer
* buffer
) {
216 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
222 base::AutoLock
autolock(light_buffer_lock_
);
223 device_light_buffer_
= buffer
;
224 SetLightBufferValue(-1);
226 bool success
= Start(kTypeLight
);
228 base::AutoLock
autolock(light_buffer_lock_
);
229 SetLightBufferValue(std::numeric_limits
<double>::infinity());
233 void SensorManagerAndroid::StopFetchingDeviceLightData() {
234 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
235 StopFetchingLightDataOnUI();
239 BrowserThread::PostTask(
240 BrowserThread::UI
, FROM_HERE
,
241 base::Bind(&SensorManagerAndroid::StopFetchingLightDataOnUI
,
242 base::Unretained(this)));
245 void SensorManagerAndroid::StopFetchingLightDataOnUI() {
246 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
252 base::AutoLock
autolock(light_buffer_lock_
);
253 if (device_light_buffer_
) {
254 SetLightBufferValue(-1);
255 device_light_buffer_
= nullptr;
260 void SensorManagerAndroid::SetLightBufferValue(double lux
) {
261 device_light_buffer_
->seqlock
.WriteBegin();
262 device_light_buffer_
->data
.value
= lux
;
263 device_light_buffer_
->seqlock
.WriteEnd();
268 bool SensorManagerAndroid::StartFetchingDeviceMotionData(
269 DeviceMotionHardwareBuffer
* buffer
) {
270 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
271 StartFetchingMotionDataOnUI(buffer
);
273 BrowserThread::PostTask(
274 BrowserThread::UI
, FROM_HERE
,
275 base::Bind(&SensorManagerAndroid::StartFetchingMotionDataOnUI
,
276 base::Unretained(this),
282 void SensorManagerAndroid::StartFetchingMotionDataOnUI(
283 DeviceMotionHardwareBuffer
* buffer
) {
284 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
290 base::AutoLock
autolock(motion_buffer_lock_
);
291 device_motion_buffer_
= buffer
;
292 ClearInternalMotionBuffers();
296 // If no motion data can ever be provided, the number of active device motion
297 // sensors will be zero. In that case flag the shared memory buffer
298 // as ready to read, as it will not change anyway.
299 number_active_device_motion_sensors_
= GetNumberActiveDeviceMotionSensors();
301 base::AutoLock
autolock(motion_buffer_lock_
);
302 CheckMotionBufferReadyToRead();
306 void SensorManagerAndroid::StopFetchingDeviceMotionData() {
307 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
308 StopFetchingMotionDataOnUI();
312 BrowserThread::PostTask(
313 BrowserThread::UI
, FROM_HERE
,
314 base::Bind(&SensorManagerAndroid::StopFetchingMotionDataOnUI
,
315 base::Unretained(this)));
318 void SensorManagerAndroid::StopFetchingMotionDataOnUI() {
319 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
325 base::AutoLock
autolock(motion_buffer_lock_
);
326 if (device_motion_buffer_
) {
327 ClearInternalMotionBuffers();
328 device_motion_buffer_
= nullptr;
333 void SensorManagerAndroid::CheckMotionBufferReadyToRead() {
334 if (received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION
] +
335 received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY
] +
336 received_motion_data_
[RECEIVED_MOTION_DATA_ROTATION_RATE
] ==
337 number_active_device_motion_sensors_
) {
338 device_motion_buffer_
->seqlock
.WriteBegin();
339 device_motion_buffer_
->data
.interval
=
340 kInertialSensorIntervalMicroseconds
/ 1000.;
341 device_motion_buffer_
->seqlock
.WriteEnd();
342 SetMotionBufferReadyStatus(true);
344 UMA_HISTOGRAM_BOOLEAN("InertialSensor.AccelerometerAndroidAvailable",
345 received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION
] > 0);
346 UMA_HISTOGRAM_BOOLEAN(
347 "InertialSensor.AccelerometerIncGravityAndroidAvailable",
348 received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY
]
350 UMA_HISTOGRAM_BOOLEAN("InertialSensor.GyroscopeAndroidAvailable",
351 received_motion_data_
[RECEIVED_MOTION_DATA_ROTATION_RATE
] > 0);
355 void SensorManagerAndroid::SetMotionBufferReadyStatus(bool ready
) {
356 device_motion_buffer_
->seqlock
.WriteBegin();
357 device_motion_buffer_
->data
.allAvailableSensorsAreActive
= ready
;
358 device_motion_buffer_
->seqlock
.WriteEnd();
359 is_motion_buffer_ready_
= ready
;
362 void SensorManagerAndroid::ClearInternalMotionBuffers() {
363 memset(received_motion_data_
, 0, sizeof(received_motion_data_
));
364 number_active_device_motion_sensors_
= 0;
365 SetMotionBufferReadyStatus(false);
368 // --- Device Orientation
370 void SensorManagerAndroid::SetOrientationBufferReadyStatus(bool ready
) {
371 device_orientation_buffer_
->seqlock
.WriteBegin();
372 device_orientation_buffer_
->data
.absolute
= ready
;
373 device_orientation_buffer_
->data
.hasAbsolute
= ready
;
374 device_orientation_buffer_
->data
.allAvailableSensorsAreActive
= ready
;
375 device_orientation_buffer_
->seqlock
.WriteEnd();
376 is_orientation_buffer_ready_
= ready
;
379 bool SensorManagerAndroid::StartFetchingDeviceOrientationData(
380 DeviceOrientationHardwareBuffer
* buffer
) {
381 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
382 StartFetchingOrientationDataOnUI(buffer
);
384 BrowserThread::PostTask(
385 BrowserThread::UI
, FROM_HERE
,
386 base::Bind(&SensorManagerAndroid::StartFetchingOrientationDataOnUI
,
387 base::Unretained(this),
393 void SensorManagerAndroid::StartFetchingOrientationDataOnUI(
394 DeviceOrientationHardwareBuffer
* buffer
) {
395 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
401 base::AutoLock
autolock(orientation_buffer_lock_
);
402 device_orientation_buffer_
= buffer
;
404 bool success
= Start(kTypeOrientation
);
407 base::AutoLock
autolock(orientation_buffer_lock_
);
408 // If Start() was unsuccessful then set the buffer ready flag to true
409 // to start firing all-null events.
410 SetOrientationBufferReadyStatus(!success
);
414 UpdateDeviceOrientationHistogram(NOT_AVAILABLE
);
416 is_using_backup_sensors_for_orientation_
=
417 isUsingBackupSensorsForOrientation();
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 SetOrientationBufferReadyStatus(false);
443 device_orientation_buffer_
= nullptr;
448 void SensorManagerAndroid::Shutdown() {
449 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
453 } // namespace content