SystemSensorManager.java revision 1aab1dbca5cf7386797ce609c768249247233186
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