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/memory/singleton.h"
11 #include "base/metrics/histogram.h"
12 #include "content/browser/device_sensors/inertial_sensor_consts.h"
13 #include "jni/DeviceSensors_jni.h"
15 using base::android::AttachCurrentThread
;
19 enum OrientationSensorType
{
22 ACCELEROMETER_MAGNETIC
= 2,
23 ORIENTATION_SENSOR_MAX
= 3,
26 static void UpdateDeviceOrientationHistogram(OrientationSensorType type
) {
27 UMA_HISTOGRAM_ENUMERATION("InertialSensor.DeviceOrientationSensorAndroid",
29 ORIENTATION_SENSOR_MAX
);
36 SensorManagerAndroid::SensorManagerAndroid()
37 : number_active_device_motion_sensors_(0),
38 device_light_buffer_(NULL
),
39 device_motion_buffer_(NULL
),
40 device_orientation_buffer_(NULL
),
41 is_light_buffer_ready_(false),
42 is_motion_buffer_ready_(false),
43 is_orientation_buffer_ready_(false),
44 is_using_backup_sensors_for_orientation_(false) {
45 memset(received_motion_data_
, 0, sizeof(received_motion_data_
));
46 device_sensors_
.Reset(Java_DeviceSensors_getInstance(
47 AttachCurrentThread(), base::android::GetApplicationContext()));
50 SensorManagerAndroid::~SensorManagerAndroid() {
53 bool SensorManagerAndroid::Register(JNIEnv
* env
) {
54 return RegisterNativesImpl(env
);
57 SensorManagerAndroid
* SensorManagerAndroid::GetInstance() {
58 return Singleton
<SensorManagerAndroid
,
59 LeakySingletonTraits
<SensorManagerAndroid
> >::get();
62 void SensorManagerAndroid::GotOrientation(
63 JNIEnv
*, jobject
, double alpha
, double beta
, double gamma
) {
64 base::AutoLock
autolock(orientation_buffer_lock_
);
66 if (!device_orientation_buffer_
)
69 device_orientation_buffer_
->seqlock
.WriteBegin();
70 device_orientation_buffer_
->data
.alpha
= alpha
;
71 device_orientation_buffer_
->data
.hasAlpha
= true;
72 device_orientation_buffer_
->data
.beta
= beta
;
73 device_orientation_buffer_
->data
.hasBeta
= true;
74 device_orientation_buffer_
->data
.gamma
= gamma
;
75 device_orientation_buffer_
->data
.hasGamma
= true;
76 device_orientation_buffer_
->seqlock
.WriteEnd();
78 if (!is_orientation_buffer_ready_
) {
79 SetOrientationBufferReadyStatus(true);
80 UpdateDeviceOrientationHistogram(is_using_backup_sensors_for_orientation_
81 ? ACCELEROMETER_MAGNETIC
: ROTATION_VECTOR
);
85 void SensorManagerAndroid::GotAcceleration(
86 JNIEnv
*, jobject
, double x
, double y
, double z
) {
87 base::AutoLock
autolock(motion_buffer_lock_
);
89 if (!device_motion_buffer_
)
92 device_motion_buffer_
->seqlock
.WriteBegin();
93 device_motion_buffer_
->data
.accelerationX
= x
;
94 device_motion_buffer_
->data
.hasAccelerationX
= true;
95 device_motion_buffer_
->data
.accelerationY
= y
;
96 device_motion_buffer_
->data
.hasAccelerationY
= true;
97 device_motion_buffer_
->data
.accelerationZ
= z
;
98 device_motion_buffer_
->data
.hasAccelerationZ
= true;
99 device_motion_buffer_
->seqlock
.WriteEnd();
101 if (!is_motion_buffer_ready_
) {
102 received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION
] = 1;
103 CheckMotionBufferReadyToRead();
107 void SensorManagerAndroid::GotAccelerationIncludingGravity(
108 JNIEnv
*, jobject
, double x
, double y
, double z
) {
109 base::AutoLock
autolock(motion_buffer_lock_
);
111 if (!device_motion_buffer_
)
114 device_motion_buffer_
->seqlock
.WriteBegin();
115 device_motion_buffer_
->data
.accelerationIncludingGravityX
= x
;
116 device_motion_buffer_
->data
.hasAccelerationIncludingGravityX
= true;
117 device_motion_buffer_
->data
.accelerationIncludingGravityY
= y
;
118 device_motion_buffer_
->data
.hasAccelerationIncludingGravityY
= true;
119 device_motion_buffer_
->data
.accelerationIncludingGravityZ
= z
;
120 device_motion_buffer_
->data
.hasAccelerationIncludingGravityZ
= true;
121 device_motion_buffer_
->seqlock
.WriteEnd();
123 if (!is_motion_buffer_ready_
) {
124 received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY
] = 1;
125 CheckMotionBufferReadyToRead();
129 void SensorManagerAndroid::GotRotationRate(
130 JNIEnv
*, jobject
, double alpha
, double beta
, double gamma
) {
131 base::AutoLock
autolock(motion_buffer_lock_
);
133 if (!device_motion_buffer_
)
136 device_motion_buffer_
->seqlock
.WriteBegin();
137 device_motion_buffer_
->data
.rotationRateAlpha
= alpha
;
138 device_motion_buffer_
->data
.hasRotationRateAlpha
= true;
139 device_motion_buffer_
->data
.rotationRateBeta
= beta
;
140 device_motion_buffer_
->data
.hasRotationRateBeta
= true;
141 device_motion_buffer_
->data
.rotationRateGamma
= gamma
;
142 device_motion_buffer_
->data
.hasRotationRateGamma
= true;
143 device_motion_buffer_
->seqlock
.WriteEnd();
145 if (!is_motion_buffer_ready_
) {
146 received_motion_data_
[RECEIVED_MOTION_DATA_ROTATION_RATE
] = 1;
147 CheckMotionBufferReadyToRead();
151 void SensorManagerAndroid::GotLight(JNIEnv
*, jobject
, double value
) {
152 base::AutoLock
autolock(light_buffer_lock_
);
154 if (!device_light_buffer_
)
157 device_light_buffer_
->seqlock
.WriteBegin();
158 device_light_buffer_
->data
.value
= value
;
159 device_light_buffer_
->seqlock
.WriteEnd();
162 bool SensorManagerAndroid::Start(EventType event_type
) {
163 DCHECK(!device_sensors_
.is_null());
164 int rate_in_microseconds
= (event_type
== kTypeLight
)
165 ? kLightSensorIntervalMicroseconds
166 : kInertialSensorIntervalMicroseconds
;
167 return Java_DeviceSensors_start(AttachCurrentThread(),
168 device_sensors_
.obj(),
169 reinterpret_cast<intptr_t>(this),
170 static_cast<jint
>(event_type
),
171 rate_in_microseconds
);
174 void SensorManagerAndroid::Stop(EventType event_type
) {
175 DCHECK(!device_sensors_
.is_null());
176 Java_DeviceSensors_stop(AttachCurrentThread(),
177 device_sensors_
.obj(),
178 static_cast<jint
>(event_type
));
181 int SensorManagerAndroid::GetNumberActiveDeviceMotionSensors() {
182 DCHECK(!device_sensors_
.is_null());
183 return Java_DeviceSensors_getNumberActiveDeviceMotionSensors(
184 AttachCurrentThread(), device_sensors_
.obj());
187 bool SensorManagerAndroid::isUsingBackupSensorsForOrientation() {
188 DCHECK(!device_sensors_
.is_null());
189 return Java_DeviceSensors_isUsingBackupSensorsForOrientation(
190 AttachCurrentThread(), device_sensors_
.obj());
193 // ----- Shared memory API methods
197 bool SensorManagerAndroid::StartFetchingDeviceLightData(
198 DeviceLightHardwareBuffer
* buffer
) {
201 base::AutoLock
autolock(light_buffer_lock_
);
202 device_light_buffer_
= buffer
;
203 SetLightBufferValue(-1);
205 bool success
= Start(kTypeLight
);
207 base::AutoLock
autolock(light_buffer_lock_
);
208 SetLightBufferValue(std::numeric_limits
<double>::infinity());
213 void SensorManagerAndroid::StopFetchingDeviceLightData() {
216 base::AutoLock
autolock(light_buffer_lock_
);
217 if (device_light_buffer_
) {
218 SetLightBufferValue(-1);
219 device_light_buffer_
= NULL
;
224 void SensorManagerAndroid::SetLightBufferValue(double lux
) {
225 device_light_buffer_
->seqlock
.WriteBegin();
226 device_light_buffer_
->data
.value
= lux
;
227 device_light_buffer_
->seqlock
.WriteEnd();
231 bool SensorManagerAndroid::StartFetchingDeviceMotionData(
232 DeviceMotionHardwareBuffer
* buffer
) {
235 base::AutoLock
autolock(motion_buffer_lock_
);
236 device_motion_buffer_
= buffer
;
237 ClearInternalMotionBuffers();
239 bool success
= Start(kTypeMotion
);
241 // If no motion data can ever be provided, the number of active device motion
242 // sensors will be zero. In that case flag the shared memory buffer
243 // as ready to read, as it will not change anyway.
244 number_active_device_motion_sensors_
= GetNumberActiveDeviceMotionSensors();
246 base::AutoLock
autolock(motion_buffer_lock_
);
247 CheckMotionBufferReadyToRead();
252 void SensorManagerAndroid::StopFetchingDeviceMotionData() {
255 base::AutoLock
autolock(motion_buffer_lock_
);
256 if (device_motion_buffer_
) {
257 ClearInternalMotionBuffers();
258 device_motion_buffer_
= NULL
;
263 void SensorManagerAndroid::CheckMotionBufferReadyToRead() {
264 if (received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION
] +
265 received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY
] +
266 received_motion_data_
[RECEIVED_MOTION_DATA_ROTATION_RATE
] ==
267 number_active_device_motion_sensors_
) {
268 device_motion_buffer_
->seqlock
.WriteBegin();
269 device_motion_buffer_
->data
.interval
=
270 kInertialSensorIntervalMicroseconds
/ 1000.;
271 device_motion_buffer_
->seqlock
.WriteEnd();
272 SetMotionBufferReadyStatus(true);
274 UMA_HISTOGRAM_BOOLEAN("InertialSensor.AccelerometerAndroidAvailable",
275 received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION
] > 0);
276 UMA_HISTOGRAM_BOOLEAN(
277 "InertialSensor.AccelerometerIncGravityAndroidAvailable",
278 received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY
]
280 UMA_HISTOGRAM_BOOLEAN("InertialSensor.GyroscopeAndroidAvailable",
281 received_motion_data_
[RECEIVED_MOTION_DATA_ROTATION_RATE
] > 0);
285 void SensorManagerAndroid::SetMotionBufferReadyStatus(bool ready
) {
286 device_motion_buffer_
->seqlock
.WriteBegin();
287 device_motion_buffer_
->data
.allAvailableSensorsAreActive
= ready
;
288 device_motion_buffer_
->seqlock
.WriteEnd();
289 is_motion_buffer_ready_
= ready
;
292 void SensorManagerAndroid::ClearInternalMotionBuffers() {
293 memset(received_motion_data_
, 0, sizeof(received_motion_data_
));
294 number_active_device_motion_sensors_
= 0;
295 SetMotionBufferReadyStatus(false);
298 // --- Device Orientation
300 void SensorManagerAndroid::SetOrientationBufferReadyStatus(bool ready
) {
301 device_orientation_buffer_
->seqlock
.WriteBegin();
302 device_orientation_buffer_
->data
.absolute
= ready
;
303 device_orientation_buffer_
->data
.hasAbsolute
= ready
;
304 device_orientation_buffer_
->data
.allAvailableSensorsAreActive
= ready
;
305 device_orientation_buffer_
->seqlock
.WriteEnd();
306 is_orientation_buffer_ready_
= ready
;
309 bool SensorManagerAndroid::StartFetchingDeviceOrientationData(
310 DeviceOrientationHardwareBuffer
* buffer
) {
313 base::AutoLock
autolock(orientation_buffer_lock_
);
314 device_orientation_buffer_
= buffer
;
316 bool success
= Start(kTypeOrientation
);
319 base::AutoLock
autolock(orientation_buffer_lock_
);
320 // If Start() was unsuccessful then set the buffer ready flag to true
321 // to start firing all-null events.
322 SetOrientationBufferReadyStatus(!success
);
326 UpdateDeviceOrientationHistogram(NOT_AVAILABLE
);
328 is_using_backup_sensors_for_orientation_
=
329 isUsingBackupSensorsForOrientation();
335 void SensorManagerAndroid::StopFetchingDeviceOrientationData() {
336 Stop(kTypeOrientation
);
338 base::AutoLock
autolock(orientation_buffer_lock_
);
339 if (device_orientation_buffer_
) {
340 SetOrientationBufferReadyStatus(false);
341 device_orientation_buffer_
= NULL
;
346 } // namespace content