SystemSensorManager.java revision 6d7a4737643afe05034a36e6ebcd5da1085fbbdc
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 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
64        SensorThread() {
65        }
66
67        @Override
68        protected void finalize() {
69        }
70
71        // must be called with sListeners lock
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 {
92            SensorThreadRunnable() {
93            }
94
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
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
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
211        Object getListener() {
212            return mSensorEventListener;
213        }
214
215        void addSensor(Sensor sensor) {
216            mSensors.put(sensor.getHandle(), true);
217            mSensorList.add(sensor);
218        }
219        int removeSensor(Sensor sensor) {
220            mSensors.delete(sensor.getHandle());
221            mSensorList.remove(sensor);
222            return mSensors.size();
223        }
224        boolean hasSensor(Sensor sensor) {
225            return mSensors.get(sensor.getHandle());
226        }
227        List<Sensor> getSensors() {
228            return mSensorList;
229        }
230
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     */
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
284    protected List<Sensor> getFullSensorList() {
285        return sFullSensorsList;
286    }
287
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
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
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
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                    // Check if the ListenerDelegate has the sensor it is trying to unregister.
377                    } else if (l.hasSensor(sensor) && l.removeSensor(sensor) == 0) {
378                        // if we have no more sensors enabled on this listener,
379                        // take it off the list.
380                        sListeners.remove(i);
381                        disableSensorLocked(sensor);
382                    }
383                    break;
384                }
385            }
386        }
387    }
388
389    private static native void nativeClassInit();
390
391    private static native int sensors_module_init();
392    private static native int sensors_module_get_next_sensor(Sensor sensor, int next);
393
394    // Used within this module from outside SensorManager, don't make private
395    static native int sensors_create_queue();
396    static native void sensors_destroy_queue(int queue);
397    static native boolean sensors_enable_sensor(int queue, String name, int sensor, int enable);
398    static native int sensors_data_poll(int queue, float[] values, int[] status, long[] timestamp);
399}
400