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 static void updateRotationVectorHistogram(bool value
) {
20 UMA_HISTOGRAM_BOOLEAN("InertialSensor.RotationVectorAndroidAvailable", value
);
27 SensorManagerAndroid::SensorManagerAndroid()
28 : number_active_device_motion_sensors_(0),
29 device_light_buffer_(NULL
),
30 device_motion_buffer_(NULL
),
31 device_orientation_buffer_(NULL
),
32 is_light_buffer_ready_(false),
33 is_motion_buffer_ready_(false),
34 is_orientation_buffer_ready_(false),
35 is_using_backup_sensors_for_orientation_(false) {
36 memset(received_motion_data_
, 0, sizeof(received_motion_data_
));
37 device_sensors_
.Reset(Java_DeviceSensors_getInstance(
38 AttachCurrentThread(), base::android::GetApplicationContext()));
41 SensorManagerAndroid::~SensorManagerAndroid() {
44 bool SensorManagerAndroid::Register(JNIEnv
* env
) {
45 return RegisterNativesImpl(env
);
48 SensorManagerAndroid
* SensorManagerAndroid::GetInstance() {
49 return Singleton
<SensorManagerAndroid
,
50 LeakySingletonTraits
<SensorManagerAndroid
> >::get();
53 void SensorManagerAndroid::GotOrientation(
54 JNIEnv
*, jobject
, double alpha
, double beta
, double gamma
) {
55 base::AutoLock
autolock(orientation_buffer_lock_
);
57 if (!device_orientation_buffer_
)
60 device_orientation_buffer_
->seqlock
.WriteBegin();
61 device_orientation_buffer_
->data
.alpha
= alpha
;
62 device_orientation_buffer_
->data
.hasAlpha
= true;
63 device_orientation_buffer_
->data
.beta
= beta
;
64 device_orientation_buffer_
->data
.hasBeta
= true;
65 device_orientation_buffer_
->data
.gamma
= gamma
;
66 device_orientation_buffer_
->data
.hasGamma
= true;
67 device_orientation_buffer_
->seqlock
.WriteEnd();
69 if (!is_orientation_buffer_ready_
) {
70 SetOrientationBufferReadyStatus(true);
71 updateRotationVectorHistogram(!is_using_backup_sensors_for_orientation_
);
75 void SensorManagerAndroid::GotAcceleration(
76 JNIEnv
*, jobject
, double x
, double y
, double z
) {
77 base::AutoLock
autolock(motion_buffer_lock_
);
79 if (!device_motion_buffer_
)
82 device_motion_buffer_
->seqlock
.WriteBegin();
83 device_motion_buffer_
->data
.accelerationX
= x
;
84 device_motion_buffer_
->data
.hasAccelerationX
= true;
85 device_motion_buffer_
->data
.accelerationY
= y
;
86 device_motion_buffer_
->data
.hasAccelerationY
= true;
87 device_motion_buffer_
->data
.accelerationZ
= z
;
88 device_motion_buffer_
->data
.hasAccelerationZ
= true;
89 device_motion_buffer_
->seqlock
.WriteEnd();
91 if (!is_motion_buffer_ready_
) {
92 received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION
] = 1;
93 CheckMotionBufferReadyToRead();
97 void SensorManagerAndroid::GotAccelerationIncludingGravity(
98 JNIEnv
*, jobject
, double x
, double y
, double z
) {
99 base::AutoLock
autolock(motion_buffer_lock_
);
101 if (!device_motion_buffer_
)
104 device_motion_buffer_
->seqlock
.WriteBegin();
105 device_motion_buffer_
->data
.accelerationIncludingGravityX
= x
;
106 device_motion_buffer_
->data
.hasAccelerationIncludingGravityX
= true;
107 device_motion_buffer_
->data
.accelerationIncludingGravityY
= y
;
108 device_motion_buffer_
->data
.hasAccelerationIncludingGravityY
= true;
109 device_motion_buffer_
->data
.accelerationIncludingGravityZ
= z
;
110 device_motion_buffer_
->data
.hasAccelerationIncludingGravityZ
= true;
111 device_motion_buffer_
->seqlock
.WriteEnd();
113 if (!is_motion_buffer_ready_
) {
114 received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY
] = 1;
115 CheckMotionBufferReadyToRead();
119 void SensorManagerAndroid::GotRotationRate(
120 JNIEnv
*, jobject
, double alpha
, double beta
, double gamma
) {
121 base::AutoLock
autolock(motion_buffer_lock_
);
123 if (!device_motion_buffer_
)
126 device_motion_buffer_
->seqlock
.WriteBegin();
127 device_motion_buffer_
->data
.rotationRateAlpha
= alpha
;
128 device_motion_buffer_
->data
.hasRotationRateAlpha
= true;
129 device_motion_buffer_
->data
.rotationRateBeta
= beta
;
130 device_motion_buffer_
->data
.hasRotationRateBeta
= true;
131 device_motion_buffer_
->data
.rotationRateGamma
= gamma
;
132 device_motion_buffer_
->data
.hasRotationRateGamma
= true;
133 device_motion_buffer_
->seqlock
.WriteEnd();
135 if (!is_motion_buffer_ready_
) {
136 received_motion_data_
[RECEIVED_MOTION_DATA_ROTATION_RATE
] = 1;
137 CheckMotionBufferReadyToRead();
141 void SensorManagerAndroid::GotLight(JNIEnv
*, jobject
, double value
) {
142 base::AutoLock
autolock(light_buffer_lock_
);
144 if (!device_light_buffer_
)
147 device_light_buffer_
->seqlock
.WriteBegin();
148 device_light_buffer_
->data
.value
= value
;
149 device_light_buffer_
->seqlock
.WriteEnd();
152 bool SensorManagerAndroid::Start(EventType event_type
) {
153 DCHECK(!device_sensors_
.is_null());
154 int rate_in_microseconds
= (event_type
== kTypeLight
)
155 ? kLightSensorIntervalMicroseconds
156 : kInertialSensorIntervalMicroseconds
;
157 return Java_DeviceSensors_start(AttachCurrentThread(),
158 device_sensors_
.obj(),
159 reinterpret_cast<intptr_t>(this),
160 static_cast<jint
>(event_type
),
161 rate_in_microseconds
);
164 void SensorManagerAndroid::Stop(EventType event_type
) {
165 DCHECK(!device_sensors_
.is_null());
166 Java_DeviceSensors_stop(AttachCurrentThread(),
167 device_sensors_
.obj(),
168 static_cast<jint
>(event_type
));
171 int SensorManagerAndroid::GetNumberActiveDeviceMotionSensors() {
172 DCHECK(!device_sensors_
.is_null());
173 return Java_DeviceSensors_getNumberActiveDeviceMotionSensors(
174 AttachCurrentThread(), device_sensors_
.obj());
177 bool SensorManagerAndroid::isUsingBackupSensorsForOrientation() {
178 DCHECK(!device_sensors_
.is_null());
179 return Java_DeviceSensors_isUsingBackupSensorsForOrientation(
180 AttachCurrentThread(), device_sensors_
.obj());
183 // ----- Shared memory API methods
187 bool SensorManagerAndroid::StartFetchingDeviceLightData(
188 DeviceLightHardwareBuffer
* buffer
) {
191 base::AutoLock
autolock(light_buffer_lock_
);
192 device_light_buffer_
= buffer
;
193 SetLightBufferValue(-1);
195 bool success
= Start(kTypeLight
);
197 base::AutoLock
autolock(light_buffer_lock_
);
198 SetLightBufferValue(std::numeric_limits
<double>::infinity());
203 void SensorManagerAndroid::StopFetchingDeviceLightData() {
206 base::AutoLock
autolock(light_buffer_lock_
);
207 if (device_light_buffer_
) {
208 SetLightBufferValue(-1);
209 device_light_buffer_
= NULL
;
214 void SensorManagerAndroid::SetLightBufferValue(double lux
) {
215 device_light_buffer_
->seqlock
.WriteBegin();
216 device_light_buffer_
->data
.value
= lux
;
217 device_light_buffer_
->seqlock
.WriteEnd();
221 bool SensorManagerAndroid::StartFetchingDeviceMotionData(
222 DeviceMotionHardwareBuffer
* buffer
) {
225 base::AutoLock
autolock(motion_buffer_lock_
);
226 device_motion_buffer_
= buffer
;
227 ClearInternalMotionBuffers();
229 bool success
= Start(kTypeMotion
);
231 // If no motion data can ever be provided, the number of active device motion
232 // sensors will be zero. In that case flag the shared memory buffer
233 // as ready to read, as it will not change anyway.
234 number_active_device_motion_sensors_
= GetNumberActiveDeviceMotionSensors();
236 base::AutoLock
autolock(motion_buffer_lock_
);
237 CheckMotionBufferReadyToRead();
242 void SensorManagerAndroid::StopFetchingDeviceMotionData() {
245 base::AutoLock
autolock(motion_buffer_lock_
);
246 if (device_motion_buffer_
) {
247 ClearInternalMotionBuffers();
248 device_motion_buffer_
= NULL
;
253 void SensorManagerAndroid::CheckMotionBufferReadyToRead() {
254 if (received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION
] +
255 received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY
] +
256 received_motion_data_
[RECEIVED_MOTION_DATA_ROTATION_RATE
] ==
257 number_active_device_motion_sensors_
) {
258 device_motion_buffer_
->seqlock
.WriteBegin();
259 device_motion_buffer_
->data
.interval
=
260 kInertialSensorIntervalMicroseconds
/ 1000.;
261 device_motion_buffer_
->seqlock
.WriteEnd();
262 SetMotionBufferReadyStatus(true);
264 UMA_HISTOGRAM_BOOLEAN("InertialSensor.AccelerometerAndroidAvailable",
265 received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION
] > 0);
266 UMA_HISTOGRAM_BOOLEAN(
267 "InertialSensor.AccelerometerIncGravityAndroidAvailable",
268 received_motion_data_
[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY
]
270 UMA_HISTOGRAM_BOOLEAN("InertialSensor.GyroscopeAndroidAvailable",
271 received_motion_data_
[RECEIVED_MOTION_DATA_ROTATION_RATE
] > 0);
275 void SensorManagerAndroid::SetMotionBufferReadyStatus(bool ready
) {
276 device_motion_buffer_
->seqlock
.WriteBegin();
277 device_motion_buffer_
->data
.allAvailableSensorsAreActive
= ready
;
278 device_motion_buffer_
->seqlock
.WriteEnd();
279 is_motion_buffer_ready_
= ready
;
282 void SensorManagerAndroid::ClearInternalMotionBuffers() {
283 memset(received_motion_data_
, 0, sizeof(received_motion_data_
));
284 number_active_device_motion_sensors_
= 0;
285 SetMotionBufferReadyStatus(false);
288 // --- Device Orientation
290 void SensorManagerAndroid::SetOrientationBufferReadyStatus(bool ready
) {
291 device_orientation_buffer_
->seqlock
.WriteBegin();
292 device_orientation_buffer_
->data
.absolute
= ready
;
293 device_orientation_buffer_
->data
.hasAbsolute
= ready
;
294 device_orientation_buffer_
->data
.allAvailableSensorsAreActive
= ready
;
295 device_orientation_buffer_
->seqlock
.WriteEnd();
296 is_orientation_buffer_ready_
= ready
;
299 bool SensorManagerAndroid::StartFetchingDeviceOrientationData(
300 DeviceOrientationHardwareBuffer
* buffer
) {
303 base::AutoLock
autolock(orientation_buffer_lock_
);
304 device_orientation_buffer_
= buffer
;
306 bool success
= Start(kTypeOrientation
);
309 base::AutoLock
autolock(orientation_buffer_lock_
);
310 // If Start() was unsuccessful then set the buffer ready flag to true
311 // to start firing all-null events.
312 SetOrientationBufferReadyStatus(!success
);
316 updateRotationVectorHistogram(false);
318 is_using_backup_sensors_for_orientation_
=
319 isUsingBackupSensorsForOrientation();
324 void SensorManagerAndroid::StopFetchingDeviceOrientationData() {
325 Stop(kTypeOrientation
);
327 base::AutoLock
autolock(orientation_buffer_lock_
);
328 if (device_orientation_buffer_
) {
329 SetOrientationBufferReadyStatus(false);
330 device_orientation_buffer_
= NULL
;
335 } // namespace content