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