• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 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.os.Looper;
20 import android.os.Process;
21 import android.os.Handler;
22 import android.os.Message;
23 import android.util.Log;
24 import android.util.SparseArray;
25 import android.util.SparseBooleanArray;
26 import android.util.SparseIntArray;
27 
28 import java.util.ArrayList;
29 import java.util.List;
30 
31 /**
32  * Sensor manager implementation that communicates with the built-in
33  * system sensors.
34  *
35  * @hide
36  */
37 public class SystemSensorManager extends SensorManager {
38     private static final int SENSOR_DISABLE = -1;
39     private static boolean sSensorModuleInitialized = false;
40     private static ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>();
41     /* The thread and the sensor list are global to the process
42      * but the actual thread is spawned on demand */
43     private static SensorThread sSensorThread;
44     private static int sQueue;
45 
46     // Used within this module from outside SensorManager, don't make private
47     static SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>();
48     static final ArrayList<ListenerDelegate> sListeners =
49         new ArrayList<ListenerDelegate>();
50 
51     // Common pool of sensor events.
52     static SensorEventPool sPool;
53 
54     // Looper associated with the context in which this instance was created.
55     final Looper mMainLooper;
56 
57     /*-----------------------------------------------------------------------*/
58 
59     static private class SensorThread {
60 
61         Thread mThread;
62         boolean mSensorsReady;
63 
SensorThread()64         SensorThread() {
65         }
66 
67         @Override
finalize()68         protected void finalize() {
69         }
70 
71         // must be called with sListeners lock
startLocked()72         boolean startLocked() {
73             try {
74                 if (mThread == null) {
75                     mSensorsReady = false;
76                     SensorThreadRunnable runnable = new SensorThreadRunnable();
77                     Thread thread = new Thread(runnable, SensorThread.class.getName());
78                     thread.start();
79                     synchronized (runnable) {
80                         while (mSensorsReady == false) {
81                             runnable.wait();
82                         }
83                     }
84                     mThread = thread;
85                 }
86             } catch (InterruptedException e) {
87             }
88             return mThread == null ? false : true;
89         }
90 
91         private class SensorThreadRunnable implements Runnable {
SensorThreadRunnable()92             SensorThreadRunnable() {
93             }
94 
open()95             private boolean open() {
96                 // NOTE: this cannot synchronize on sListeners, since
97                 // it's held in the main thread at least until we
98                 // return from here.
99                 sQueue = sensors_create_queue();
100                 return true;
101             }
102 
run()103             public void run() {
104                 //Log.d(TAG, "entering main sensor thread");
105                 final float[] values = new float[3];
106                 final int[] status = new int[1];
107                 final long timestamp[] = new long[1];
108                 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
109 
110                 if (!open()) {
111                     return;
112                 }
113 
114                 synchronized (this) {
115                     // we've open the driver, we're ready to open the sensors
116                     mSensorsReady = true;
117                     this.notify();
118                 }
119 
120                 while (true) {
121                     // wait for an event
122                     final int sensor = sensors_data_poll(sQueue, values, status, timestamp);
123 
124                     int accuracy = status[0];
125                     synchronized (sListeners) {
126                         if (sensor == -1 || sListeners.isEmpty()) {
127                             // we lost the connection to the event stream. this happens
128                             // when the last listener is removed or if there is an error
129                             if (sensor == -1 && !sListeners.isEmpty()) {
130                                 // log a warning in case of abnormal termination
131                                 Log.e(TAG, "_sensors_data_poll() failed, we bail out: sensors=" + sensor);
132                             }
133                             // we have no more listeners or polling failed, terminate the thread
134                             sensors_destroy_queue(sQueue);
135                             sQueue = 0;
136                             mThread = null;
137                             break;
138                         }
139                         final Sensor sensorObject = sHandleToSensor.get(sensor);
140                         if (sensorObject != null) {
141                             // report the sensor event to all listeners that
142                             // care about it.
143                             final int size = sListeners.size();
144                             for (int i=0 ; i<size ; i++) {
145                                 ListenerDelegate listener = sListeners.get(i);
146                                 if (listener.hasSensor(sensorObject)) {
147                                     // this is asynchronous (okay to call
148                                     // with sListeners lock held).
149                                     listener.onSensorChangedLocked(sensorObject,
150                                             values, timestamp, accuracy);
151                                 }
152                             }
153                         }
154                     }
155                 }
156                 //Log.d(TAG, "exiting main sensor thread");
157             }
158         }
159     }
160 
161     /*-----------------------------------------------------------------------*/
162 
163     private class ListenerDelegate {
164         private final SensorEventListener mSensorEventListener;
165         private final ArrayList<Sensor> mSensorList = new ArrayList<Sensor>();
166         private final Handler mHandler;
167         public SparseBooleanArray mSensors = new SparseBooleanArray();
168         public SparseBooleanArray mFirstEvent = new SparseBooleanArray();
169         public SparseIntArray mSensorAccuracies = new SparseIntArray();
170 
ListenerDelegate(SensorEventListener listener, Sensor sensor, Handler handler)171         ListenerDelegate(SensorEventListener listener, Sensor sensor, Handler handler) {
172             mSensorEventListener = listener;
173             Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
174             // currently we create one Handler instance per listener, but we could
175             // have one per looper (we'd need to pass the ListenerDelegate
176             // instance to handleMessage and keep track of them separately).
177             mHandler = new Handler(looper) {
178                 @Override
179                 public void handleMessage(Message msg) {
180                     final SensorEvent t = (SensorEvent)msg.obj;
181                     final int handle = t.sensor.getHandle();
182 
183                     switch (t.sensor.getType()) {
184                         // Only report accuracy for sensors that support it.
185                         case Sensor.TYPE_MAGNETIC_FIELD:
186                         case Sensor.TYPE_ORIENTATION:
187                             // call onAccuracyChanged() only if the value changes
188                             final int accuracy = mSensorAccuracies.get(handle);
189                             if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
190                                 mSensorAccuracies.put(handle, t.accuracy);
191                                 mSensorEventListener.onAccuracyChanged(t.sensor, t.accuracy);
192                             }
193                             break;
194                         default:
195                             // For other sensors, just report the accuracy once
196                             if (mFirstEvent.get(handle) == false) {
197                                 mFirstEvent.put(handle, true);
198                                 mSensorEventListener.onAccuracyChanged(
199                                         t.sensor, SENSOR_STATUS_ACCURACY_HIGH);
200                             }
201                             break;
202                     }
203 
204                     mSensorEventListener.onSensorChanged(t);
205                     sPool.returnToPool(t);
206                 }
207             };
208             addSensor(sensor);
209         }
210 
getListener()211         Object getListener() {
212             return mSensorEventListener;
213         }
214 
addSensor(Sensor sensor)215         void addSensor(Sensor sensor) {
216             mSensors.put(sensor.getHandle(), true);
217             mSensorList.add(sensor);
218         }
removeSensor(Sensor sensor)219         int removeSensor(Sensor sensor) {
220             mSensors.delete(sensor.getHandle());
221             mSensorList.remove(sensor);
222             return mSensors.size();
223         }
hasSensor(Sensor sensor)224         boolean hasSensor(Sensor sensor) {
225             return mSensors.get(sensor.getHandle());
226         }
getSensors()227         List<Sensor> getSensors() {
228             return mSensorList;
229         }
230 
onSensorChangedLocked(Sensor sensor, float[] values, long[] timestamp, int accuracy)231         void onSensorChangedLocked(Sensor sensor, float[] values, long[] timestamp, int accuracy) {
232             SensorEvent t = sPool.getFromPool();
233             final float[] v = t.values;
234             v[0] = values[0];
235             v[1] = values[1];
236             v[2] = values[2];
237             t.timestamp = timestamp[0];
238             t.accuracy = accuracy;
239             t.sensor = sensor;
240             Message msg = Message.obtain();
241             msg.what = 0;
242             msg.obj = t;
243             msg.setAsynchronous(true);
244             mHandler.sendMessage(msg);
245         }
246     }
247 
248     /**
249      * {@hide}
250      */
SystemSensorManager(Looper mainLooper)251     public SystemSensorManager(Looper mainLooper) {
252         mMainLooper = mainLooper;
253 
254         synchronized(sListeners) {
255             if (!sSensorModuleInitialized) {
256                 sSensorModuleInitialized = true;
257 
258                 nativeClassInit();
259 
260                 // initialize the sensor list
261                 sensors_module_init();
262                 final ArrayList<Sensor> fullList = sFullSensorsList;
263                 int i = 0;
264                 do {
265                     Sensor sensor = new Sensor();
266                     i = sensors_module_get_next_sensor(sensor, i);
267 
268                     if (i>=0) {
269                         //Log.d(TAG, "found sensor: " + sensor.getName() +
270                         //        ", handle=" + sensor.getHandle());
271                         fullList.add(sensor);
272                         sHandleToSensor.append(sensor.getHandle(), sensor);
273                     }
274                 } while (i>0);
275 
276                 sPool = new SensorEventPool( sFullSensorsList.size()*2 );
277                 sSensorThread = new SensorThread();
278             }
279         }
280     }
281 
282     /** @hide */
283     @Override
getFullSensorList()284     protected List<Sensor> getFullSensorList() {
285         return sFullSensorsList;
286     }
287 
enableSensorLocked(Sensor sensor, int delay)288     private boolean enableSensorLocked(Sensor sensor, int delay) {
289         boolean result = false;
290         for (ListenerDelegate i : sListeners) {
291             if (i.hasSensor(sensor)) {
292                 String name = sensor.getName();
293                 int handle = sensor.getHandle();
294                 result = sensors_enable_sensor(sQueue, name, handle, delay);
295                 break;
296             }
297         }
298         return result;
299     }
300 
disableSensorLocked(Sensor sensor)301     private boolean disableSensorLocked(Sensor sensor) {
302         for (ListenerDelegate i : sListeners) {
303             if (i.hasSensor(sensor)) {
304                 // not an error, it's just that this sensor is still in use
305                 return true;
306             }
307         }
308         String name = sensor.getName();
309         int handle = sensor.getHandle();
310         return sensors_enable_sensor(sQueue, name, handle, SENSOR_DISABLE);
311     }
312 
313     /** @hide */
314     @Override
registerListenerImpl(SensorEventListener listener, Sensor sensor, int delay, Handler handler)315     protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
316             int delay, Handler handler) {
317         boolean result = true;
318         synchronized (sListeners) {
319             // look for this listener in our list
320             ListenerDelegate l = null;
321             for (ListenerDelegate i : sListeners) {
322                 if (i.getListener() == listener) {
323                     l = i;
324                     break;
325                 }
326             }
327 
328             // if we don't find it, add it to the list
329             if (l == null) {
330                 l = new ListenerDelegate(listener, sensor, handler);
331                 sListeners.add(l);
332                 // if the list is not empty, start our main thread
333                 if (!sListeners.isEmpty()) {
334                     if (sSensorThread.startLocked()) {
335                         if (!enableSensorLocked(sensor, delay)) {
336                             // oops. there was an error
337                             sListeners.remove(l);
338                             result = false;
339                         }
340                     } else {
341                         // there was an error, remove the listener
342                         sListeners.remove(l);
343                         result = false;
344                     }
345                 } else {
346                     // weird, we couldn't add the listener
347                     result = false;
348                 }
349             } else if (!l.hasSensor(sensor)) {
350                 l.addSensor(sensor);
351                 if (!enableSensorLocked(sensor, delay)) {
352                     // oops. there was an error
353                     l.removeSensor(sensor);
354                     result = false;
355                 }
356             }
357         }
358 
359         return result;
360     }
361 
362     /** @hide */
363     @Override
unregisterListenerImpl(SensorEventListener listener, Sensor sensor)364     protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
365         synchronized (sListeners) {
366             final int size = sListeners.size();
367             for (int i=0 ; i<size ; i++) {
368                 ListenerDelegate l = sListeners.get(i);
369                 if (l.getListener() == listener) {
370                     if (sensor == null) {
371                         sListeners.remove(i);
372                         // disable all sensors for this listener
373                         for (Sensor s : l.getSensors()) {
374                             disableSensorLocked(s);
375                         }
376                     } else if (l.removeSensor(sensor) == 0) {
377                         // if we have no more sensors enabled on this listener,
378                         // take it off the list.
379                         sListeners.remove(i);
380                         disableSensorLocked(sensor);
381                     }
382                     break;
383                 }
384             }
385         }
386     }
387 
nativeClassInit()388     private static native void nativeClassInit();
389 
sensors_module_init()390     private static native int sensors_module_init();
sensors_module_get_next_sensor(Sensor sensor, int next)391     private static native int sensors_module_get_next_sensor(Sensor sensor, int next);
392 
393     // Used within this module from outside SensorManager, don't make private
sensors_create_queue()394     static native int sensors_create_queue();
sensors_destroy_queue(int queue)395     static native void sensors_destroy_queue(int queue);
sensors_enable_sensor(int queue, String name, int sensor, int enable)396     static native boolean sensors_enable_sensor(int queue, String name, int sensor, int enable);
sensors_data_poll(int queue, float[] values, int[] status, long[] timestamp)397     static native int sensors_data_poll(int queue, float[] values, int[] status, long[] timestamp);
398 }
399