1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.hardware;
18
19/**
20 * This class represents a {@link android.hardware.Sensor Sensor} event and
21 * holds informations such as the sensor's type, the time-stamp, accuracy and of
22 * course the sensor's {@link SensorEvent#values data}.
23 *
24 * <p>
25 * <u>Definition of the coordinate system used by the SensorEvent API.</u>
26 * </p>
27 *
28 * <p>
29 * The coordinate-system is defined relative to the screen of the phone in its
30 * default orientation. The axes are not swapped when the device's screen
31 * orientation changes.
32 * </p>
33 *
34 * <p>
35 * The X axis is horizontal and points to the right, the Y axis is vertical and
36 * points up and the Z axis points towards the outside of the front face of the
37 * screen. In this system, coordinates behind the screen have negative Z values.
38 * </p>
39 *
40 * <p>
41 * <center><img src="../../../images/axis_device.png"
42 * alt="Sensors coordinate-system diagram." border="0" /></center>
43 * </p>
44 *
45 * <p>
46 * <b>Note:</b> This coordinate system is different from the one used in the
47 * Android 2D APIs where the origin is in the top-left corner.
48 * </p>
49 *
50 * @see SensorManager
51 * @see SensorEvent
52 * @see Sensor
53 *
54 */
55
56public class SensorEvent {
57    /**
58     * <p>
59     * The length and contents of the {@link #values values} array depends on
60     * which {@link android.hardware.Sensor sensor} type is being monitored (see
61     * also {@link SensorEvent} for a definition of the coordinate system used).
62     * </p>
63     *
64     * <h4>{@link android.hardware.Sensor#TYPE_ACCELEROMETER
65     * Sensor.TYPE_ACCELEROMETER}:</h4> All values are in SI units (m/s^2)
66     *
67     * <ul>
68     * <li> values[0]: Acceleration minus Gx on the x-axis </li>
69     * <li> values[1]: Acceleration minus Gy on the y-axis </li>
70     * <li> values[2]: Acceleration minus Gz on the z-axis </li>
71     * </ul>
72     *
73     * <p>
74     * A sensor of this type measures the acceleration applied to the device
75     * (<b>Ad</b>). Conceptually, it does so by measuring forces applied to the
76     * sensor itself (<b>Fs</b>) using the relation:
77     * </p>
78     *
79     * <b><center>Ad = - &#8721;Fs / mass</center></b>
80     *
81     * <p>
82     * In particular, the force of gravity is always influencing the measured
83     * acceleration:
84     * </p>
85     *
86     * <b><center>Ad = -g - &#8721;F / mass</center></b>
87     *
88     * <p>
89     * For this reason, when the device is sitting on a table (and obviously not
90     * accelerating), the accelerometer reads a magnitude of <b>g</b> = 9.81
91     * m/s^2
92     * </p>
93     *
94     * <p>
95     * Similarly, when the device is in free-fall and therefore dangerously
96     * accelerating towards to ground at 9.81 m/s^2, its accelerometer reads a
97     * magnitude of 0 m/s^2.
98     * </p>
99     *
100     * <p>
101     * It should be apparent that in order to measure the real acceleration of
102     * the device, the contribution of the force of gravity must be eliminated.
103     * This can be achieved by applying a <i>high-pass</i> filter. Conversely, a
104     * <i>low-pass</i> filter can be used to isolate the force of gravity.
105     * </p>
106     *
107     * <pre class="prettyprint">
108     *
109     *     public void onSensorChanged(SensorEvent event)
110     *     {
111     *          // alpha is calculated as t / (t + dT)
112     *          // with t, the low-pass filter's time-constant
113     *          // and dT, the event delivery rate
114     *
115     *          final float alpha = 0.8;
116     *
117     *          gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
118     *          gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
119     *          gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];
120     *
121     *          linear_acceleration[0] = event.values[0] - gravity[0];
122     *          linear_acceleration[1] = event.values[1] - gravity[1];
123     *          linear_acceleration[2] = event.values[2] - gravity[2];
124     *     }
125     * </pre>
126     *
127     * <p>
128     * <u>Examples</u>:
129     * <ul>
130     * <li>When the device lies flat on a table and is pushed on its left side
131     * toward the right, the x acceleration value is positive.</li>
132     *
133     * <li>When the device lies flat on a table, the acceleration value is
134     * +9.81, which correspond to the acceleration of the device (0 m/s^2) minus
135     * the force of gravity (-9.81 m/s^2).</li>
136     *
137     * <li>When the device lies flat on a table and is pushed toward the sky
138     * with an acceleration of A m/s^2, the acceleration value is equal to
139     * A+9.81 which correspond to the acceleration of the device (+A m/s^2)
140     * minus the force of gravity (-9.81 m/s^2).</li>
141     * </ul>
142     *
143     *
144     * <h4>{@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD
145     * Sensor.TYPE_MAGNETIC_FIELD}:</h4>
146     * All values are in micro-Tesla (uT) and measure the ambient magnetic field
147     * in the X, Y and Z axis.
148     *
149     * <h4>{@link android.hardware.Sensor#TYPE_GYROSCOPE Sensor.TYPE_GYROSCOPE}:
150     * </h4> All values are in radians/second and measure the rate of rotation
151     * around the device's local X, Y and Z axis. The coordinate system is the
152     * same as is used for the acceleration sensor. Rotation is positive in the
153     * counter-clockwise direction. That is, an observer looking from some
154     * positive location on the x, y or z axis at a device positioned on the
155     * origin would report positive rotation if the device appeared to be
156     * rotating counter clockwise. Note that this is the standard mathematical
157     * definition of positive rotation and does not agree with the definition of
158     * roll given earlier.
159     * <ul>
160     * <li> values[0]: Angular speed around the x-axis </li>
161     * <li> values[1]: Angular speed around the y-axis </li>
162     * <li> values[2]: Angular speed around the z-axis </li>
163     * </ul>
164     * <p>
165     * Typically the output of the gyroscope is integrated over time to
166     * calculate a rotation describing the change of angles over the timestep,
167     * for example:
168     * </p>
169     *
170     * <pre class="prettyprint">
171     *     private static final float NS2S = 1.0f / 1000000000.0f;
172     *     private final float[] deltaRotationVector = new float[4]();
173     *     private float timestamp;
174     *
175     *     public void onSensorChanged(SensorEvent event) {
176     *          // This timestep's delta rotation to be multiplied by the current rotation
177     *          // after computing it from the gyro sample data.
178     *          if (timestamp != 0) {
179     *              final float dT = (event.timestamp - timestamp) * NS2S;
180     *              // Axis of the rotation sample, not normalized yet.
181     *              float axisX = event.values[0];
182     *              float axisY = event.values[1];
183     *              float axisZ = event.values[2];
184     *
185     *              // Calculate the angular speed of the sample
186     *              float omegaMagnitude = sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);
187     *
188     *              // Normalize the rotation vector if it's big enough to get the axis
189     *              if (omegaMagnitude > EPSILON) {
190     *                  axisX /= omegaMagnitude;
191     *                  axisY /= omegaMagnitude;
192     *                  axisZ /= omegaMagnitude;
193     *              }
194     *
195     *              // Integrate around this axis with the angular speed by the timestep
196     *              // in order to get a delta rotation from this sample over the timestep
197     *              // We will convert this axis-angle representation of the delta rotation
198     *              // into a quaternion before turning it into the rotation matrix.
199     *              float thetaOverTwo = omegaMagnitude * dT / 2.0f;
200     *              float sinThetaOverTwo = sin(thetaOverTwo);
201     *              float cosThetaOverTwo = cos(thetaOverTwo);
202     *              deltaRotationVector[0] = sinThetaOverTwo * axisX;
203     *              deltaRotationVector[1] = sinThetaOverTwo * axisY;
204     *              deltaRotationVector[2] = sinThetaOverTwo * axisZ;
205     *              deltaRotationVector[3] = cosThetaOverTwo;
206     *          }
207     *          timestamp = event.timestamp;
208     *          float[] deltaRotationMatrix = new float[9];
209     *          SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector);
210     *          // User code should concatenate the delta rotation we computed with the current rotation
211     *          // in order to get the updated rotation.
212     *          // rotationCurrent = rotationCurrent * deltaRotationMatrix;
213     *     }
214     * </pre>
215     * <p>
216     * In practice, the gyroscope noise and offset will introduce some errors
217     * which need to be compensated for. This is usually done using the
218     * information from other sensors, but is beyond the scope of this document.
219     * </p>
220     * <h4>{@link android.hardware.Sensor#TYPE_LIGHT Sensor.TYPE_LIGHT}:</h4>
221     * <ul>
222     * <li>values[0]: Ambient light level in SI lux units </li>
223     * </ul>
224     *
225     * <h4>{@link android.hardware.Sensor#TYPE_PRESSURE Sensor.TYPE_PRESSURE}:</h4>
226     * <ul>
227     * <li>values[0]: Atmospheric pressure in hPa (millibar) </li>
228     * </ul>
229     *
230     * <h4>{@link android.hardware.Sensor#TYPE_PROXIMITY Sensor.TYPE_PROXIMITY}:
231     * </h4>
232     *
233     * <ul>
234     * <li>values[0]: Proximity sensor distance measured in centimeters </li>
235     * </ul>
236     *
237     * <p>
238     * <b>Note:</b> Some proximity sensors only support a binary <i>near</i> or
239     * <i>far</i> measurement. In this case, the sensor should report its
240     * {@link android.hardware.Sensor#getMaximumRange() maximum range} value in
241     * the <i>far</i> state and a lesser value in the <i>near</i> state.
242     * </p>
243     *
244     *  <h4>{@link android.hardware.Sensor#TYPE_GRAVITY Sensor.TYPE_GRAVITY}:</h4>
245     *  <p>A three dimensional vector indicating the direction and magnitude of gravity.  Units
246     *  are m/s^2. The coordinate system is the same as is used by the acceleration sensor.</p>
247     *  <p><b>Note:</b> When the device is at rest, the output of the gravity sensor should be identical
248     *  to that of the accelerometer.</p>
249     *
250     *  <h4>{@link android.hardware.Sensor#TYPE_LINEAR_ACCELERATION Sensor.TYPE_LINEAR_ACCELERATION}:</h4>
251     *  A three dimensional vector indicating acceleration along each device axis, not including
252     *  gravity.  All values have units of m/s^2.  The coordinate system is the same as is used by the
253     *  acceleration sensor.
254     *  <p>The output of the accelerometer, gravity and  linear-acceleration sensors must obey the
255     *  following relation:</p>
256     *   <p><ul>acceleration = gravity + linear-acceleration</ul></p>
257     *
258     *  <h4>{@link android.hardware.Sensor#TYPE_ROTATION_VECTOR Sensor.TYPE_ROTATION_VECTOR}:</h4>
259     *  <p>The rotation vector represents the orientation of the device as a combination of an <i>angle</i>
260     *  and an <i>axis</i>, in which the device has rotated through an angle &#952 around an axis
261     *  &lt;x, y, z>.</p>
262     *  <p>The three elements of the rotation vector are
263     *  &lt;x*sin(&#952/2), y*sin(&#952/2), z*sin(&#952/2)>, such that the magnitude of the rotation
264     *  vector is equal to sin(&#952/2), and the direction of the rotation vector is equal to the
265     *  direction of the axis of rotation.</p>
266     *  </p>The three elements of the rotation vector are equal to
267     *  the last three components of a <b>unit</b> quaternion
268     *  &lt;cos(&#952/2), x*sin(&#952/2), y*sin(&#952/2), z*sin(&#952/2)>.</p>
269     *  <p>Elements of the rotation vector are unitless.
270     *  The x,y, and z axis are defined in the same way as the acceleration
271     *  sensor.</p>
272     *  The reference coordinate system is defined as a direct orthonormal basis,
273     *  where:
274     * </p>
275     *
276     * <ul>
277     * <li>X is defined as the vector product <b>Y.Z</b> (It is tangential to
278     * the ground at the device's current location and roughly points East).</li>
279     * <li>Y is tangential to the ground at the device's current location and
280     * points towards magnetic north.</li>
281     * <li>Z points towards the sky and is perpendicular to the ground.</li>
282     * </ul>
283     *
284     * <p>
285     * <center><img src="../../../images/axis_globe.png"
286     * alt="World coordinate-system diagram." border="0" /></center>
287     * </p>
288     *
289     * <ul>
290     * <li> values[0]: x*sin(&#952/2) </li>
291     * <li> values[1]: y*sin(&#952/2) </li>
292     * <li> values[2]: z*sin(&#952/2) </li>
293     * <li> values[3]: cos(&#952/2) </li>
294     * <li> values[4]: estimated heading Accuracy (in radians) (-1 if unavailable)</li>
295     * </ul>
296     * <p> values[3], originally optional, will always be present from SDK Level 18 onwards.
297     * values[4] is a new value that has been added in SDK Level 18.
298     * </p>
299     *
300     * <h4>{@link android.hardware.Sensor#TYPE_ORIENTATION
301     * Sensor.TYPE_ORIENTATION}:</h4> All values are angles in degrees.
302     *
303     * <ul>
304     * <li> values[0]: Azimuth, angle between the magnetic north direction and the
305     * y-axis, around the z-axis (0 to 359). 0=North, 90=East, 180=South,
306     * 270=West
307     * </p>
308     *
309     * <p>
310     * values[1]: Pitch, rotation around x-axis (-180 to 180), with positive
311     * values when the z-axis moves <b>toward</b> the y-axis.
312     * </p>
313     *
314     * <p>
315     * values[2]: Roll, rotation around the y-axis (-90 to 90)
316     * increasing as the device moves clockwise.
317     * </p>
318     * </ul>
319     *
320     * <p>
321     * <b>Note:</b> This definition is different from <b>yaw, pitch and roll</b>
322     * used in aviation where the X axis is along the long side of the plane
323     * (tail to nose).
324     * </p>
325     *
326     * <p>
327     * <b>Note:</b> This sensor type exists for legacy reasons, please use
328     * {@link android.hardware.Sensor#TYPE_ROTATION_VECTOR
329     * rotation vector sensor type} and
330     * {@link android.hardware.SensorManager#getRotationMatrix
331     * getRotationMatrix()} in conjunction with
332     * {@link android.hardware.SensorManager#remapCoordinateSystem
333     * remapCoordinateSystem()} and
334     * {@link android.hardware.SensorManager#getOrientation getOrientation()} to
335     * compute these values instead.
336     * </p>
337     *
338     * <p>
339     * <b>Important note:</b> For historical reasons the roll angle is positive
340     * in the clockwise direction (mathematically speaking, it should be
341     * positive in the counter-clockwise direction).
342     * </p>
343     *
344     * <h4>{@link android.hardware.Sensor#TYPE_RELATIVE_HUMIDITY
345     * Sensor.TYPE_RELATIVE_HUMIDITY}:</h4>
346     * <ul>
347     * <li> values[0]: Relative ambient air humidity in percent </li>
348     * </ul>
349     * <p>
350     * When relative ambient air humidity and ambient temperature are
351     * measured, the dew point and absolute humidity can be calculated.
352     * </p>
353     * <u>Dew Point</u>
354     * <p>
355     * The dew point is the temperature to which a given parcel of air must be
356     * cooled, at constant barometric pressure, for water vapor to condense
357     * into water.
358     * </p>
359     * <center><pre>
360     *                    ln(RH/100%) + m&#183;t/(T<sub>n</sub>+t)
361     * t<sub>d</sub>(t,RH) = T<sub>n</sub> &#183; ------------------------------
362     *                 m - [ln(RH/100%) + m&#183;t/(T<sub>n</sub>+t)]
363     * </pre></center>
364     * <dl>
365     * <dt>t<sub>d</sub></dt> <dd>dew point temperature in &deg;C</dd>
366     * <dt>t</dt>             <dd>actual temperature in &deg;C</dd>
367     * <dt>RH</dt>            <dd>actual relative humidity in %</dd>
368     * <dt>m</dt>             <dd>17.62</dd>
369     * <dt>T<sub>n</sub></dt> <dd>243.12 &deg;C</dd>
370     * </dl>
371     * <p>for example:</p>
372     * <pre class="prettyprint">
373     * h = Math.log(rh / 100.0) + (17.62 * t) / (243.12 + t);
374     * td = 243.12 * h / (17.62 - h);
375     * </pre>
376     * <u>Absolute Humidity</u>
377     * <p>
378     * The absolute humidity is the mass of water vapor in a particular volume
379     * of dry air. The unit is g/m<sup>3</sup>.
380     * </p>
381     * <center><pre>
382     *                    RH/100%&#183;A&#183;exp(m&#183;t/(T<sub>n</sub>+t))
383     * d<sub>v</sub>(t,RH) = 216.7 &#183; -------------------------
384     *                           273.15 + t
385     * </pre></center>
386     * <dl>
387     * <dt>d<sub>v</sub></dt> <dd>absolute humidity in g/m<sup>3</sup></dd>
388     * <dt>t</dt>             <dd>actual temperature in &deg;C</dd>
389     * <dt>RH</dt>            <dd>actual relative humidity in %</dd>
390     * <dt>m</dt>             <dd>17.62</dd>
391     * <dt>T<sub>n</sub></dt> <dd>243.12 &deg;C</dd>
392     * <dt>A</dt>             <dd>6.112 hPa</dd>
393     * </dl>
394     * <p>for example:</p>
395     * <pre class="prettyprint">
396     * dv = 216.7 *
397     * (rh / 100.0 * 6.112 * Math.exp(17.62 * t / (243.12 + t)) / (273.15 + t));
398     * </pre>
399     *
400     * <h4>{@link android.hardware.Sensor#TYPE_AMBIENT_TEMPERATURE Sensor.TYPE_AMBIENT_TEMPERATURE}:
401     * </h4>
402     *
403     * <ul>
404     * <li> values[0]: ambient (room) temperature in degree Celsius.</li>
405     * </ul>
406     *
407     *
408     * <h4>{@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD_UNCALIBRATED
409     * Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED}:</h4>
410     * Similar to {@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD},
411     * but the hard iron calibration is reported separately instead of being included
412     * in the measurement. Factory calibration and temperature compensation will still
413     * be applied to the "uncalibrated" measurement. Assumptions that the magnetic field
414     * is due to the Earth's poles is avoided.
415     * <p>
416     * The values array is shown below:
417     * <ul>
418     * <li> values[0] = x_uncalib </li>
419     * <li> values[1] = y_uncalib </li>
420     * <li> values[2] = z_uncalib </li>
421     * <li> values[3] = x_bias </li>
422     * <li> values[4] = y_bias </li>
423     * <li> values[5] = z_bias </li>
424     * </ul>
425     * </p>
426     * <p>
427     * x_uncalib, y_uncalib, z_uncalib are the measured magnetic field in X, Y, Z axes.
428     * Soft iron and temperature calibrations are applied. But the hard iron
429     * calibration is not applied. The values are in micro-Tesla (uT).
430     * </p>
431     * <p>
432     * x_bias, y_bias, z_bias give the iron bias estimated in X, Y, Z axes.
433     * Each field is a component of the estimated hard iron calibration.
434     * The values are in micro-Tesla (uT).
435     * </p>
436     * <p> Hard iron - These distortions arise due to the magnetized iron, steel or permanenet
437     * magnets on the device.
438     * Soft iron - These distortions arise due to the interaction with the earth's magentic
439     * field.
440     * </p>
441     * <h4> {@link android.hardware.Sensor#TYPE_GAME_ROTATION_VECTOR}:</h4>
442     * Identical to {@link android.hardware.Sensor#TYPE_ROTATION_VECTOR} except that it
443     * doesn't use the geomagnetic field. Therefore the Y axis doesn't
444     * point north, but instead to some other reference, that reference is
445     * allowed to drift by the same order of magnitude as the gyroscope
446     * drift around the Z axis.
447     * <p>
448     * In the ideal case, a phone rotated and returning to the same real-world
449     * orientation will report the same game rotation vector
450     * (without using the earth's geomagnetic field). However, the orientation
451     * may drift somewhat over time. See {@link android.hardware.Sensor#TYPE_ROTATION_VECTOR}
452     * for a detailed description of the values. This sensor will not have
453     * the estimated heading accuracy value.
454     * </p>
455     *
456     * <h4> {@link android.hardware.Sensor#TYPE_GYROSCOPE_UNCALIBRATED
457     * Sensor.TYPE_GYROSCOPE_UNCALIBRATED}:</h4>
458     * All values are in radians/second and measure the rate of rotation
459     * around the X, Y and Z axis. An estimation of the drift on each axis is
460     * reported as well.
461     * <p>
462     * No gyro-drift compensation is performed. Factory calibration and temperature
463     * compensation is still applied to the rate of rotation (angular speeds).
464     * </p>
465     * <p>
466     * The coordinate system is the same as is used for the
467     * {@link android.hardware.Sensor#TYPE_ACCELEROMETER}
468     * Rotation is positive in the counter-clockwise direction (right-hand rule).
469     * That is, an observer looking from some positive location on the x, y or z axis
470     * at a device positioned on the origin would report positive rotation if the device
471     * appeared to be rotating counter clockwise.
472     * The range would at least be 17.45 rad/s (ie: ~1000 deg/s).
473     * <ul>
474     * <li> values[0] : angular speed (w/o drift compensation) around the X axis in rad/s </li>
475     * <li> values[1] : angular speed (w/o drift compensation) around the Y axis in rad/s </li>
476     * <li> values[2] : angular speed (w/o drift compensation) around the Z axis in rad/s </li>
477     * <li> values[3] : estimated drift around X axis in rad/s </li>
478     * <li> values[4] : estimated drift around Y axis in rad/s </li>
479     * <li> values[5] : estimated drift around Z axis in rad/s </li>
480     * </ul>
481     * </p>
482     * <p><b>Pro Tip:</b> Always use the length of the values array while performing operations
483     * on it. In earlier versions, this used to be always 3 which has changed now. </p>
484     *
485     * @see GeomagneticField
486     */
487    public final float[] values;
488
489    /**
490     * The sensor that generated this event. See
491     * {@link android.hardware.SensorManager SensorManager} for details.
492     */
493    public Sensor sensor;
494
495    /**
496     * The accuracy of this event. See {@link android.hardware.SensorManager
497     * SensorManager} for details.
498     */
499    public int accuracy;
500
501    /**
502     * The time in nanosecond at which the event happened
503     */
504    public long timestamp;
505
506    SensorEvent(int valueSize) {
507        values = new float[valueSize];
508    }
509}
510