Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(584)

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/DeviceSensors.java

Issue 2646093002: Move //content/browser/device_sensor/ into device/sensors (Closed)
Patch Set: gn format & code rebase Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 package org.chromium.content.browser;
6
7 import android.content.Context;
8 import android.hardware.Sensor;
9 import android.hardware.SensorEvent;
10 import android.hardware.SensorEventListener;
11 import android.hardware.SensorManager;
12 import android.os.Handler;
13 import android.os.HandlerThread;
14
15 import org.chromium.base.CollectionUtil;
16 import org.chromium.base.Log;
17 import org.chromium.base.ThreadUtils;
18 import org.chromium.base.VisibleForTesting;
19 import org.chromium.base.annotations.CalledByNative;
20 import org.chromium.base.annotations.JNINamespace;
21
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Set;
25
26 /**
27 * Android implementation of the device {motion|orientation|light} APIs.
28 */
29 @JNINamespace("content")
30 class DeviceSensors implements SensorEventListener {
31
32 private static final String TAG = "cr.DeviceSensors";
33
34 // Matches kEnableExperimentalWebPlatformFeatures.
35 private static final String EXPERIMENTAL_WEB_PLAFTORM_FEATURES =
36 "enable-experimental-web-platform-features";
37
38 // These fields are lazily initialized by getHandler().
39 private Thread mThread;
40 private Handler mHandler;
41
42 // A reference to the application context in order to acquire the SensorServ ice.
43 private final Context mAppContext;
44
45 // The lock to access the mHandler.
46 private final Object mHandlerLock = new Object();
47
48 // Non-zero if and only if we're listening for events.
49 // To avoid race conditions on the C++ side, access must be synchronized.
50 private long mNativePtr;
51
52 // The lock to access the mNativePtr.
53 private final Object mNativePtrLock = new Object();
54
55 // The geomagnetic vector expressed in the body frame.
56 private float[] mMagneticFieldVector;
57
58 // Holds a shortened version of the rotation vector for compatibility purpos es.
59 private float[] mTruncatedRotationVector;
60
61 // Holds current rotation matrix for the device.
62 private float[] mDeviceRotationMatrix;
63
64 // Holds Euler angles corresponding to the rotation matrix.
65 private double[] mRotationAngles;
66
67 // Lazily initialized when registering for notifications.
68 private SensorManagerProxy mSensorManagerProxy;
69
70 // The only instance of that class and its associated lock.
71 private static DeviceSensors sSingleton;
72 private static Object sSingletonLock = new Object();
73
74 static final Set<Integer> DEVICE_ORIENTATION_SENSORS_A = CollectionUtil.newH ashSet(
75 Sensor.TYPE_GAME_ROTATION_VECTOR);
76 static final Set<Integer> DEVICE_ORIENTATION_SENSORS_B = CollectionUtil.newH ashSet(
77 Sensor.TYPE_ROTATION_VECTOR);
78 // Option C backup sensors are used when options A and B are not available.
79 static final Set<Integer> DEVICE_ORIENTATION_SENSORS_C = CollectionUtil.newH ashSet(
80 Sensor.TYPE_ACCELEROMETER,
81 Sensor.TYPE_MAGNETIC_FIELD);
82 static final Set<Integer> DEVICE_ORIENTATION_ABSOLUTE_SENSORS = CollectionUt il.newHashSet(
83 Sensor.TYPE_ROTATION_VECTOR);
84 static final Set<Integer> DEVICE_MOTION_SENSORS = CollectionUtil.newHashSet(
85 Sensor.TYPE_ACCELEROMETER,
86 Sensor.TYPE_LINEAR_ACCELERATION,
87 Sensor.TYPE_GYROSCOPE);
88 static final Set<Integer> DEVICE_LIGHT_SENSORS = CollectionUtil.newHashSet(
89 Sensor.TYPE_LIGHT);
90
91 @VisibleForTesting
92 final Set<Integer> mActiveSensors = new HashSet<Integer>();
93 final List<Set<Integer>> mOrientationSensorSets;
94 Set<Integer> mDeviceOrientationSensors;
95 boolean mDeviceLightIsActive;
96 boolean mDeviceMotionIsActive;
97 boolean mDeviceOrientationIsActive;
98 boolean mDeviceOrientationIsActiveWithBackupSensors;
99 boolean mDeviceOrientationAbsoluteIsActive;
100 boolean mOrientationNotAvailable;
101
102 protected DeviceSensors(Context context) {
103 mAppContext = context.getApplicationContext();
104
105 mOrientationSensorSets = CollectionUtil.newArrayList(DEVICE_ORIENTATION_ SENSORS_A,
106 DEVICE_ORIENTATION_ SENSORS_B,
107 DEVICE_ORIENTATION_ SENSORS_C);
108 }
109
110 // For orientation we use a 3-way fallback approach where up to 3 different sets of sensors
111 // are attempted if necessary. The sensors to be used for orientation are de termined in the
112 // following order:
113 // A: GAME_ROTATION_VECTOR (relative)
114 // B: ROTATION_VECTOR (absolute)
115 // C: combination of ACCELEROMETER and MAGNETIC_FIELD (absolute)
116 // Some of the sensors may not be available depending on the device and Andr oid version, so
117 // the 3-way fallback ensures selection of the best possible option.
118 // Examples:
119 // * Nexus 9, Android 5.0.2 --> option A
120 // * Nexus 10, Android 5.1 --> option B
121 // * Moto G, Android 4.4.4 --> option C
122 @VisibleForTesting
123 protected boolean registerOrientationSensorsWithFallback(int rateInMicroseco nds) {
124 if (mOrientationNotAvailable) return false;
125 if (mDeviceOrientationSensors != null) {
126 return registerSensors(mDeviceOrientationSensors, rateInMicroseconds , true);
127 }
128 ensureRotationStructuresAllocated();
129
130 for (Set<Integer> sensors : mOrientationSensorSets) {
131 mDeviceOrientationSensors = sensors;
132 if (registerSensors(mDeviceOrientationSensors, rateInMicroseconds, t rue)) return true;
133 }
134
135 mOrientationNotAvailable = true;
136 mDeviceOrientationSensors = null;
137 mDeviceRotationMatrix = null;
138 mRotationAngles = null;
139 return false;
140 }
141
142 /**
143 * Start listening for sensor events. If this object is already listening
144 * for events, the old callback is unregistered first.
145 *
146 * @param nativePtr Value to pass to nativeGotOrientation() for each event.
147 * @param rateInMicroseconds Requested callback rate in microseconds. The
148 * actual rate may be higher. Unwanted events should be ignored.
149 * @param eventType Type of event to listen to, can be either DEVICE_ORIENTA TION,
150 * DEVICE_ORIENTATION_ABSOLUTE, DEVICE_MOTION or DEVICE_LIGHT.
151 * @return True on success.
152 */
153 @CalledByNative
154 public boolean start(long nativePtr, int eventType, int rateInMicroseconds) {
155 boolean success = false;
156 synchronized (mNativePtrLock) {
157 switch (eventType) {
158 case ConsumerType.ORIENTATION:
159 success = registerOrientationSensorsWithFallback(rateInMicro seconds);
160 break;
161 case ConsumerType.ORIENTATION_ABSOLUTE:
162 ensureRotationStructuresAllocated();
163 success = registerSensors(DEVICE_ORIENTATION_ABSOLUTE_SENSOR S,
164 rateInMicroseconds, true);
165 break;
166 case ConsumerType.MOTION:
167 // note: device motion spec does not require all sensors to be available
168 success = registerSensors(DEVICE_MOTION_SENSORS, rateInMicro seconds, false);
169 break;
170 case ConsumerType.LIGHT:
171 success = registerSensors(DEVICE_LIGHT_SENSORS, rateInMicros econds, true);
172 break;
173 default:
174 Log.e(TAG, "Unknown event type: %d", eventType);
175 return false;
176 }
177 if (success) {
178 mNativePtr = nativePtr;
179 setEventTypeActive(eventType, true);
180 }
181 return success;
182 }
183 }
184
185 @CalledByNative
186 public int getNumberActiveDeviceMotionSensors() {
187 Set<Integer> deviceMotionSensors = new HashSet<Integer>(DEVICE_MOTION_SE NSORS);
188 deviceMotionSensors.removeAll(mActiveSensors);
189 return DEVICE_MOTION_SENSORS.size() - deviceMotionSensors.size();
190 }
191
192 @CalledByNative
193 public int getOrientationSensorTypeUsed() {
194 if (mOrientationNotAvailable) {
195 return OrientationSensorType.NOT_AVAILABLE;
196 }
197 if (mDeviceOrientationSensors == DEVICE_ORIENTATION_SENSORS_A) {
198 return OrientationSensorType.GAME_ROTATION_VECTOR;
199 }
200 if (mDeviceOrientationSensors == DEVICE_ORIENTATION_SENSORS_B) {
201 return OrientationSensorType.ROTATION_VECTOR;
202 }
203 if (mDeviceOrientationSensors == DEVICE_ORIENTATION_SENSORS_C) {
204 return OrientationSensorType.ACCELEROMETER_MAGNETIC;
205 }
206
207 assert false; // should never happen
208 return OrientationSensorType.NOT_AVAILABLE;
209 }
210
211 /**
212 * Stop listening to sensors for a given event type. Ensures that sensors ar e not disabled
213 * if they are still in use by a different event type.
214 *
215 * @param eventType Type of event to listen to, can be either DEVICE_ORIENTA TION or
216 * DEVICE_MOTION or DEVICE_LIGHT.
217 * We strictly guarantee that the corresponding native*() methods will not b e called
218 * after this method returns.
219 */
220 @CalledByNative
221 public void stop(int eventType) {
222 Set<Integer> sensorsToRemainActive = new HashSet<Integer>();
223
224 synchronized (mNativePtrLock) {
225 if (mDeviceOrientationIsActive && eventType != ConsumerType.ORIENTAT ION) {
226 sensorsToRemainActive.addAll(mDeviceOrientationSensors);
227 }
228
229 if (mDeviceOrientationAbsoluteIsActive
230 && eventType != ConsumerType.ORIENTATION_ABSOLUTE) {
231 sensorsToRemainActive.addAll(DEVICE_ORIENTATION_ABSOLUTE_SENSORS );
232 }
233
234 if (mDeviceMotionIsActive && eventType != ConsumerType.MOTION) {
235 sensorsToRemainActive.addAll(DEVICE_MOTION_SENSORS);
236 }
237
238 if (mDeviceLightIsActive && eventType != ConsumerType.LIGHT) {
239 sensorsToRemainActive.addAll(DEVICE_LIGHT_SENSORS);
240 }
241
242 Set<Integer> sensorsToDeactivate = new HashSet<Integer>(mActiveSenso rs);
243 sensorsToDeactivate.removeAll(sensorsToRemainActive);
244 unregisterSensors(sensorsToDeactivate);
245 setEventTypeActive(eventType, false);
246 if (mActiveSensors.isEmpty()) {
247 mNativePtr = 0;
248 }
249 }
250 }
251
252 @Override
253 public void onAccuracyChanged(Sensor sensor, int accuracy) {
254 // Nothing
255 }
256
257 @Override
258 public void onSensorChanged(SensorEvent event) {
259 sensorChanged(event.sensor.getType(), event.values);
260 }
261
262 @VisibleForTesting
263 void sensorChanged(int type, float[] values) {
264 switch (type) {
265 case Sensor.TYPE_ACCELEROMETER:
266 if (mDeviceMotionIsActive) {
267 gotAccelerationIncludingGravity(values[0], values[1], values [2]);
268 }
269 if (mDeviceOrientationIsActiveWithBackupSensors) {
270 getOrientationFromGeomagneticVectors(values, mMagneticFieldV ector);
271 }
272 break;
273 case Sensor.TYPE_LINEAR_ACCELERATION:
274 if (mDeviceMotionIsActive) {
275 gotAcceleration(values[0], values[1], values[2]);
276 }
277 break;
278 case Sensor.TYPE_GYROSCOPE:
279 if (mDeviceMotionIsActive) {
280 gotRotationRate(values[0], values[1], values[2]);
281 }
282 break;
283 case Sensor.TYPE_ROTATION_VECTOR:
284 if (mDeviceOrientationAbsoluteIsActive) {
285 convertRotationVectorToAngles(values, mRotationAngles);
286 gotOrientationAbsolute(mRotationAngles[0], mRotationAngles[1 ],
287 mRotationAngles[2]);
288 }
289 if (mDeviceOrientationIsActive
290 && mDeviceOrientationSensors == DEVICE_ORIENTATION_SENSO RS_B) {
291 if (!mDeviceOrientationAbsoluteIsActive) {
292 // only compute if not already computed for absolute ori entation above.
293 convertRotationVectorToAngles(values, mRotationAngles);
294 }
295 gotOrientation(mRotationAngles[0], mRotationAngles[1], mRota tionAngles[2]);
296 }
297 break;
298 case Sensor.TYPE_GAME_ROTATION_VECTOR:
299 if (mDeviceOrientationIsActive) {
300 convertRotationVectorToAngles(values, mRotationAngles);
301 gotOrientation(mRotationAngles[0], mRotationAngles[1], mRota tionAngles[2]);
302 }
303 break;
304 case Sensor.TYPE_MAGNETIC_FIELD:
305 if (mDeviceOrientationIsActiveWithBackupSensors) {
306 if (mMagneticFieldVector == null) {
307 mMagneticFieldVector = new float[3];
308 }
309 System.arraycopy(values, 0, mMagneticFieldVector, 0,
310 mMagneticFieldVector.length);
311 }
312 break;
313 case Sensor.TYPE_LIGHT:
314 if (mDeviceLightIsActive) {
315 gotLight(values[0]);
316 }
317 break;
318 default:
319 // Unexpected
320 return;
321 }
322 }
323
324 /**
325 * Returns orientation angles from a rotation matrix, such that the angles a re according
326 * to spec {@link http://dev.w3.org/geo/api/spec-source-orientation.html}.
327 * <p>
328 * It is assumed the rotation matrix transforms a 3D column vector from devi ce coordinate system
329 * to the world's coordinate system, as e.g. computed by {@see SensorManager .getRotationMatrix}.
330 * <p>
331 * In particular we compute the decomposition of a given rotation matrix R s uch that <br>
332 * R = Rz(alpha) * Rx(beta) * Ry(gamma), <br>
333 * where Rz, Rx and Ry are rotation matrices around Z, X and Y axes in the w orld coordinate
334 * reference frame respectively. The reference frame consists of three ortho gonal axes X, Y, Z
335 * where X points East, Y points north and Z points upwards perpendicular to the ground plane.
336 * The computed angles alpha, beta and gamma are in radians and clockwise-po sitive when viewed
337 * along the positive direction of the corresponding axis. Except for the sp ecial case when the
338 * beta angle is +-pi/2 these angles uniquely define the orientation of a mo bile device in 3D
339 * space. The alpha-beta-gamma representation resembles the yaw-pitch-roll c onvention used in
340 * vehicle dynamics, however it does not exactly match it. One of the differ ences is that the
341 * 'pitch' angle beta is allowed to be within [-pi, pi). A mobile device wit h pitch angle
342 * greater than pi/2 could correspond to a user lying down and looking upwar d at the screen.
343 *
344 * <p>
345 * Upon return the array values is filled with the result,
346 * <ul>
347 * <li>values[0]: rotation around the Z axis, alpha in [0, 2*pi)</li>
348 * <li>values[1]: rotation around the X axis, beta in [-pi, pi)</li>
349 * <li>values[2]: rotation around the Y axis, gamma in [-pi/2, pi/2)</li>
350 * </ul>
351 * <p>
352 *
353 * @param matrixR
354 * a 3x3 rotation matrix {@see SensorManager.getRotationMatrix}.
355 *
356 * @param values
357 * an array of 3 doubles to hold the result.
358 *
359 * @return the array values passed as argument.
360 */
361 @VisibleForTesting
362 public static double[] computeDeviceOrientationFromRotationMatrix(
363 float[] matrixR, double[] values) {
364 /*
365 * 3x3 (length=9) case:
366 * / R[ 0] R[ 1] R[ 2] \
367 * | R[ 3] R[ 4] R[ 5] |
368 * \ R[ 6] R[ 7] R[ 8] /
369 *
370 */
371 if (matrixR.length != 9) return values;
372
373 if (matrixR[8] > 0) { // cos(beta) > 0
374 values[0] = Math.atan2(-matrixR[1], matrixR[4]);
375 values[1] = Math.asin(matrixR[7]); // beta (-pi/2, p i/2)
376 values[2] = Math.atan2(-matrixR[6], matrixR[8]); // gamma (-pi/2, pi/2)
377 } else if (matrixR[8] < 0) { // cos(beta) < 0
378 values[0] = Math.atan2(matrixR[1], -matrixR[4]);
379 values[1] = -Math.asin(matrixR[7]);
380 values[1] += (values[1] >= 0) ? -Math.PI : Math.PI; // beta [-pi,-pi /2) U (pi/2,pi)
381 values[2] = Math.atan2(matrixR[6], -matrixR[8]); // gamma (-pi/2, pi/2)
382 } else { // R[8] == 0
383 if (matrixR[6] > 0) { // cos(gamma) == 0, cos(beta) > 0
384 values[0] = Math.atan2(-matrixR[1], matrixR[4]);
385 values[1] = Math.asin(matrixR[7]); // beta [-pi/2, pi/2]
386 values[2] = -Math.PI / 2; // gamma = -pi/2
387 } else if (matrixR[6] < 0) { // cos(gamma) == 0, cos(beta) < 0
388 values[0] = Math.atan2(matrixR[1], -matrixR[4]);
389 values[1] = -Math.asin(matrixR[7]);
390 values[1] += (values[1] >= 0) ? -Math.PI : Math.PI; // beta [-pi ,-pi/2) U (pi/2,pi)
391 values[2] = -Math.PI / 2; // gamma = - pi/2
392 } else { // R[6] == 0, cos(beta) == 0
393 // gimbal lock discontinuity
394 values[0] = Math.atan2(matrixR[3], matrixR[0]);
395 values[1] = (matrixR[7] > 0) ? Math.PI / 2 : -Math.PI / 2; // b eta = +-pi/2
396 values[2] = 0; // g amma = 0
397 }
398 }
399
400 // alpha is in [-pi, pi], make sure it is in [0, 2*pi).
401 if (values[0] < 0) {
402 values[0] += 2 * Math.PI; // alpha [0, 2*pi)
403 }
404
405 return values;
406 }
407
408 /*
409 * Converts a given rotation vector to its Euler angles representation. The angles
410 * are in degrees.
411 */
412 public void convertRotationVectorToAngles(float[] rotationVector, double[] a ngles) {
413 if (rotationVector.length > 4) {
414 // On some Samsung devices SensorManager.getRotationMatrixFromVector
415 // appears to throw an exception if rotation vector has length > 4.
416 // For the purposes of this class the first 4 values of the
417 // rotation vector are sufficient (see crbug.com/335298 for details) .
418 System.arraycopy(rotationVector, 0, mTruncatedRotationVector, 0, 4);
419 SensorManager.getRotationMatrixFromVector(mDeviceRotationMatrix,
420 mTruncatedRotationVector);
421 } else {
422 SensorManager.getRotationMatrixFromVector(mDeviceRotationMatrix, rot ationVector);
423 }
424 computeDeviceOrientationFromRotationMatrix(mDeviceRotationMatrix, angles );
425 for (int i = 0; i < 3; i++) {
426 angles[i] = Math.toDegrees(angles[i]);
427 }
428 }
429
430 private void getOrientationFromGeomagneticVectors(float[] acceleration, floa t[] magnetic) {
431 if (acceleration == null || magnetic == null) {
432 return;
433 }
434 if (!SensorManager.getRotationMatrix(mDeviceRotationMatrix, null, accele ration, magnetic)) {
435 return;
436 }
437 computeDeviceOrientationFromRotationMatrix(mDeviceRotationMatrix, mRotat ionAngles);
438
439 gotOrientation(Math.toDegrees(mRotationAngles[0]),
440 Math.toDegrees(mRotationAngles[1]),
441 Math.toDegrees(mRotationAngles[2]));
442 }
443
444 private SensorManagerProxy getSensorManagerProxy() {
445 if (mSensorManagerProxy != null) {
446 return mSensorManagerProxy;
447 }
448
449 ThreadUtils.assertOnUiThread();
450 SensorManager sensorManager =
451 (SensorManager) mAppContext.getSystemService(Context.SENSOR_SERV ICE);
452
453 if (sensorManager != null) {
454 mSensorManagerProxy = new SensorManagerProxyImpl(sensorManager);
455 }
456 return mSensorManagerProxy;
457 }
458
459 @VisibleForTesting
460 void setSensorManagerProxy(SensorManagerProxy sensorManagerProxy) {
461 mSensorManagerProxy = sensorManagerProxy;
462 }
463
464 private void setEventTypeActive(int eventType, boolean active) {
465 switch (eventType) {
466 case ConsumerType.ORIENTATION:
467 mDeviceOrientationIsActive = active;
468 mDeviceOrientationIsActiveWithBackupSensors = active
469 && (mDeviceOrientationSensors == DEVICE_ORIENTATION_SENS ORS_C);
470 return;
471 case ConsumerType.ORIENTATION_ABSOLUTE:
472 mDeviceOrientationAbsoluteIsActive = active;
473 return;
474 case ConsumerType.MOTION:
475 mDeviceMotionIsActive = active;
476 return;
477 case ConsumerType.LIGHT:
478 mDeviceLightIsActive = active;
479 return;
480 }
481 }
482
483 private void ensureRotationStructuresAllocated() {
484 if (mDeviceRotationMatrix == null) {
485 mDeviceRotationMatrix = new float[9];
486 }
487 if (mRotationAngles == null) {
488 mRotationAngles = new double[3];
489 }
490 if (mTruncatedRotationVector == null) {
491 mTruncatedRotationVector = new float[4];
492 }
493 }
494
495 /**
496 * @param sensorTypes List of sensors to activate.
497 * @param rateInMicroseconds Intended delay (in microseconds) between sensor readings.
498 * @param failOnMissingSensor If true the method returns true only if all se nsors could be
499 * activated. When false the method return true i f at least one
500 * sensor in sensorTypes could be activated.
501 */
502 private boolean registerSensors(Set<Integer> sensorTypes, int rateInMicrosec onds,
503 boolean failOnMissingSensor) {
504 Set<Integer> sensorsToActivate = new HashSet<Integer>(sensorTypes);
505 sensorsToActivate.removeAll(mActiveSensors);
506 if (sensorsToActivate.isEmpty()) return true;
507
508 boolean success = false;
509 for (Integer sensorType : sensorsToActivate) {
510 boolean result = registerForSensorType(sensorType, rateInMicrosecond s);
511 if (!result && failOnMissingSensor) {
512 // restore the previous state upon failure
513 unregisterSensors(sensorsToActivate);
514 return false;
515 }
516 if (result) {
517 mActiveSensors.add(sensorType);
518 success = true;
519 }
520 }
521 return success;
522 }
523
524 private void unregisterSensors(Iterable<Integer> sensorTypes) {
525 for (Integer sensorType : sensorTypes) {
526 if (mActiveSensors.contains(sensorType)) {
527 getSensorManagerProxy().unregisterListener(this, sensorType);
528 mActiveSensors.remove(sensorType);
529 }
530 }
531 }
532
533 private boolean registerForSensorType(int type, int rateInMicroseconds) {
534 SensorManagerProxy sensorManager = getSensorManagerProxy();
535 if (sensorManager == null) {
536 return false;
537 }
538 return sensorManager.registerListener(this, type, rateInMicroseconds, ge tHandler());
539 }
540
541 protected void gotOrientation(double alpha, double beta, double gamma) {
542 synchronized (mNativePtrLock) {
543 if (mNativePtr != 0) {
544 nativeGotOrientation(mNativePtr, alpha, beta, gamma);
545 }
546 }
547 }
548
549 protected void gotOrientationAbsolute(double alpha, double beta, double gamm a) {
550 synchronized (mNativePtrLock) {
551 if (mNativePtr != 0) {
552 nativeGotOrientationAbsolute(mNativePtr, alpha, beta, gamma);
553 }
554 }
555 }
556
557 protected void gotAcceleration(double x, double y, double z) {
558 synchronized (mNativePtrLock) {
559 if (mNativePtr != 0) {
560 nativeGotAcceleration(mNativePtr, x, y, z);
561 }
562 }
563 }
564
565 protected void gotAccelerationIncludingGravity(double x, double y, double z) {
566 synchronized (mNativePtrLock) {
567 if (mNativePtr != 0) {
568 nativeGotAccelerationIncludingGravity(mNativePtr, x, y, z);
569 }
570 }
571 }
572
573 protected void gotRotationRate(double alpha, double beta, double gamma) {
574 synchronized (mNativePtrLock) {
575 if (mNativePtr != 0) {
576 nativeGotRotationRate(mNativePtr, alpha, beta, gamma);
577 }
578 }
579 }
580
581 protected void gotLight(double value) {
582 synchronized (mNativePtrLock) {
583 if (mNativePtr != 0) {
584 nativeGotLight(mNativePtr, value);
585 }
586 }
587 }
588
589 private Handler getHandler() {
590 // TODO(timvolodine): Remove the mHandlerLock when sure that getHandler is not called
591 // from multiple threads. This will be the case when device motion and d evice orientation
592 // use the same polling thread (also see crbug/234282).
593 synchronized (mHandlerLock) {
594 if (mHandler == null) {
595 HandlerThread thread = new HandlerThread("DeviceMotionAndOrienta tion");
596 thread.start();
597 mHandler = new Handler(thread.getLooper()); // blocks on thread start
598 }
599 return mHandler;
600 }
601 }
602
603 @CalledByNative
604 static DeviceSensors getInstance(Context appContext) {
605 synchronized (sSingletonLock) {
606 if (sSingleton == null) {
607 sSingleton = new DeviceSensors(appContext);
608 }
609 return sSingleton;
610 }
611 }
612
613 /**
614 * Native JNI calls,
615 * see content/browser/device_sensors/sensor_manager_android.cc
616 */
617
618 /**
619 * Orientation of the device with respect to its reference frame.
620 */
621 private native void nativeGotOrientation(
622 long nativeSensorManagerAndroid,
623 double alpha, double beta, double gamma);
624
625 /**
626 * Absolute orientation of the device with respect to its reference frame.
627 */
628 private native void nativeGotOrientationAbsolute(
629 long nativeSensorManagerAndroid,
630 double alpha, double beta, double gamma);
631
632 /**
633 * Linear acceleration without gravity of the device with respect to its bod y frame.
634 */
635 private native void nativeGotAcceleration(
636 long nativeSensorManagerAndroid,
637 double x, double y, double z);
638
639 /**
640 * Acceleration including gravity of the device with respect to its body fra me.
641 */
642 private native void nativeGotAccelerationIncludingGravity(
643 long nativeSensorManagerAndroid,
644 double x, double y, double z);
645
646 /**
647 * Rotation rate of the device with respect to its body frame.
648 */
649 private native void nativeGotRotationRate(
650 long nativeSensorManagerAndroid,
651 double alpha, double beta, double gamma);
652
653 /**
654 * Device Light value from Ambient Light sensors.
655 */
656 private native void nativeGotLight(
657 long nativeSensorManagerAndroid,
658 double value);
659
660 /**
661 * Need the an interface for SensorManager for testing.
662 */
663 interface SensorManagerProxy {
664 public boolean registerListener(SensorEventListener listener, int sensor Type, int rate,
665 Handler handler);
666 public void unregisterListener(SensorEventListener listener, int sensorT ype);
667 }
668
669 static class SensorManagerProxyImpl implements SensorManagerProxy {
670 private final SensorManager mSensorManager;
671
672 SensorManagerProxyImpl(SensorManager sensorManager) {
673 mSensorManager = sensorManager;
674 }
675
676 @Override
677 public boolean registerListener(SensorEventListener listener, int sensor Type, int rate,
678 Handler handler) {
679 List<Sensor> sensors = mSensorManager.getSensorList(sensorType);
680 if (sensors.isEmpty()) {
681 return false;
682 }
683 return mSensorManager.registerListener(listener, sensors.get(0), rat e, handler);
684 }
685
686 @Override
687 public void unregisterListener(SensorEventListener listener, int sensorT ype) {
688 List<Sensor> sensors = mSensorManager.getSensorList(sensorType);
689 if (sensors.isEmpty()) {
690 return;
691 }
692 try {
693 mSensorManager.unregisterListener(listener, sensors.get(0));
694 } catch (IllegalArgumentException e) {
695 // Suppress occasional exception on Digma iDxD* devices:
696 // Receiver not registered: android.hardware.SystemSensorManager $1
697 // See crbug.com/596453.
698 Log.w(TAG, "Failed to unregister device sensor " + sensors.get(0 ).getName());
699 }
700 }
701 }
702
703 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698