SystemSensorManager.java revision db772d813492517dce2bd7e6e9fbc88e42b30c02
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 java.util.ArrayList;
20import java.util.Hashtable;
21import java.util.List;
22
23import dalvik.system.CloseGuard;
24
25import android.os.Handler;
26import android.os.Looper;
27import android.os.MessageQueue;
28import android.util.SparseArray;
29import android.util.SparseBooleanArray;
30import android.util.SparseIntArray;
31
32/**
33 * Sensor manager implementation that communicates with the built-in
34 * system sensors.
35 *
36 * @hide
37 */
38public class SystemSensorManager extends SensorManager {
39    private static native void nativeClassInit();
40    private static native int nativeGetNextSensor(Sensor sensor, int next);
41
42    private static boolean sSensorModuleInitialized = false;
43    private static final Object sSensorModuleLock = new Object();
44    private static final ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>();
45    private static final SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>();
46
47    // Listener list
48    private final ArrayList<SensorEventListenerSensorPair> mListenerDelegates = new ArrayList<SensorEventListenerSensorPair>();
49
50    // Common pool of sensor events.
51    private static SensorEventPool sPool;
52
53    // Looper associated with the context in which this instance was created.
54    private final Looper mMainLooper;
55
56    // maps a SensorEventListener to a SensorEventQueue
57    private final Hashtable<SensorEventListener, SensorEventQueue> mSensorEventQueueMap;
58
59    /** {@hide} */
60    public SystemSensorManager(Looper mainLooper) {
61        mMainLooper = mainLooper;
62        mSensorEventQueueMap = new Hashtable<SensorEventListener, SensorEventQueue>();
63
64        synchronized(sSensorModuleLock) {
65            if (!sSensorModuleInitialized) {
66                sSensorModuleInitialized = true;
67
68                nativeClassInit();
69
70                // initialize the sensor list
71                final ArrayList<Sensor> fullList = sFullSensorsList;
72                int i = 0;
73                do {
74                    Sensor sensor = new Sensor();
75                    i = nativeGetNextSensor(sensor, i);
76                    if (i>=0) {
77                        //Log.d(TAG, "found sensor: " + sensor.getName() +
78                        //        ", handle=" + sensor.getHandle());
79                        fullList.add(sensor);
80                        sHandleToSensor.append(sensor.getHandle(), sensor);
81                    }
82                } while (i>0);
83
84                sPool = new SensorEventPool( sFullSensorsList.size()*2 );
85            }
86        }
87    }
88
89
90    /** @hide */
91    @Override
92    protected List<Sensor> getFullSensorList() {
93        return sFullSensorsList;
94    }
95
96
97    /** @hide */
98    @Override
99    protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
100            int delay, Handler handler)
101    {
102        // Invariants to preserve:
103        // - one Looper per SensorEventListener
104        // - one Looper per SensorEventQueue
105        // We map SensorEventListeners to a SensorEventQueue, which holds the looper
106
107        if (sensor == null) throw new NullPointerException("sensor cannot be null");
108
109        boolean result;
110        synchronized (mSensorEventQueueMap) {
111            // check if we already have this SensorEventListener, Sensor pair
112            // registered -- if so, we ignore the register. This is not ideal
113            // but this is what the implementation has always been doing.
114            for (SensorEventListenerSensorPair l : mListenerDelegates) {
115                if (l.isSameListenerSensorPair(listener, sensor)) {
116                    // already added, just return silently.
117                    return true;
118                }
119            }
120
121            // now find the SensorEventQueue associated to this listener
122            SensorEventQueue queue = mSensorEventQueueMap.get(listener);
123            if (queue != null) {
124                result = queue.addSensor(sensor, delay);
125                if (result) {
126                    // create a new ListenerDelegate for this pair
127                    mListenerDelegates.add(new SensorEventListenerSensorPair(listener, sensor));
128                }
129            } else {
130                Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;
131                queue = new SensorEventQueue(listener, looper.getQueue());
132                result = queue.addSensor(sensor, delay);
133                if (result) {
134                    // create a new ListenerDelegate for this pair
135                    mListenerDelegates.add(new SensorEventListenerSensorPair(listener, sensor));
136                    mSensorEventQueueMap.put(listener, queue);
137                } else {
138                    queue.dispose();
139                }
140            }
141        }
142        return result;
143    }
144
145    /** @hide */
146    @Override
147    protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
148        synchronized (mSensorEventQueueMap) {
149
150            // remove this listener/sensor from our list
151            final ArrayList<SensorEventListenerSensorPair> copy =
152                    new ArrayList<SensorEventListenerSensorPair>(mListenerDelegates);
153            int lastIndex = copy.size()-1;
154            for (int i=lastIndex ; i>= 0 ; i--) {
155                if (copy.get(i).isSameListenerSensorPair(listener, sensor)) {
156                    mListenerDelegates.remove(i);
157                }
158            }
159
160            // find the SensorEventQueue associated to this SensorEventListener
161            SensorEventQueue queue = mSensorEventQueueMap.get(listener);
162            if (queue != null) {
163                if (sensor != null) {
164                    queue.removeSensor(sensor);
165                } else {
166                    queue.removeAllSensors();
167                }
168                if (!queue.hasSensors()) {
169                    mSensorEventQueueMap.remove(listener);
170                    queue.dispose();
171                }
172            }
173        }
174    }
175
176
177    /*
178     * ListenerDelegate is essentially a SensorEventListener, Sensor pair
179     * and is associated with a single SensorEventQueue.
180     */
181    private static final class SensorEventListenerSensorPair {
182        private final SensorEventListener mSensorEventListener;
183        private final Sensor mSensor;
184        public SensorEventListenerSensorPair(SensorEventListener listener, Sensor sensor) {
185            mSensorEventListener = listener;
186            mSensor = sensor;
187        }
188        public boolean isSameListenerSensorPair(SensorEventListener listener, Sensor sensor) {
189            // if sensor is null, we match only on the listener
190            if (sensor != null) {
191                return (listener == mSensorEventListener) &&
192                        (sensor.getHandle() == mSensor.getHandle());
193            } else {
194                return (listener == mSensorEventListener);
195            }
196        }
197    }
198
199    /*
200     * SensorEventQueue is the communication channel with the sensor service,
201     * there is a one-to-one mapping between SensorEventQueue and
202     * SensorEventListener.
203     */
204    private static final class SensorEventQueue {
205        private static native int nativeInitSensorEventQueue(SensorEventQueue eventQ, MessageQueue msgQ, float[] scratch);
206        private static native int nativeEnableSensor(int eventQ, int handle, int us);
207        private static native int nativeDisableSensor(int eventQ, int handle);
208        private static native void nativeDestroySensorEventQueue(int eventQ);
209        private int nSensorEventQueue;
210        private final SensorEventListener mListener;
211        private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
212        private final SparseIntArray mSensorAccuracies = new SparseIntArray();
213        private final SparseBooleanArray mFirstEvent = new SparseBooleanArray();
214        private final CloseGuard mCloseGuard = CloseGuard.get();
215        private final float[] mScratch = new float[16];
216
217        public SensorEventQueue(SensorEventListener listener, MessageQueue msgQ) {
218            nSensorEventQueue = nativeInitSensorEventQueue(this, msgQ, mScratch);
219            mListener = listener;
220            mCloseGuard.open("dispose");
221        }
222        public void dispose() {
223            dispose(false);
224        }
225
226        public boolean addSensor(Sensor sensor, int delay) {
227            if (enableSensor(sensor, delay) == 0) {
228                mActiveSensors.put(sensor.getHandle(), true);
229                return true;
230            }
231            return false;
232        }
233
234        public void removeAllSensors() {
235            for (int i=0 ; i<mActiveSensors.size(); i++) {
236                if (mActiveSensors.valueAt(i) == true) {
237                    int handle = mActiveSensors.keyAt(i);
238                    Sensor sensor = sHandleToSensor.get(handle);
239                    if (sensor != null) {
240                        disableSensor(sensor);
241                        mActiveSensors.put(handle, false);
242                    } else {
243                        // it should never happen -- just ignore.
244                    }
245                }
246            }
247        }
248
249        public void removeSensor(Sensor sensor) {
250            final int handle = sensor.getHandle();
251            if (mActiveSensors.get(handle)) {
252                disableSensor(sensor);
253                mActiveSensors.put(sensor.getHandle(), false);
254            }
255        }
256
257        public boolean hasSensors() {
258            // no more sensors are set
259            return mActiveSensors.indexOfValue(true) >= 0;
260        }
261
262        @Override
263        protected void finalize() throws Throwable {
264            try {
265                dispose(true);
266            } finally {
267                super.finalize();
268            }
269        }
270
271        private void dispose(boolean finalized) {
272            if (mCloseGuard != null) {
273                if (finalized) {
274                    mCloseGuard.warnIfOpen();
275                }
276                mCloseGuard.close();
277            }
278            if (nSensorEventQueue != 0) {
279                nativeDestroySensorEventQueue(nSensorEventQueue);
280                nSensorEventQueue = 0;
281            }
282        }
283
284        private int enableSensor(Sensor sensor, int us) {
285            if (nSensorEventQueue == 0) throw new NullPointerException();
286            if (sensor == null) throw new NullPointerException();
287            return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), us);
288        }
289        private int disableSensor(Sensor sensor) {
290            if (nSensorEventQueue == 0) throw new NullPointerException();
291            if (sensor == null) throw new NullPointerException();
292            return nativeDisableSensor(nSensorEventQueue, sensor.getHandle());
293        }
294
295        // Called from native code.
296        @SuppressWarnings("unused")
297        private void dispatchSensorEvent(int handle, float[] values, int inAccuracy, long timestamp) {
298            // this is always called on the same thread.
299            final SensorEvent t = sPool.getFromPool();
300            try {
301                final Sensor sensor = sHandleToSensor.get(handle);
302                final SensorEventListener listener = mListener;
303                // FIXME: handle more than 3 values
304                System.arraycopy(values, 0, t.values, 0, 3);
305                t.timestamp = timestamp;
306                t.accuracy = inAccuracy;
307                t.sensor = sensor;
308                switch (t.sensor.getType()) {
309                    // Only report accuracy for sensors that support it.
310                    case Sensor.TYPE_MAGNETIC_FIELD:
311                    case Sensor.TYPE_ORIENTATION:
312                        // call onAccuracyChanged() only if the value changes
313                        final int accuracy = mSensorAccuracies.get(handle);
314                        if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
315                            mSensorAccuracies.put(handle, t.accuracy);
316                            listener.onAccuracyChanged(t.sensor, t.accuracy);
317                        }
318                        break;
319                    default:
320                        // For other sensors, just report the accuracy once
321                        if (mFirstEvent.get(handle) == false) {
322                            mFirstEvent.put(handle, true);
323                            listener.onAccuracyChanged(
324                                    t.sensor, SENSOR_STATUS_ACCURACY_HIGH);
325                        }
326                        break;
327                }
328                listener.onSensorChanged(t);
329            } finally {
330                sPool.returnToPool(t);
331            }
332        }
333    }
334
335    /*
336     * A dumb pool of SensorEvent
337     */
338    private static final class SensorEventPool {
339        private final int mPoolSize;
340        private final SensorEvent mPool[];
341        private int mNumItemsInPool;
342
343        private SensorEvent createSensorEvent() {
344            // maximal size for all legacy events is 3
345            return new SensorEvent(3);
346        }
347
348        SensorEventPool(int poolSize) {
349            mPoolSize = poolSize;
350            mNumItemsInPool = poolSize;
351            mPool = new SensorEvent[poolSize];
352        }
353
354        SensorEvent getFromPool() {
355            SensorEvent t = null;
356            synchronized (this) {
357                if (mNumItemsInPool > 0) {
358                    // remove the "top" item from the pool
359                    final int index = mPoolSize - mNumItemsInPool;
360                    t = mPool[index];
361                    mPool[index] = null;
362                    mNumItemsInPool--;
363                }
364            }
365            if (t == null) {
366                // the pool was empty or this item was removed from the pool for
367                // the first time. In any case, we need to create a new item.
368                t = createSensorEvent();
369            }
370            return t;
371        }
372
373        void returnToPool(SensorEvent t) {
374            synchronized (this) {
375                // is there space left in the pool?
376                if (mNumItemsInPool < mPoolSize) {
377                    // if so, return the item to the pool
378                    mNumItemsInPool++;
379                    final int index = mPoolSize - mNumItemsInPool;
380                    mPool[index] = t;
381                }
382            }
383        }
384    }
385}
386