• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.hardware;
18 
19 import android.content.Context;
20 import android.os.Binder;
21 import android.os.Bundle;
22 import android.os.Looper;
23 import android.os.Parcelable;
24 import android.os.ParcelFileDescriptor;
25 import android.os.Process;
26 import android.os.RemoteException;
27 import android.os.Handler;
28 import android.os.Message;
29 import android.os.ServiceManager;
30 import android.util.Log;
31 import android.util.SparseArray;
32 import android.view.IRotationWatcher;
33 import android.view.IWindowManager;
34 import android.view.Surface;
35 
36 import java.io.FileDescriptor;
37 import java.io.IOException;
38 import java.util.ArrayList;
39 import java.util.Collections;
40 import java.util.HashMap;
41 import java.util.List;
42 
43 /**
44  * Class that lets you access the device's sensors. Get an instance of this
45  * class by calling {@link android.content.Context#getSystemService(java.lang.String)
46  * Context.getSystemService()} with an argument of {@link android.content.Context#SENSOR_SERVICE}.
47  */
48 public class SensorManager
49 {
50     private static final String TAG = "SensorManager";
51     private static final float[] mTempMatrix = new float[16];
52 
53     /* NOTE: sensor IDs must be a power of 2 */
54 
55     /**
56      * A constant describing an orientation sensor.
57      * See {@link android.hardware.SensorListener SensorListener} for more details.
58      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
59      */
60     @Deprecated
61     public static final int SENSOR_ORIENTATION = 1 << 0;
62 
63     /**
64      * A constant describing an accelerometer.
65      * See {@link android.hardware.SensorListener SensorListener} for more details.
66      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
67      */
68     @Deprecated
69     public static final int SENSOR_ACCELEROMETER = 1 << 1;
70 
71     /**
72      * A constant describing a temperature sensor
73      * See {@link android.hardware.SensorListener SensorListener} for more details.
74      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
75      */
76     @Deprecated
77     public static final int SENSOR_TEMPERATURE = 1 << 2;
78 
79     /**
80      * A constant describing a magnetic sensor
81      * See {@link android.hardware.SensorListener SensorListener} for more details.
82      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
83      */
84     @Deprecated
85     public static final int SENSOR_MAGNETIC_FIELD = 1 << 3;
86 
87     /**
88      * A constant describing an ambient light sensor
89      * See {@link android.hardware.SensorListener SensorListener} for more details.
90      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
91      */
92     @Deprecated
93     public static final int SENSOR_LIGHT = 1 << 4;
94 
95     /**
96      * A constant describing a proximity sensor
97      * See {@link android.hardware.SensorListener SensorListener} for more details.
98      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
99      */
100     @Deprecated
101     public static final int SENSOR_PROXIMITY = 1 << 5;
102 
103     /**
104      * A constant describing a Tricorder
105      * See {@link android.hardware.SensorListener SensorListener} for more details.
106      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
107      */
108     @Deprecated
109     public static final int SENSOR_TRICORDER = 1 << 6;
110 
111     /**
112      * A constant describing an orientation sensor.
113      * See {@link android.hardware.SensorListener SensorListener} for more details.
114      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
115      */
116     @Deprecated
117     public static final int SENSOR_ORIENTATION_RAW = 1 << 7;
118 
119     /** A constant that includes all sensors
120      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
121      */
122     @Deprecated
123     public static final int SENSOR_ALL = 0x7F;
124 
125     /** Smallest sensor ID
126      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
127      */
128     @Deprecated
129     public static final int SENSOR_MIN = SENSOR_ORIENTATION;
130 
131     /** Largest sensor ID
132      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
133      */
134     @Deprecated
135     public static final int SENSOR_MAX = ((SENSOR_ALL + 1)>>1);
136 
137 
138     /** Index of the X value in the array returned by
139      * {@link android.hardware.SensorListener#onSensorChanged}
140      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
141      */
142     @Deprecated
143     public static final int DATA_X = 0;
144     /** Index of the Y value in the array returned by
145      * {@link android.hardware.SensorListener#onSensorChanged}
146      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
147      */
148     @Deprecated
149     public static final int DATA_Y = 1;
150     /** Index of the Z value in the array returned by
151      * {@link android.hardware.SensorListener#onSensorChanged}
152      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
153      */
154     @Deprecated
155     public static final int DATA_Z = 2;
156 
157     /** Offset to the untransformed values in the array returned by
158      * {@link android.hardware.SensorListener#onSensorChanged}
159      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
160      */
161     @Deprecated
162     public static final int RAW_DATA_INDEX = 3;
163 
164     /** Index of the untransformed X value in the array returned by
165      * {@link android.hardware.SensorListener#onSensorChanged}
166      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
167      */
168     @Deprecated
169     public static final int RAW_DATA_X = 3;
170     /** Index of the untransformed Y value in the array returned by
171      * {@link android.hardware.SensorListener#onSensorChanged}
172      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
173      */
174     @Deprecated
175     public static final int RAW_DATA_Y = 4;
176     /** Index of the untransformed Z value in the array returned by
177      * {@link android.hardware.SensorListener#onSensorChanged}
178      * @deprecated use {@link android.hardware.Sensor Sensor} instead.
179      */
180     @Deprecated
181     public static final int RAW_DATA_Z = 5;
182 
183 
184     /** Standard gravity (g) on Earth. This value is equivalent to 1G */
185     public static final float STANDARD_GRAVITY = 9.80665f;
186 
187     /** values returned by the accelerometer in various locations in the universe.
188      * all values are in SI units (m/s^2) */
189     public static final float GRAVITY_SUN             = 275.0f;
190     public static final float GRAVITY_MERCURY         = 3.70f;
191     public static final float GRAVITY_VENUS           = 8.87f;
192     public static final float GRAVITY_EARTH           = 9.80665f;
193     public static final float GRAVITY_MOON            = 1.6f;
194     public static final float GRAVITY_MARS            = 3.71f;
195     public static final float GRAVITY_JUPITER         = 23.12f;
196     public static final float GRAVITY_SATURN          = 8.96f;
197     public static final float GRAVITY_URANUS          = 8.69f;
198     public static final float GRAVITY_NEPTUNE         = 11.0f;
199     public static final float GRAVITY_PLUTO           = 0.6f;
200     public static final float GRAVITY_DEATH_STAR_I    = 0.000000353036145f;
201     public static final float GRAVITY_THE_ISLAND      = 4.815162342f;
202 
203 
204     /** Maximum magnetic field on Earth's surface */
205     public static final float MAGNETIC_FIELD_EARTH_MAX = 60.0f;
206 
207     /** Minimum magnetic field on Earth's surface */
208     public static final float MAGNETIC_FIELD_EARTH_MIN = 30.0f;
209 
210 
211     /** Various luminance values during the day (lux) */
212     public static final float LIGHT_SUNLIGHT_MAX = 120000.0f;
213     public static final float LIGHT_SUNLIGHT     = 110000.0f;
214     public static final float LIGHT_SHADE        = 20000.0f;
215     public static final float LIGHT_OVERCAST     = 10000.0f;
216     public static final float LIGHT_SUNRISE      = 400.0f;
217     public static final float LIGHT_CLOUDY       = 100.0f;
218     /** Various luminance values during the night (lux) */
219     public static final float LIGHT_FULLMOON     = 0.25f;
220     public static final float LIGHT_NO_MOON      = 0.001f;
221 
222     /** get sensor data as fast as possible */
223     public static final int SENSOR_DELAY_FASTEST = 0;
224     /** rate suitable for games */
225     public static final int SENSOR_DELAY_GAME = 1;
226     /** rate suitable for the user interface  */
227     public static final int SENSOR_DELAY_UI = 2;
228     /** rate (default) suitable for screen orientation changes */
229     public static final int SENSOR_DELAY_NORMAL = 3;
230 
231 
232     /** The values returned by this sensor cannot be trusted, calibration
233      * is needed or the environment doesn't allow readings */
234     public static final int SENSOR_STATUS_UNRELIABLE = 0;
235 
236     /** This sensor is reporting data with low accuracy, calibration with the
237      * environment is needed */
238     public static final int SENSOR_STATUS_ACCURACY_LOW = 1;
239 
240     /** This sensor is reporting data with an average level of accuracy,
241      * calibration with the environment may improve the readings */
242     public static final int SENSOR_STATUS_ACCURACY_MEDIUM = 2;
243 
244     /** This sensor is reporting data with maximum accuracy */
245     public static final int SENSOR_STATUS_ACCURACY_HIGH = 3;
246 
247     /** see {@link #remapCoordinateSystem} */
248     public static final int AXIS_X = 1;
249     /** see {@link #remapCoordinateSystem} */
250     public static final int AXIS_Y = 2;
251     /** see {@link #remapCoordinateSystem} */
252     public static final int AXIS_Z = 3;
253     /** see {@link #remapCoordinateSystem} */
254     public static final int AXIS_MINUS_X = AXIS_X | 0x80;
255     /** see {@link #remapCoordinateSystem} */
256     public static final int AXIS_MINUS_Y = AXIS_Y | 0x80;
257     /** see {@link #remapCoordinateSystem} */
258     public static final int AXIS_MINUS_Z = AXIS_Z | 0x80;
259 
260     /*-----------------------------------------------------------------------*/
261 
262     private ISensorService mSensorService;
263     Looper mMainLooper;
264     @SuppressWarnings("deprecation")
265     private HashMap<SensorListener, LegacyListener> mLegacyListenersMap =
266         new HashMap<SensorListener, LegacyListener>();
267 
268     /*-----------------------------------------------------------------------*/
269 
270     private static final int SENSOR_DISABLE = -1;
271     private static boolean sSensorModuleInitialized = false;
272     private static ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>();
273     private static SparseArray<List<Sensor>> sSensorListByType = new SparseArray<List<Sensor>>();
274     private static IWindowManager sWindowManager;
275     private static int sRotation = Surface.ROTATION_0;
276     /* The thread and the sensor list are global to the process
277      * but the actual thread is spawned on demand */
278     private static SensorThread sSensorThread;
279 
280     // Used within this module from outside SensorManager, don't make private
281     static SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>();
282     static final ArrayList<ListenerDelegate> sListeners =
283         new ArrayList<ListenerDelegate>();
284 
285     /*-----------------------------------------------------------------------*/
286 
287     static private class SensorThread {
288 
289         Thread mThread;
290 
SensorThread()291         SensorThread() {
292             // this gets to the sensor module. We can have only one per process.
293             sensors_data_init();
294         }
295 
296         @Override
finalize()297         protected void finalize() {
298             sensors_data_uninit();
299         }
300 
301         // must be called with sListeners lock
startLocked(ISensorService service)302         void startLocked(ISensorService service) {
303             try {
304                 if (mThread == null) {
305                     Bundle dataChannel = service.getDataChannel();
306                     mThread = new Thread(new SensorThreadRunnable(dataChannel),
307                             SensorThread.class.getName());
308                     mThread.start();
309                 }
310             } catch (RemoteException e) {
311                 Log.e(TAG, "RemoteException in startLocked: ", e);
312             }
313         }
314 
315         private class SensorThreadRunnable implements Runnable {
316             private Bundle mDataChannel;
SensorThreadRunnable(Bundle dataChannel)317             SensorThreadRunnable(Bundle dataChannel) {
318                 mDataChannel = dataChannel;
319             }
320 
open()321             private boolean open() {
322                 if (mDataChannel == null) {
323                     Log.e(TAG, "mDataChannel == NULL, exiting");
324                     synchronized (sListeners) {
325                         mThread = null;
326                     }
327                     return false;
328                 }
329 
330                 // this thread is guaranteed to be unique
331                 Parcelable[] pfds = mDataChannel.getParcelableArray("fds");
332                 FileDescriptor[] fds;
333                 if (pfds != null) {
334                     int length = pfds.length;
335                     fds = new FileDescriptor[length];
336                     for (int i = 0; i < length; i++) {
337                         ParcelFileDescriptor pfd = (ParcelFileDescriptor)pfds[i];
338                         fds[i] = pfd.getFileDescriptor();
339                     }
340                 } else {
341                     fds = null;
342                 }
343                 int[] ints = mDataChannel.getIntArray("ints");
344                 sensors_data_open(fds, ints);
345                 if (pfds != null) {
346                     try {
347                         // close our copies of the file descriptors,
348                         // since we are just passing these to the JNI code and not using them here.
349                         for (int i = pfds.length - 1; i >= 0; i--) {
350                             ParcelFileDescriptor pfd = (ParcelFileDescriptor)pfds[i];
351                             pfd.close();
352                         }
353                     } catch (IOException e) {
354                         // *shrug*
355                         Log.e(TAG, "IOException: ", e);
356                     }
357                 }
358                 mDataChannel = null;
359                 return true;
360             }
361 
run()362             public void run() {
363                 //Log.d(TAG, "entering main sensor thread");
364                 final float[] values = new float[3];
365                 final int[] status = new int[1];
366                 final long timestamp[] = new long[1];
367                 Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
368 
369                 if (!open()) {
370                     return;
371                 }
372 
373                 while (true) {
374                     // wait for an event
375                     final int sensor = sensors_data_poll(values, status, timestamp);
376 
377                     int accuracy = status[0];
378                     synchronized (sListeners) {
379                         if (sensor == -1 || sListeners.isEmpty()) {
380                             if (sensor == -1) {
381                                 // we lost the connection to the event stream. this happens
382                                 // when the last listener is removed.
383                                 Log.d(TAG, "_sensors_data_poll() failed, we bail out.");
384                             }
385 
386                             // we have no more listeners or polling failed, terminate the thread
387                             sensors_data_close();
388                             mThread = null;
389                             break;
390                         }
391                         final Sensor sensorObject = sHandleToSensor.get(sensor);
392                         if (sensorObject != null) {
393                             // report the sensor event to all listeners that
394                             // care about it.
395                             final int size = sListeners.size();
396                             for (int i=0 ; i<size ; i++) {
397                                 ListenerDelegate listener = sListeners.get(i);
398                                 if (listener.hasSensor(sensorObject)) {
399                                     // this is asynchronous (okay to call
400                                     // with sListeners lock held).
401                                     listener.onSensorChangedLocked(sensorObject,
402                                             values, timestamp, accuracy);
403                                 }
404                             }
405                         }
406                     }
407                 }
408                 //Log.d(TAG, "exiting main sensor thread");
409             }
410         }
411     }
412 
413     /*-----------------------------------------------------------------------*/
414 
415     private class ListenerDelegate extends Binder {
416         final SensorEventListener mSensorEventListener;
417         private final ArrayList<Sensor> mSensorList = new ArrayList<Sensor>();
418         private final Handler mHandler;
419         private SensorEvent mValuesPool;
420         public int mSensors;
421 
ListenerDelegate(SensorEventListener listener, Sensor sensor, Handler handler)422         ListenerDelegate(SensorEventListener listener, Sensor sensor, Handler handler) {
423             mSensorEventListener = listener;
424             Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
425             // currently we create one Handler instance per listener, but we could
426             // have one per looper (we'd need to pass the ListenerDelegate
427             // instance to handleMessage and keep track of them separately).
428             mHandler = new Handler(looper) {
429                 @Override
430                 public void handleMessage(Message msg) {
431                     SensorEvent t = (SensorEvent)msg.obj;
432                     if (t.accuracy >= 0) {
433                         mSensorEventListener.onAccuracyChanged(t.sensor, t.accuracy);
434                     }
435                     mSensorEventListener.onSensorChanged(t);
436                     returnToPool(t);
437                 }
438             };
439             addSensor(sensor);
440         }
441 
createSensorEvent()442         protected SensorEvent createSensorEvent() {
443             // maximal size for all legacy events is 3
444             return new SensorEvent(3);
445         }
446 
getFromPool()447         protected SensorEvent getFromPool() {
448             SensorEvent t = null;
449             synchronized (this) {
450                 // remove the array from the pool
451                 t = mValuesPool;
452                 mValuesPool = null;
453             }
454             if (t == null) {
455                 // the pool was empty, we need a new one
456                 t = createSensorEvent();
457             }
458             return t;
459         }
460 
returnToPool(SensorEvent t)461         protected void returnToPool(SensorEvent t) {
462             synchronized (this) {
463                 // put back the array into the pool
464                 if (mValuesPool == null) {
465                     mValuesPool = t;
466                 }
467             }
468         }
469 
getListener()470         Object getListener() {
471             return mSensorEventListener;
472         }
473 
addSensor(Sensor sensor)474         int addSensor(Sensor sensor) {
475             mSensors |= 1<<sensor.getHandle();
476             mSensorList.add(sensor);
477             return mSensors;
478         }
removeSensor(Sensor sensor)479         int removeSensor(Sensor sensor) {
480             mSensors &= ~(1<<sensor.getHandle());
481             mSensorList.remove(sensor);
482             return mSensors;
483         }
hasSensor(Sensor sensor)484         boolean hasSensor(Sensor sensor) {
485             return ((mSensors & (1<<sensor.getHandle())) != 0);
486         }
getSensors()487         List<Sensor> getSensors() {
488             return mSensorList;
489         }
490 
onSensorChangedLocked(Sensor sensor, float[] values, long[] timestamp, int accuracy)491         void onSensorChangedLocked(Sensor sensor, float[] values, long[] timestamp, int accuracy) {
492             SensorEvent t = getFromPool();
493             final float[] v = t.values;
494             v[0] = values[0];
495             v[1] = values[1];
496             v[2] = values[2];
497             t.timestamp = timestamp[0];
498             t.accuracy = accuracy;
499             t.sensor = sensor;
500             Message msg = Message.obtain();
501             msg.what = 0;
502             msg.obj = t;
503             mHandler.sendMessage(msg);
504         }
505     }
506 
507     /**
508      * {@hide}
509      */
SensorManager(Looper mainLooper)510     public SensorManager(Looper mainLooper) {
511         mSensorService = ISensorService.Stub.asInterface(
512                 ServiceManager.getService(Context.SENSOR_SERVICE));
513         mMainLooper = mainLooper;
514 
515 
516         synchronized(sListeners) {
517             if (!sSensorModuleInitialized) {
518                 sSensorModuleInitialized = true;
519 
520                 nativeClassInit();
521 
522                 sWindowManager = IWindowManager.Stub.asInterface(
523                         ServiceManager.getService("window"));
524                 if (sWindowManager != null) {
525                     // if it's null we're running in the system process
526                     // which won't get the rotated values
527                     try {
528                         sRotation = sWindowManager.watchRotation(
529                             new IRotationWatcher.Stub() {
530                                 public void onRotationChanged(int rotation) {
531                                     SensorManager.this.onRotationChanged(rotation);
532                                 }
533                             }
534                         );
535                     } catch (RemoteException e) {
536                     }
537                 }
538 
539                 // initialize the sensor list
540                 sensors_module_init();
541                 final ArrayList<Sensor> fullList = sFullSensorsList;
542                 int i = 0;
543                 do {
544                     Sensor sensor = new Sensor();
545                     i = sensors_module_get_next_sensor(sensor, i);
546 
547                     if (i>=0) {
548                         Log.d(TAG, "found sensor: " + sensor.getName() +
549                                 ", handle=" + sensor.getHandle());
550                         sensor.setLegacyType(getLegacySensorType(sensor.getType()));
551                         fullList.add(sensor);
552                         sHandleToSensor.append(sensor.getHandle(), sensor);
553                     }
554                 } while (i>0);
555 
556                 sSensorThread = new SensorThread();
557             }
558         }
559     }
560 
getLegacySensorType(int type)561     private int getLegacySensorType(int type) {
562         switch (type) {
563             case Sensor.TYPE_ACCELEROMETER:
564                 return SENSOR_ACCELEROMETER;
565             case Sensor.TYPE_MAGNETIC_FIELD:
566                 return SENSOR_MAGNETIC_FIELD;
567             case Sensor.TYPE_ORIENTATION:
568                 return SENSOR_ORIENTATION_RAW;
569             case Sensor.TYPE_TEMPERATURE:
570                 return SENSOR_TEMPERATURE;
571         }
572         return 0;
573     }
574 
575     /** @return available sensors.
576      * @deprecated This method is deprecated, use
577      * {@link SensorManager#getSensorList(int)} instead
578      */
579     @Deprecated
getSensors()580     public int getSensors() {
581         int result = 0;
582         final ArrayList<Sensor> fullList = sFullSensorsList;
583         for (Sensor i : fullList) {
584             switch (i.getType()) {
585                 case Sensor.TYPE_ACCELEROMETER:
586                     result |= SensorManager.SENSOR_ACCELEROMETER;
587                     break;
588                 case Sensor.TYPE_MAGNETIC_FIELD:
589                     result |= SensorManager.SENSOR_MAGNETIC_FIELD;
590                     break;
591                 case Sensor.TYPE_ORIENTATION:
592                     result |= SensorManager.SENSOR_ORIENTATION |
593                                     SensorManager.SENSOR_ORIENTATION_RAW;
594                     break;
595             }
596         }
597         return result;
598     }
599 
600     /**
601      * Use this method to get the list of available sensors of a certain
602      * type. Make multiple calls to get sensors of different types or use
603      * {@link android.hardware.Sensor#TYPE_ALL Sensor.TYPE_ALL} to get all
604      * the sensors.
605      *
606      * @param type of sensors requested
607      * @return a list of sensors matching the asked type.
608      */
getSensorList(int type)609     public List<Sensor> getSensorList(int type) {
610         // cache the returned lists the first time
611         List<Sensor> list;
612         final ArrayList<Sensor> fullList = sFullSensorsList;
613         synchronized(fullList) {
614             list = sSensorListByType.get(type);
615             if (list == null) {
616                 if (type == Sensor.TYPE_ALL) {
617                     list = fullList;
618                 } else {
619                     list = new ArrayList<Sensor>();
620                     for (Sensor i : fullList) {
621                         if (i.getType() == type)
622                             list.add(i);
623                     }
624                 }
625                 list = Collections.unmodifiableList(list);
626                 sSensorListByType.append(type, list);
627             }
628         }
629         return list;
630     }
631 
632     /**
633      * Use this method to get the default sensor for a given type. Note that
634      * the returned sensor could be a composite sensor, and its data could be
635      * averaged or filtered. If you need to access the raw sensors use
636      * {@link SensorManager#getSensorList(int) getSensorList}.
637      *
638      *
639      * @param type of sensors requested
640      * @return the default sensors matching the asked type.
641      */
getDefaultSensor(int type)642     public Sensor getDefaultSensor(int type) {
643         // TODO: need to be smarter, for now, just return the 1st sensor
644         List<Sensor> l = getSensorList(type);
645         return l.isEmpty() ? null : l.get(0);
646     }
647 
648 
649     /**
650      * Registers a listener for given sensors.
651      * @deprecated This method is deprecated, use
652      * {@link SensorManager#registerListener(SensorEventListener, Sensor, int)}
653      * instead.
654      *
655      * @param listener sensor listener object
656      * @param sensors a bit masks of the sensors to register to
657      *
658      * @return true if the sensor is supported and successfully enabled
659      */
660     @Deprecated
registerListener(SensorListener listener, int sensors)661     public boolean registerListener(SensorListener listener, int sensors) {
662         return registerListener(listener, sensors, SENSOR_DELAY_NORMAL);
663     }
664 
665     /**
666      * Registers a SensorListener for given sensors.
667      * @deprecated This method is deprecated, use
668      * {@link SensorManager#registerListener(SensorEventListener, Sensor, int)}
669      * instead.
670      *
671      * @param listener sensor listener object
672      * @param sensors a bit masks of the sensors to register to
673      * @param rate rate of events. This is only a hint to the system. events
674      * may be received faster or slower than the specified rate. Usually events
675      * are received faster. The value must be one of {@link #SENSOR_DELAY_NORMAL},
676      * {@link #SENSOR_DELAY_UI}, {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}.
677      *
678      * @return true if the sensor is supported and successfully enabled
679      */
680     @Deprecated
registerListener(SensorListener listener, int sensors, int rate)681     public boolean registerListener(SensorListener listener, int sensors, int rate) {
682         if (listener == null) {
683             return false;
684         }
685         boolean result = false;
686         result = registerLegacyListener(SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER,
687                 listener, sensors, rate) || result;
688         result = registerLegacyListener(SENSOR_MAGNETIC_FIELD, Sensor.TYPE_MAGNETIC_FIELD,
689                 listener, sensors, rate) || result;
690         result = registerLegacyListener(SENSOR_ORIENTATION_RAW, Sensor.TYPE_ORIENTATION,
691                 listener, sensors, rate) || result;
692         result = registerLegacyListener(SENSOR_ORIENTATION, Sensor.TYPE_ORIENTATION,
693                 listener, sensors, rate) || result;
694         result = registerLegacyListener(SENSOR_TEMPERATURE, Sensor.TYPE_TEMPERATURE,
695                 listener, sensors, rate) || result;
696         return result;
697     }
698 
699     @SuppressWarnings("deprecation")
registerLegacyListener(int legacyType, int type, SensorListener listener, int sensors, int rate)700     private boolean registerLegacyListener(int legacyType, int type,
701             SensorListener listener, int sensors, int rate)
702     {
703         if (listener == null) {
704             return false;
705         }
706         boolean result = false;
707         // Are we activating this legacy sensor?
708         if ((sensors & legacyType) != 0) {
709             // if so, find a suitable Sensor
710             Sensor sensor = getDefaultSensor(type);
711             if (sensor != null) {
712                 // If we don't already have one, create a LegacyListener
713                 // to wrap this listener and process the events as
714                 // they are expected by legacy apps.
715                 LegacyListener legacyListener = null;
716                 synchronized (mLegacyListenersMap) {
717                     legacyListener = mLegacyListenersMap.get(listener);
718                     if (legacyListener == null) {
719                         // we didn't find a LegacyListener for this client,
720                         // create one, and put it in our list.
721                         legacyListener = new LegacyListener(listener);
722                         mLegacyListenersMap.put(listener, legacyListener);
723                     }
724                 }
725                 // register this legacy sensor with this legacy listener
726                 legacyListener.registerSensor(legacyType);
727                 // and finally, register the legacy listener with the new apis
728                 result = registerListener(legacyListener, sensor, rate);
729             }
730         }
731         return result;
732     }
733 
734     /**
735      * Unregisters a listener for the sensors with which it is registered.
736      * @deprecated This method is deprecated, use
737      * {@link SensorManager#unregisterListener(SensorEventListener, Sensor)}
738      * instead.
739      *
740      * @param listener a SensorListener object
741      * @param sensors a bit masks of the sensors to unregister from
742      */
743     @Deprecated
unregisterListener(SensorListener listener, int sensors)744     public void unregisterListener(SensorListener listener, int sensors) {
745         unregisterLegacyListener(SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER,
746                 listener, sensors);
747         unregisterLegacyListener(SENSOR_MAGNETIC_FIELD, Sensor.TYPE_MAGNETIC_FIELD,
748                 listener, sensors);
749         unregisterLegacyListener(SENSOR_ORIENTATION_RAW, Sensor.TYPE_ORIENTATION,
750                 listener, sensors);
751         unregisterLegacyListener(SENSOR_ORIENTATION, Sensor.TYPE_ORIENTATION,
752                 listener, sensors);
753         unregisterLegacyListener(SENSOR_TEMPERATURE, Sensor.TYPE_TEMPERATURE,
754                 listener, sensors);
755     }
756 
757     @SuppressWarnings("deprecation")
unregisterLegacyListener(int legacyType, int type, SensorListener listener, int sensors)758     private void unregisterLegacyListener(int legacyType, int type,
759             SensorListener listener, int sensors)
760     {
761         if (listener == null) {
762             return;
763         }
764         // do we know about this listener?
765         LegacyListener legacyListener = null;
766         synchronized (mLegacyListenersMap) {
767             legacyListener = mLegacyListenersMap.get(listener);
768         }
769         if (legacyListener != null) {
770             // Are we deactivating this legacy sensor?
771             if ((sensors & legacyType) != 0) {
772                 // if so, find the corresponding Sensor
773                 Sensor sensor = getDefaultSensor(type);
774                 if (sensor != null) {
775                     // unregister this legacy sensor and if we don't
776                     // need the corresponding Sensor, unregister it too
777                     if (legacyListener.unregisterSensor(legacyType)) {
778                         // corresponding sensor not needed, unregister
779                         unregisterListener(legacyListener, sensor);
780                         // finally check if we still need the legacyListener
781                         // in our mapping, if not, get rid of it too.
782                         synchronized(sListeners) {
783                             boolean found = false;
784                             for (ListenerDelegate i : sListeners) {
785                                 if (i.getListener() == legacyListener) {
786                                     found = true;
787                                     break;
788                                 }
789                             }
790                             if (!found) {
791                                 synchronized (mLegacyListenersMap) {
792                                     mLegacyListenersMap.remove(listener);
793                                 }
794                             }
795                         }
796                     }
797                 }
798             }
799         }
800     }
801 
802     /**
803      * Unregisters a listener for all sensors.
804      * @deprecated This method is deprecated, use
805      * {@link SensorManager#unregisterListener(SensorEventListener)}
806      * instead.
807      *
808      * @param listener a SensorListener object
809      */
810     @Deprecated
unregisterListener(SensorListener listener)811     public void unregisterListener(SensorListener listener) {
812         unregisterListener(listener, SENSOR_ALL | SENSOR_ORIENTATION_RAW);
813     }
814 
815     /**
816      * Unregisters a listener for the sensors with which it is registered.
817      *
818      * @param listener a SensorEventListener object
819      * @param sensor the sensor to unregister from
820      *
821      */
unregisterListener(SensorEventListener listener, Sensor sensor)822     public void unregisterListener(SensorEventListener listener, Sensor sensor) {
823         unregisterListener((Object)listener, sensor);
824     }
825 
826     /**
827      * Unregisters a listener for all sensors.
828      *
829      * @param listener a SensorListener object
830      *
831      */
unregisterListener(SensorEventListener listener)832     public void unregisterListener(SensorEventListener listener) {
833         unregisterListener((Object)listener);
834     }
835 
836 
837     /**
838      * Registers a {@link android.hardware.SensorEventListener SensorEventListener}
839      * for the given sensor.
840      *
841      * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object.
842      * @param sensor The {@link android.hardware.Sensor Sensor} to register to.
843      * @param rate The rate {@link android.hardware.SensorEvent sensor events} are delivered at.
844      * This is only a hint to the system. Events may be received faster or
845      * slower than the specified rate. Usually events are received faster. The value must be
846      * one of {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI}, {@link #SENSOR_DELAY_GAME},
847      * or {@link #SENSOR_DELAY_FASTEST}.
848      *
849      * @return true if the sensor is supported and successfully enabled.
850      *
851      */
registerListener(SensorEventListener listener, Sensor sensor, int rate)852     public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate) {
853         return registerListener(listener, sensor, rate, null);
854     }
855 
856     /**
857      * Registers a {@link android.hardware.SensorEventListener SensorEventListener}
858      * for the given sensor.
859      *
860      * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object.
861      * @param sensor The {@link android.hardware.Sensor Sensor} to register to.
862      * @param rate The rate {@link android.hardware.SensorEvent sensor events} are delivered at.
863      * This is only a hint to the system. Events may be received faster or
864      * slower than the specified rate. Usually events are received faster. The value must be one
865      * of {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI}, {@link #SENSOR_DELAY_GAME}, or
866      * {@link #SENSOR_DELAY_FASTEST}.
867      * @param handler The {@link android.os.Handler Handler} the
868      * {@link android.hardware.SensorEvent sensor events} will be delivered to.
869      *
870      * @return true if the sensor is supported and successfully enabled.
871      *
872      */
registerListener(SensorEventListener listener, Sensor sensor, int rate, Handler handler)873     public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate,
874             Handler handler) {
875         if (listener == null || sensor == null) {
876             return false;
877         }
878         boolean result;
879         int delay = -1;
880         switch (rate) {
881             case SENSOR_DELAY_FASTEST:
882                 delay = 0;
883                 break;
884             case SENSOR_DELAY_GAME:
885                 delay = 20;
886                 break;
887             case SENSOR_DELAY_UI:
888                 delay = 60;
889                 break;
890             case SENSOR_DELAY_NORMAL:
891                 delay = 200;
892                 break;
893             default:
894                 return false;
895         }
896 
897         try {
898             synchronized (sListeners) {
899                 ListenerDelegate l = null;
900                 for (ListenerDelegate i : sListeners) {
901                     if (i.getListener() == listener) {
902                         l = i;
903                         break;
904                     }
905                 }
906 
907                 String name = sensor.getName();
908                 int handle = sensor.getHandle();
909                 if (l == null) {
910                     l = new ListenerDelegate(listener, sensor, handler);
911                     result = mSensorService.enableSensor(l, name, handle, delay);
912                     if (result) {
913                         sListeners.add(l);
914                         sListeners.notify();
915                     }
916                     if (!sListeners.isEmpty()) {
917                         sSensorThread.startLocked(mSensorService);
918                     }
919                 } else {
920                     result = mSensorService.enableSensor(l, name, handle, delay);
921                     if (result) {
922                         l.addSensor(sensor);
923                     }
924                 }
925             }
926         } catch (RemoteException e) {
927             Log.e(TAG, "RemoteException in registerListener: ", e);
928             result = false;
929         }
930         return result;
931     }
932 
unregisterListener(Object listener, Sensor sensor)933     private void unregisterListener(Object listener, Sensor sensor) {
934         if (listener == null || sensor == null) {
935             return;
936         }
937         try {
938             synchronized (sListeners) {
939                 final int size = sListeners.size();
940                 for (int i=0 ; i<size ; i++) {
941                     ListenerDelegate l = sListeners.get(i);
942                     if (l.getListener() == listener) {
943                         // disable these sensors
944                         String name = sensor.getName();
945                         int handle = sensor.getHandle();
946                         mSensorService.enableSensor(l, name, handle, SENSOR_DISABLE);
947                         // if we have no more sensors enabled on this listener,
948                         // take it off the list.
949                         if (l.removeSensor(sensor) == 0) {
950                             sListeners.remove(i);
951                         }
952                         break;
953                     }
954                 }
955             }
956         } catch (RemoteException e) {
957             Log.e(TAG, "RemoteException in unregisterListener: ", e);
958         }
959     }
960 
unregisterListener(Object listener)961     private void unregisterListener(Object listener) {
962         if (listener == null) {
963             return;
964         }
965         try {
966             synchronized (sListeners) {
967                 final int size = sListeners.size();
968                 for (int i=0 ; i<size ; i++) {
969                     ListenerDelegate l = sListeners.get(i);
970                     if (l.getListener() == listener) {
971                         // disable all sensors for this listener
972                         for (Sensor sensor : l.getSensors()) {
973                             String name = sensor.getName();
974                             int handle = sensor.getHandle();
975                             mSensorService.enableSensor(l, name, handle, SENSOR_DISABLE);
976                         }
977                         sListeners.remove(i);
978                         break;
979                     }
980                 }
981             }
982         } catch (RemoteException e) {
983             Log.e(TAG, "RemoteException in unregisterListener: ", e);
984         }
985     }
986 
987     /**
988      * Computes the inclination matrix <b>I</b> as well as the rotation
989      * matrix <b>R</b> transforming a vector from the
990      * device coordinate system to the world's coordinate system which is
991      * defined as a direct orthonormal basis, where:
992      *
993      * <li>X is defined as the vector product <b>Y.Z</b> (It is tangential to
994      * the ground at the device's current location and roughly points East).</li>
995      * <li>Y is tangential to the ground at the device's current location and
996      * points towards the magnetic North Pole.</li>
997      * <li>Z points towards the sky and is perpendicular to the ground.</li>
998      * <p>
999      * <hr>
1000      * <p>By definition:
1001      * <p>[0 0 g] = <b>R</b> * <b>gravity</b> (g = magnitude of gravity)
1002      * <p>[0 m 0] = <b>I</b> * <b>R</b> * <b>geomagnetic</b>
1003      * (m = magnitude of geomagnetic field)
1004      * <p><b>R</b> is the identity matrix when the device is aligned with the
1005      * world's coordinate system, that is, when the device's X axis points
1006      * toward East, the Y axis points to the North Pole and the device is facing
1007      * the sky.
1008      *
1009      * <p><b>I</b> is a rotation matrix transforming the geomagnetic
1010      * vector into the same coordinate space as gravity (the world's coordinate
1011      * space). <b>I</b> is a simple rotation around the X axis.
1012      * The inclination angle in radians can be computed with
1013      * {@link #getInclination}.
1014      * <hr>
1015      *
1016      * <p> Each matrix is returned either as a 3x3 or 4x4 row-major matrix
1017      * depending on the length of the passed array:
1018      * <p><u>If the array length is 16:</u>
1019      * <pre>
1020      *   /  M[ 0]   M[ 1]   M[ 2]   M[ 3]  \
1021      *   |  M[ 4]   M[ 5]   M[ 6]   M[ 7]  |
1022      *   |  M[ 8]   M[ 9]   M[10]   M[11]  |
1023      *   \  M[12]   M[13]   M[14]   M[15]  /
1024      *</pre>
1025      * This matrix is ready to be used by OpenGL ES's
1026      * {@link javax.microedition.khronos.opengles.GL10#glLoadMatrixf(float[], int)
1027      * glLoadMatrixf(float[], int)}.
1028      * <p>Note that because OpenGL matrices are column-major matrices you must
1029      * transpose the matrix before using it. However, since the matrix is a
1030      * rotation matrix, its transpose is also its inverse, conveniently, it is
1031      * often the inverse of the rotation that is needed for rendering; it can
1032      * therefore be used with OpenGL ES directly.
1033      * <p>
1034      * Also note that the returned matrices always have this form:
1035      * <pre>
1036      *   /  M[ 0]   M[ 1]   M[ 2]   0  \
1037      *   |  M[ 4]   M[ 5]   M[ 6]   0  |
1038      *   |  M[ 8]   M[ 9]   M[10]   0  |
1039      *   \      0       0       0   1  /
1040      *</pre>
1041      * <p><u>If the array length is 9:</u>
1042      * <pre>
1043      *   /  M[ 0]   M[ 1]   M[ 2]  \
1044      *   |  M[ 3]   M[ 4]   M[ 5]  |
1045      *   \  M[ 6]   M[ 7]   M[ 8]  /
1046      *</pre>
1047      *
1048      * <hr>
1049      * <p>The inverse of each matrix can be computed easily by taking its
1050      * transpose.
1051      *
1052      * <p>The matrices returned by this function are meaningful only when the
1053      * device is not free-falling and it is not close to the magnetic north.
1054      * If the device is accelerating, or placed into a strong magnetic field,
1055      * the returned matrices may be inaccurate.
1056      *
1057      * @param R is an array of 9 floats holding the rotation matrix <b>R</b>
1058      * when this function returns. R can be null.<p>
1059      * @param I is an array of 9 floats holding the rotation matrix <b>I</b>
1060      * when this function returns. I can be null.<p>
1061      * @param gravity is an array of 3 floats containing the gravity vector
1062      * expressed in the device's coordinate. You can simply use the
1063      * {@link android.hardware.SensorEvent#values values}
1064      * returned by a {@link android.hardware.SensorEvent SensorEvent} of a
1065      * {@link android.hardware.Sensor Sensor} of type
1066      * {@link android.hardware.Sensor#TYPE_ACCELEROMETER TYPE_ACCELEROMETER}.<p>
1067      * @param geomagnetic is an array of 3 floats containing the geomagnetic
1068      * vector expressed in the device's coordinate. You can simply use the
1069      * {@link android.hardware.SensorEvent#values values}
1070      * returned by a {@link android.hardware.SensorEvent SensorEvent} of a
1071      * {@link android.hardware.Sensor Sensor} of type
1072      * {@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD TYPE_MAGNETIC_FIELD}.
1073      * @return
1074      *   true on success<p>
1075      *   false on failure (for instance, if the device is in free fall).
1076      *   On failure the output matrices are not modified.
1077      */
1078 
getRotationMatrix(float[] R, float[] I, float[] gravity, float[] geomagnetic)1079     public static boolean getRotationMatrix(float[] R, float[] I,
1080             float[] gravity, float[] geomagnetic) {
1081         // TODO: move this to native code for efficiency
1082         float Ax = gravity[0];
1083         float Ay = gravity[1];
1084         float Az = gravity[2];
1085         final float Ex = geomagnetic[0];
1086         final float Ey = geomagnetic[1];
1087         final float Ez = geomagnetic[2];
1088         float Hx = Ey*Az - Ez*Ay;
1089         float Hy = Ez*Ax - Ex*Az;
1090         float Hz = Ex*Ay - Ey*Ax;
1091         final float normH = (float)Math.sqrt(Hx*Hx + Hy*Hy + Hz*Hz);
1092         if (normH < 0.1f) {
1093             // device is close to free fall (or in space?), or close to
1094             // magnetic north pole. Typical values are  > 100.
1095             return false;
1096         }
1097         final float invH = 1.0f / normH;
1098         Hx *= invH;
1099         Hy *= invH;
1100         Hz *= invH;
1101         final float invA = 1.0f / (float)Math.sqrt(Ax*Ax + Ay*Ay + Az*Az);
1102         Ax *= invA;
1103         Ay *= invA;
1104         Az *= invA;
1105         final float Mx = Ay*Hz - Az*Hy;
1106         final float My = Az*Hx - Ax*Hz;
1107         final float Mz = Ax*Hy - Ay*Hx;
1108         if (R != null) {
1109             if (R.length == 9) {
1110                 R[0] = Hx;     R[1] = Hy;     R[2] = Hz;
1111                 R[3] = Mx;     R[4] = My;     R[5] = Mz;
1112                 R[6] = Ax;     R[7] = Ay;     R[8] = Az;
1113             } else if (R.length == 16) {
1114                 R[0]  = Hx;    R[1]  = Hy;    R[2]  = Hz;   R[3]  = 0;
1115                 R[4]  = Mx;    R[5]  = My;    R[6]  = Mz;   R[7]  = 0;
1116                 R[8]  = Ax;    R[9]  = Ay;    R[10] = Az;   R[11] = 0;
1117                 R[12] = 0;     R[13] = 0;     R[14] = 0;    R[15] = 1;
1118             }
1119         }
1120         if (I != null) {
1121             // compute the inclination matrix by projecting the geomagnetic
1122             // vector onto the Z (gravity) and X (horizontal component
1123             // of geomagnetic vector) axes.
1124             final float invE = 1.0f / (float)Math.sqrt(Ex*Ex + Ey*Ey + Ez*Ez);
1125             final float c = (Ex*Mx + Ey*My + Ez*Mz) * invE;
1126             final float s = (Ex*Ax + Ey*Ay + Ez*Az) * invE;
1127             if (I.length == 9) {
1128                 I[0] = 1;     I[1] = 0;     I[2] = 0;
1129                 I[3] = 0;     I[4] = c;     I[5] = s;
1130                 I[6] = 0;     I[7] =-s;     I[8] = c;
1131             } else if (I.length == 16) {
1132                 I[0] = 1;     I[1] = 0;     I[2] = 0;
1133                 I[4] = 0;     I[5] = c;     I[6] = s;
1134                 I[8] = 0;     I[9] =-s;     I[10]= c;
1135                 I[3] = I[7] = I[11] = I[12] = I[13] = I[14] = 0;
1136                 I[15] = 1;
1137             }
1138         }
1139         return true;
1140     }
1141 
1142     /**
1143      * Computes the geomagnetic inclination angle in radians from the
1144      * inclination matrix <b>I</b> returned by {@link #getRotationMatrix}.
1145      * @param I inclination matrix see {@link #getRotationMatrix}.
1146      * @return The geomagnetic inclination angle in radians.
1147      */
getInclination(float[] I)1148     public static float getInclination(float[] I) {
1149         if (I.length == 9) {
1150             return (float)Math.atan2(I[5], I[4]);
1151         } else {
1152             return (float)Math.atan2(I[6], I[5]);
1153         }
1154     }
1155 
1156     /**
1157      * Rotates the supplied rotation matrix so it is expressed in a
1158      * different coordinate system. This is typically used when an application
1159      * needs to compute the three orientation angles of the device (see
1160      * {@link #getOrientation}) in a different coordinate system.
1161      *
1162      * <p>When the rotation matrix is used for drawing (for instance with
1163      * OpenGL ES), it usually <b>doesn't need</b> to be transformed by this
1164      * function, unless the screen is physically rotated, such as when used
1165      * in landscape mode.
1166      *
1167      * <p><u>Examples:</u><p>
1168      *
1169      * <li>Using the camera (Y axis along the camera's axis) for an augmented
1170      * reality application where the rotation angles are needed :</li><p>
1171      *
1172      * <code>remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR);</code><p>
1173      *
1174      * <li>Using the device as a mechanical compass in landscape mode:</li><p>
1175      *
1176      * <code>remapCoordinateSystem(inR, AXIS_Y, AXIS_MINUS_X, outR);</code><p>
1177      *
1178      * Beware of the above example. This call is needed only if the device is
1179      * physically used in landscape mode to calculate the rotation angles (see
1180      * {@link #getOrientation}).
1181      * If the rotation matrix is also used for rendering, it may not need to
1182      * be transformed, for instance if your {@link android.app.Activity
1183      * Activity} is running in landscape mode.
1184      *
1185      * <p>Since the resulting coordinate system is orthonormal, only two axes
1186      * need to be specified.
1187      *
1188      * @param inR the rotation matrix to be transformed. Usually it is the
1189      * matrix returned by {@link #getRotationMatrix}.
1190      * @param X defines on which world axis and direction the X axis of the
1191      *        device is mapped.
1192      * @param Y defines on which world axis and direction the Y axis of the
1193      *        device is mapped.
1194      * @param outR the transformed rotation matrix. inR and outR can be the same
1195      *        array, but it is not recommended for performance reason.
1196      * @return true on success. false if the input parameters are incorrect, for
1197      * instance if X and Y define the same axis. Or if inR and outR don't have
1198      * the same length.
1199      */
1200 
remapCoordinateSystem(float[] inR, int X, int Y, float[] outR)1201     public static boolean remapCoordinateSystem(float[] inR, int X, int Y,
1202             float[] outR)
1203     {
1204         if (inR == outR) {
1205             final float[] temp = mTempMatrix;
1206             synchronized(temp) {
1207                 // we don't expect to have a lot of contention
1208                 if (remapCoordinateSystemImpl(inR, X, Y, temp)) {
1209                     final int size = outR.length;
1210                     for (int i=0 ; i<size ; i++)
1211                         outR[i] = temp[i];
1212                     return true;
1213                 }
1214             }
1215         }
1216         return remapCoordinateSystemImpl(inR, X, Y, outR);
1217     }
1218 
remapCoordinateSystemImpl(float[] inR, int X, int Y, float[] outR)1219     private static boolean remapCoordinateSystemImpl(float[] inR, int X, int Y,
1220             float[] outR)
1221     {
1222         /*
1223          * X and Y define a rotation matrix 'r':
1224          *
1225          *  (X==1)?((X&0x80)?-1:1):0    (X==2)?((X&0x80)?-1:1):0    (X==3)?((X&0x80)?-1:1):0
1226          *  (Y==1)?((Y&0x80)?-1:1):0    (Y==2)?((Y&0x80)?-1:1):0    (Y==3)?((X&0x80)?-1:1):0
1227          *                              r[0] ^ r[1]
1228          *
1229          * where the 3rd line is the vector product of the first 2 lines
1230          *
1231          */
1232 
1233         final int length = outR.length;
1234         if (inR.length != length)
1235             return false;   // invalid parameter
1236         if ((X & 0x7C)!=0 || (Y & 0x7C)!=0)
1237             return false;   // invalid parameter
1238         if (((X & 0x3)==0) || ((Y & 0x3)==0))
1239             return false;   // no axis specified
1240         if ((X & 0x3) == (Y & 0x3))
1241             return false;   // same axis specified
1242 
1243         // Z is "the other" axis, its sign is either +/- sign(X)*sign(Y)
1244         // this can be calculated by exclusive-or'ing X and Y; except for
1245         // the sign inversion (+/-) which is calculated below.
1246         int Z = X ^ Y;
1247 
1248         // extract the axis (remove the sign), offset in the range 0 to 2.
1249         final int x = (X & 0x3)-1;
1250         final int y = (Y & 0x3)-1;
1251         final int z = (Z & 0x3)-1;
1252 
1253         // compute the sign of Z (whether it needs to be inverted)
1254         final int axis_y = (z+1)%3;
1255         final int axis_z = (z+2)%3;
1256         if (((x^axis_y)|(y^axis_z)) != 0)
1257             Z ^= 0x80;
1258 
1259         final boolean sx = (X>=0x80);
1260         final boolean sy = (Y>=0x80);
1261         final boolean sz = (Z>=0x80);
1262 
1263         // Perform R * r, in avoiding actual muls and adds.
1264         final int rowLength = ((length==16)?4:3);
1265         for (int j=0 ; j<3 ; j++) {
1266             final int offset = j*rowLength;
1267             for (int i=0 ; i<3 ; i++) {
1268                 if (x==i)   outR[offset+i] = sx ? -inR[offset+0] : inR[offset+0];
1269                 if (y==i)   outR[offset+i] = sy ? -inR[offset+1] : inR[offset+1];
1270                 if (z==i)   outR[offset+i] = sz ? -inR[offset+2] : inR[offset+2];
1271             }
1272         }
1273         if (length == 16) {
1274             outR[3] = outR[7] = outR[11] = outR[12] = outR[13] = outR[14] = 0;
1275             outR[15] = 1;
1276         }
1277         return true;
1278     }
1279 
1280     /**
1281      * Computes the device's orientation based on the rotation matrix.
1282      * <p> When it returns, the array values is filled with the result:
1283      * <li>values[0]: <i>azimuth</i>, rotation around the Z axis.</li>
1284      * <li>values[1]: <i>pitch</i>, rotation around the X axis.</li>
1285      * <li>values[2]: <i>roll</i>, rotation around the Y axis.</li>
1286      * <p>
1287      *
1288      * @param R rotation matrix see {@link #getRotationMatrix}.
1289      * @param values an array of 3 floats to hold the result.
1290      * @return The array values passed as argument.
1291      */
getOrientation(float[] R, float values[])1292     public static float[] getOrientation(float[] R, float values[]) {
1293         /*
1294          * 4x4 (length=16) case:
1295          *   /  R[ 0]   R[ 1]   R[ 2]   0  \
1296          *   |  R[ 4]   R[ 5]   R[ 6]   0  |
1297          *   |  R[ 8]   R[ 9]   R[10]   0  |
1298          *   \      0       0       0   1  /
1299          *
1300          * 3x3 (length=9) case:
1301          *   /  R[ 0]   R[ 1]   R[ 2]  \
1302          *   |  R[ 3]   R[ 4]   R[ 5]  |
1303          *   \  R[ 6]   R[ 7]   R[ 8]  /
1304          *
1305          */
1306         if (R.length == 9) {
1307             values[0] = (float)Math.atan2(R[1], R[4]);
1308             values[1] = (float)Math.asin(-R[7]);
1309             values[2] = (float)Math.atan2(-R[6], R[8]);
1310         } else {
1311             values[0] = (float)Math.atan2(R[1], R[5]);
1312             values[1] = (float)Math.asin(-R[9]);
1313             values[2] = (float)Math.atan2(-R[8], R[10]);
1314         }
1315         return values;
1316     }
1317 
1318 
1319     /**
1320      * {@hide}
1321      */
onRotationChanged(int rotation)1322     public void onRotationChanged(int rotation) {
1323         synchronized(sListeners) {
1324             sRotation  = rotation;
1325         }
1326     }
1327 
getRotation()1328     static int getRotation() {
1329         synchronized(sListeners) {
1330             return sRotation;
1331         }
1332     }
1333 
1334     private class LegacyListener implements SensorEventListener {
1335         private float mValues[] = new float[6];
1336         @SuppressWarnings("deprecation")
1337         private SensorListener mTarget;
1338         private int mSensors;
1339         private final LmsFilter mYawfilter = new LmsFilter();
1340 
1341         @SuppressWarnings("deprecation")
LegacyListener(SensorListener target)1342         LegacyListener(SensorListener target) {
1343             mTarget = target;
1344             mSensors = 0;
1345         }
1346 
registerSensor(int legacyType)1347         void registerSensor(int legacyType) {
1348             mSensors |= legacyType;
1349         }
1350 
unregisterSensor(int legacyType)1351         boolean unregisterSensor(int legacyType) {
1352             mSensors &= ~legacyType;
1353             int mask = SENSOR_ORIENTATION|SENSOR_ORIENTATION_RAW;
1354             if (((legacyType&mask)!=0) && ((mSensors&mask)!=0)) {
1355                 return false;
1356             }
1357             return true;
1358         }
1359 
1360         @SuppressWarnings("deprecation")
onAccuracyChanged(Sensor sensor, int accuracy)1361         public void onAccuracyChanged(Sensor sensor, int accuracy) {
1362             try {
1363                 mTarget.onAccuracyChanged(sensor.getLegacyType(), accuracy);
1364             } catch (AbstractMethodError e) {
1365                 // old app that doesn't implement this method
1366                 // just ignore it.
1367             }
1368         }
1369 
1370         @SuppressWarnings("deprecation")
onSensorChanged(SensorEvent event)1371         public void onSensorChanged(SensorEvent event) {
1372             final float v[] = mValues;
1373             v[0] = event.values[0];
1374             v[1] = event.values[1];
1375             v[2] = event.values[2];
1376             int legacyType = event.sensor.getLegacyType();
1377             mapSensorDataToWindow(legacyType, v, SensorManager.getRotation());
1378             if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
1379                 if ((mSensors & SENSOR_ORIENTATION_RAW)!=0) {
1380                     mTarget.onSensorChanged(SENSOR_ORIENTATION_RAW, v);
1381                 }
1382                 if ((mSensors & SENSOR_ORIENTATION)!=0) {
1383                     v[0] = mYawfilter.filter(event.timestamp, v[0]);
1384                     mTarget.onSensorChanged(SENSOR_ORIENTATION, v);
1385                 }
1386             } else {
1387                 mTarget.onSensorChanged(legacyType, v);
1388             }
1389         }
1390 
1391         /*
1392          * Helper function to convert the specified sensor's data to the windows's
1393          * coordinate space from the device's coordinate space.
1394          *
1395          * output: 3,4,5: values in the old API format
1396          *         0,1,2: transformed values in the old API format
1397          *
1398          */
mapSensorDataToWindow(int sensor, float[] values, int orientation)1399         private void mapSensorDataToWindow(int sensor,
1400                 float[] values, int orientation) {
1401             float x = values[0];
1402             float y = values[1];
1403             float z = values[2];
1404 
1405             switch (sensor) {
1406                 case SensorManager.SENSOR_ORIENTATION:
1407                 case SensorManager.SENSOR_ORIENTATION_RAW:
1408                     z = -z;
1409                     break;
1410                 case SensorManager.SENSOR_ACCELEROMETER:
1411                     x = -x;
1412                     y = -y;
1413                     z = -z;
1414                     break;
1415                 case SensorManager.SENSOR_MAGNETIC_FIELD:
1416                     x = -x;
1417                     y = -y;
1418                     break;
1419             }
1420             values[0] = x;
1421             values[1] = y;
1422             values[2] = z;
1423             values[3] = x;
1424             values[4] = y;
1425             values[5] = z;
1426             // TODO: add support for 180 and 270 orientations
1427             if (orientation == Surface.ROTATION_90) {
1428                 switch (sensor) {
1429                     case SENSOR_ACCELEROMETER:
1430                     case SENSOR_MAGNETIC_FIELD:
1431                         values[0] =-y;
1432                         values[1] = x;
1433                         values[2] = z;
1434                         break;
1435                     case SENSOR_ORIENTATION:
1436                     case SENSOR_ORIENTATION_RAW:
1437                         values[0] = x + ((x < 270) ? 90 : -270);
1438                         values[1] = z;
1439                         values[2] = y;
1440                         break;
1441                 }
1442             }
1443         }
1444     }
1445 
1446     class LmsFilter {
1447         private static final int SENSORS_RATE_MS = 20;
1448         private static final int COUNT = 12;
1449         private static final float PREDICTION_RATIO = 1.0f/3.0f;
1450         private static final float PREDICTION_TIME = (SENSORS_RATE_MS*COUNT/1000.0f)*PREDICTION_RATIO;
1451         private float mV[] = new float[COUNT*2];
1452         private float mT[] = new float[COUNT*2];
1453         private int mIndex;
1454 
LmsFilter()1455         public LmsFilter() {
1456             mIndex = COUNT;
1457         }
1458 
filter(long time, float in)1459         public float filter(long time, float in) {
1460             float v = in;
1461             final float ns = 1.0f / 1000000000.0f;
1462             final float t = time*ns;
1463             float v1 = mV[mIndex];
1464             if ((v-v1) > 180) {
1465                 v -= 360;
1466             } else if ((v1-v) > 180) {
1467                 v += 360;
1468             }
1469             /* Manage the circular buffer, we write the data twice spaced
1470              * by COUNT values, so that we don't have to copy the array
1471              * when it's full
1472              */
1473             mIndex++;
1474             if (mIndex >= COUNT*2)
1475                 mIndex = COUNT;
1476             mV[mIndex] = v;
1477             mT[mIndex] = t;
1478             mV[mIndex-COUNT] = v;
1479             mT[mIndex-COUNT] = t;
1480 
1481             float A, B, C, D, E;
1482             float a, b;
1483             int i;
1484 
1485             A = B = C = D = E = 0;
1486             for (i=0 ; i<COUNT-1 ; i++) {
1487                 final int j = mIndex - 1 - i;
1488                 final float Z = mV[j];
1489                 final float T = 0.5f*(mT[j] + mT[j+1]) - t;
1490                 float dT = mT[j] - mT[j+1];
1491                 dT *= dT;
1492                 A += Z*dT;
1493                 B += T*(T*dT);
1494                 C +=   (T*dT);
1495                 D += Z*(T*dT);
1496                 E += dT;
1497             }
1498             b = (A*B + C*D) / (E*B + C*C);
1499             a = (E*b - A) / C;
1500             float f = b + PREDICTION_TIME*a;
1501 
1502             // Normalize
1503             f *= (1.0f / 360.0f);
1504             if (((f>=0)?f:-f) >= 0.5f)
1505                 f = f - (float)Math.ceil(f + 0.5f) + 1.0f;
1506             if (f < 0)
1507                 f += 1.0f;
1508             f *= 360.0f;
1509             return f;
1510         }
1511     }
1512 
1513 
nativeClassInit()1514     private static native void nativeClassInit();
1515 
sensors_module_init()1516     private static native int sensors_module_init();
sensors_module_get_next_sensor(Sensor sensor, int next)1517     private static native int sensors_module_get_next_sensor(Sensor sensor, int next);
1518 
1519     // Used within this module from outside SensorManager, don't make private
sensors_data_init()1520     static native int sensors_data_init();
sensors_data_uninit()1521     static native int sensors_data_uninit();
sensors_data_open(FileDescriptor[] fds, int[] ints)1522     static native int sensors_data_open(FileDescriptor[] fds, int[] ints);
sensors_data_close()1523     static native int sensors_data_close();
sensors_data_poll(float[] values, int[] status, long[] timestamp)1524     static native int sensors_data_poll(float[] values, int[] status, long[] timestamp);
1525 }
1526