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. 4 5 #include "content/browser/device_sensors/sensor_manager_android.h" 6 7 #include <string.h> 8 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" 14 15 using base::android::AttachCurrentThread; 16 17 namespace { 18 19 static void updateRotationVectorHistogram(bool value) { 20 UMA_HISTOGRAM_BOOLEAN("InertialSensor.RotationVectorAndroidAvailable", value); 21 } 22 23 } 24 25 namespace content { 26 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 memset(received_motion_data_, 0, sizeof(received_motion_data_)); 36 device_sensors_.Reset(Java_DeviceSensors_getInstance( 37 AttachCurrentThread(), base::android::GetApplicationContext())); 38 } 39 40 SensorManagerAndroid::~SensorManagerAndroid() { 41 } 42 43 bool SensorManagerAndroid::Register(JNIEnv* env) { 44 return RegisterNativesImpl(env); 45 } 46 47 SensorManagerAndroid* SensorManagerAndroid::GetInstance() { 48 return Singleton<SensorManagerAndroid, 49 LeakySingletonTraits<SensorManagerAndroid> >::get(); 50 } 51 52 void SensorManagerAndroid::GotOrientation( 53 JNIEnv*, jobject, double alpha, double beta, double gamma) { 54 base::AutoLock autolock(orientation_buffer_lock_); 55 56 if (!device_orientation_buffer_) 57 return; 58 59 device_orientation_buffer_->seqlock.WriteBegin(); 60 device_orientation_buffer_->data.alpha = alpha; 61 device_orientation_buffer_->data.hasAlpha = true; 62 device_orientation_buffer_->data.beta = beta; 63 device_orientation_buffer_->data.hasBeta = true; 64 device_orientation_buffer_->data.gamma = gamma; 65 device_orientation_buffer_->data.hasGamma = true; 66 device_orientation_buffer_->seqlock.WriteEnd(); 67 68 if (!is_orientation_buffer_ready_) { 69 SetOrientationBufferReadyStatus(true); 70 updateRotationVectorHistogram(true); 71 } 72 } 73 74 void SensorManagerAndroid::GotAcceleration( 75 JNIEnv*, jobject, double x, double y, double z) { 76 base::AutoLock autolock(motion_buffer_lock_); 77 78 if (!device_motion_buffer_) 79 return; 80 81 device_motion_buffer_->seqlock.WriteBegin(); 82 device_motion_buffer_->data.accelerationX = x; 83 device_motion_buffer_->data.hasAccelerationX = true; 84 device_motion_buffer_->data.accelerationY = y; 85 device_motion_buffer_->data.hasAccelerationY = true; 86 device_motion_buffer_->data.accelerationZ = z; 87 device_motion_buffer_->data.hasAccelerationZ = true; 88 device_motion_buffer_->seqlock.WriteEnd(); 89 90 if (!is_motion_buffer_ready_) { 91 received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION] = 1; 92 CheckMotionBufferReadyToRead(); 93 } 94 } 95 96 void SensorManagerAndroid::GotAccelerationIncludingGravity( 97 JNIEnv*, jobject, double x, double y, double z) { 98 base::AutoLock autolock(motion_buffer_lock_); 99 100 if (!device_motion_buffer_) 101 return; 102 103 device_motion_buffer_->seqlock.WriteBegin(); 104 device_motion_buffer_->data.accelerationIncludingGravityX = x; 105 device_motion_buffer_->data.hasAccelerationIncludingGravityX = true; 106 device_motion_buffer_->data.accelerationIncludingGravityY = y; 107 device_motion_buffer_->data.hasAccelerationIncludingGravityY = true; 108 device_motion_buffer_->data.accelerationIncludingGravityZ = z; 109 device_motion_buffer_->data.hasAccelerationIncludingGravityZ = true; 110 device_motion_buffer_->seqlock.WriteEnd(); 111 112 if (!is_motion_buffer_ready_) { 113 received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY] = 1; 114 CheckMotionBufferReadyToRead(); 115 } 116 } 117 118 void SensorManagerAndroid::GotRotationRate( 119 JNIEnv*, jobject, double alpha, double beta, double gamma) { 120 base::AutoLock autolock(motion_buffer_lock_); 121 122 if (!device_motion_buffer_) 123 return; 124 125 device_motion_buffer_->seqlock.WriteBegin(); 126 device_motion_buffer_->data.rotationRateAlpha = alpha; 127 device_motion_buffer_->data.hasRotationRateAlpha = true; 128 device_motion_buffer_->data.rotationRateBeta = beta; 129 device_motion_buffer_->data.hasRotationRateBeta = true; 130 device_motion_buffer_->data.rotationRateGamma = gamma; 131 device_motion_buffer_->data.hasRotationRateGamma = true; 132 device_motion_buffer_->seqlock.WriteEnd(); 133 134 if (!is_motion_buffer_ready_) { 135 received_motion_data_[RECEIVED_MOTION_DATA_ROTATION_RATE] = 1; 136 CheckMotionBufferReadyToRead(); 137 } 138 } 139 140 void SensorManagerAndroid::GotLight(JNIEnv*, jobject, double value) { 141 base::AutoLock autolock(light_buffer_lock_); 142 143 if (!device_light_buffer_) 144 return; 145 146 device_light_buffer_->seqlock.WriteBegin(); 147 device_light_buffer_->data.value = value; 148 device_light_buffer_->seqlock.WriteEnd(); 149 } 150 151 bool SensorManagerAndroid::Start(EventType event_type) { 152 DCHECK(!device_sensors_.is_null()); 153 int rate_in_milliseconds = (event_type == kTypeLight) 154 ? kLightSensorIntervalMillis 155 : kInertialSensorIntervalMillis; 156 return Java_DeviceSensors_start(AttachCurrentThread(), 157 device_sensors_.obj(), 158 reinterpret_cast<intptr_t>(this), 159 static_cast<jint>(event_type), 160 rate_in_milliseconds); 161 } 162 163 void SensorManagerAndroid::Stop(EventType event_type) { 164 DCHECK(!device_sensors_.is_null()); 165 Java_DeviceSensors_stop(AttachCurrentThread(), 166 device_sensors_.obj(), 167 static_cast<jint>(event_type)); 168 } 169 170 int SensorManagerAndroid::GetNumberActiveDeviceMotionSensors() { 171 DCHECK(!device_sensors_.is_null()); 172 return Java_DeviceSensors_getNumberActiveDeviceMotionSensors( 173 AttachCurrentThread(), device_sensors_.obj()); 174 } 175 176 177 // ----- Shared memory API methods 178 179 // --- Device Light 180 181 bool SensorManagerAndroid::StartFetchingDeviceLightData( 182 DeviceLightHardwareBuffer* buffer) { 183 DCHECK(buffer); 184 { 185 base::AutoLock autolock(light_buffer_lock_); 186 device_light_buffer_ = buffer; 187 SetLightBufferValue(-1); 188 } 189 bool success = Start(kTypeLight); 190 if (!success) { 191 base::AutoLock autolock(light_buffer_lock_); 192 SetLightBufferValue(std::numeric_limits<double>::infinity()); 193 } 194 return success; 195 } 196 197 void SensorManagerAndroid::StopFetchingDeviceLightData() { 198 Stop(kTypeLight); 199 { 200 base::AutoLock autolock(light_buffer_lock_); 201 if (device_light_buffer_) { 202 SetLightBufferValue(-1); 203 device_light_buffer_ = NULL; 204 } 205 } 206 } 207 208 void SensorManagerAndroid::SetLightBufferValue(double lux) { 209 device_light_buffer_->seqlock.WriteBegin(); 210 device_light_buffer_->data.value = lux; 211 device_light_buffer_->seqlock.WriteEnd(); 212 } 213 // --- Device Motion 214 215 bool SensorManagerAndroid::StartFetchingDeviceMotionData( 216 DeviceMotionHardwareBuffer* buffer) { 217 DCHECK(buffer); 218 { 219 base::AutoLock autolock(motion_buffer_lock_); 220 device_motion_buffer_ = buffer; 221 ClearInternalMotionBuffers(); 222 } 223 bool success = Start(kTypeMotion); 224 225 // If no motion data can ever be provided, the number of active device motion 226 // sensors will be zero. In that case flag the shared memory buffer 227 // as ready to read, as it will not change anyway. 228 number_active_device_motion_sensors_ = GetNumberActiveDeviceMotionSensors(); 229 { 230 base::AutoLock autolock(motion_buffer_lock_); 231 CheckMotionBufferReadyToRead(); 232 } 233 return success; 234 } 235 236 void SensorManagerAndroid::StopFetchingDeviceMotionData() { 237 Stop(kTypeMotion); 238 { 239 base::AutoLock autolock(motion_buffer_lock_); 240 if (device_motion_buffer_) { 241 ClearInternalMotionBuffers(); 242 device_motion_buffer_ = NULL; 243 } 244 } 245 } 246 247 void SensorManagerAndroid::CheckMotionBufferReadyToRead() { 248 if (received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION] + 249 received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY] + 250 received_motion_data_[RECEIVED_MOTION_DATA_ROTATION_RATE] == 251 number_active_device_motion_sensors_) { 252 device_motion_buffer_->seqlock.WriteBegin(); 253 device_motion_buffer_->data.interval = kInertialSensorIntervalMillis; 254 device_motion_buffer_->seqlock.WriteEnd(); 255 SetMotionBufferReadyStatus(true); 256 257 UMA_HISTOGRAM_BOOLEAN("InertialSensor.AccelerometerAndroidAvailable", 258 received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION] > 0); 259 UMA_HISTOGRAM_BOOLEAN( 260 "InertialSensor.AccelerometerIncGravityAndroidAvailable", 261 received_motion_data_[RECEIVED_MOTION_DATA_ACCELERATION_INCL_GRAVITY] 262 > 0); 263 UMA_HISTOGRAM_BOOLEAN("InertialSensor.GyroscopeAndroidAvailable", 264 received_motion_data_[RECEIVED_MOTION_DATA_ROTATION_RATE] > 0); 265 } 266 } 267 268 void SensorManagerAndroid::SetMotionBufferReadyStatus(bool ready) { 269 device_motion_buffer_->seqlock.WriteBegin(); 270 device_motion_buffer_->data.allAvailableSensorsAreActive = ready; 271 device_motion_buffer_->seqlock.WriteEnd(); 272 is_motion_buffer_ready_ = ready; 273 } 274 275 void SensorManagerAndroid::ClearInternalMotionBuffers() { 276 memset(received_motion_data_, 0, sizeof(received_motion_data_)); 277 number_active_device_motion_sensors_ = 0; 278 SetMotionBufferReadyStatus(false); 279 } 280 281 // --- Device Orientation 282 283 void SensorManagerAndroid::SetOrientationBufferReadyStatus(bool ready) { 284 device_orientation_buffer_->seqlock.WriteBegin(); 285 device_orientation_buffer_->data.absolute = ready; 286 device_orientation_buffer_->data.hasAbsolute = ready; 287 device_orientation_buffer_->data.allAvailableSensorsAreActive = ready; 288 device_orientation_buffer_->seqlock.WriteEnd(); 289 is_orientation_buffer_ready_ = ready; 290 } 291 292 bool SensorManagerAndroid::StartFetchingDeviceOrientationData( 293 DeviceOrientationHardwareBuffer* buffer) { 294 DCHECK(buffer); 295 { 296 base::AutoLock autolock(orientation_buffer_lock_); 297 device_orientation_buffer_ = buffer; 298 } 299 bool success = Start(kTypeOrientation); 300 301 { 302 base::AutoLock autolock(orientation_buffer_lock_); 303 // If Start() was unsuccessful then set the buffer ready flag to true 304 // to start firing all-null events. 305 SetOrientationBufferReadyStatus(!success); 306 } 307 308 if (!success) 309 updateRotationVectorHistogram(false); 310 311 return success; 312 } 313 314 void SensorManagerAndroid::StopFetchingDeviceOrientationData() { 315 Stop(kTypeOrientation); 316 { 317 base::AutoLock autolock(orientation_buffer_lock_); 318 if (device_orientation_buffer_) { 319 SetOrientationBufferReadyStatus(false); 320 device_orientation_buffer_ = NULL; 321 } 322 } 323 } 324 325 } // namespace content 326