SystemSensorManager.java revision c0ce7eeb481540e24bc45f52e604df923c507043
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.Handler; 20import android.os.Looper; 21import android.os.MessageQueue; 22import android.util.Log; 23import android.util.Pools; 24import android.util.SparseArray; 25import android.util.SparseBooleanArray; 26import android.util.SparseIntArray; 27import dalvik.system.CloseGuard; 28 29import java.util.ArrayList; 30import java.util.HashMap; 31import java.util.List; 32 33/** 34 * Sensor manager implementation that communicates with the built-in 35 * system sensors. 36 * 37 * @hide 38 */ 39public class SystemSensorManager extends SensorManager { 40 private static native void nativeClassInit(); 41 private static native int nativeGetNextSensor(Sensor sensor, int next); 42 43 private static boolean sSensorModuleInitialized = false; 44 private static final Object sSensorModuleLock = new Object(); 45 private static final ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>(); 46 private static final SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>(); 47 48 // Listener list 49 private final HashMap<SensorEventListener, SensorEventQueue> mSensorListeners = 50 new HashMap<SensorEventListener, SensorEventQueue>(); 51 private final HashMap<TriggerEventListener, TriggerEventQueue> mTriggerListeners = 52 new HashMap<TriggerEventListener, TriggerEventQueue>(); 53 54 private static final int MAX_EVENTS = 16; 55 private static Pools.SynchronizedPool<SensorEvent> sSensorEventPool; 56 private static Pools.SynchronizedPool<TriggerEvent> sTriggerEventPool; 57 58 // Looper associated with the context in which this instance was created. 59 private final Looper mMainLooper; 60 61 /** {@hide} */ 62 public SystemSensorManager(Looper mainLooper) { 63 mMainLooper = mainLooper; 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 sSensorEventPool = new Pools.SynchronizedPool<SensorEvent>( 85 Math.max(sFullSensorsList.size()*2, 1)); 86 sTriggerEventPool = new Pools.SynchronizedPool<TriggerEvent>( 87 Math.max(sFullSensorsList.size()*2, 1)); 88 } 89 } 90 } 91 92 93 /** @hide */ 94 @Override 95 protected List<Sensor> getFullSensorList() { 96 return sFullSensorsList; 97 } 98 99 100 /** @hide */ 101 @Override 102 protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor, 103 int delay, Handler handler) 104 { 105 // Invariants to preserve: 106 // - one Looper per SensorEventListener 107 // - one Looper per SensorEventQueue 108 // We map SensorEventListener to a SensorEventQueue, which holds the looper 109 if (sensor == null) throw new IllegalArgumentException("sensor cannot be null"); 110 111 // Trigger Sensors should use the requestTriggerSensor call. 112 if (Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) return false; 113 114 synchronized (mSensorListeners) { 115 SensorEventQueue queue = mSensorListeners.get(listener); 116 if (queue == null) { 117 Looper looper = (handler != null) ? handler.getLooper() : mMainLooper; 118 queue = new SensorEventQueue(listener, looper); 119 if (!queue.addSensor(sensor, delay)) { 120 queue.dispose(); 121 return false; 122 } 123 mSensorListeners.put(listener, queue); 124 return true; 125 } else { 126 return queue.addSensor(sensor, delay); 127 } 128 } 129 } 130 131 /** @hide */ 132 @Override 133 protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) { 134 // Trigger Sensors should use the cancelTriggerSensor call. 135 if (sensor != null && Sensor.getReportingMode(sensor) == Sensor.REPORTING_MODE_ONE_SHOT) { 136 return; 137 } 138 139 synchronized (mSensorListeners) { 140 SensorEventQueue queue = mSensorListeners.get(listener); 141 if (queue != null) { 142 boolean result; 143 if (sensor == null) { 144 result = queue.removeAllSensors(); 145 } else { 146 result = queue.removeSensor(sensor); 147 } 148 if (result && !queue.hasSensors()) { 149 mSensorListeners.remove(listener); 150 queue.dispose(); 151 } 152 } 153 } 154 } 155 156 /** @hide */ 157 @Override 158 protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) { 159 if (sensor == null) throw new IllegalArgumentException("sensor cannot be null"); 160 161 if (Sensor.getReportingMode(sensor) != Sensor.REPORTING_MODE_ONE_SHOT) return false; 162 163 synchronized (mTriggerListeners) { 164 TriggerEventQueue queue = mTriggerListeners.get(listener); 165 if (queue == null) { 166 queue = new TriggerEventQueue(listener, mMainLooper, this); 167 if (!queue.addSensor(sensor, 0)) { 168 queue.dispose(); 169 return false; 170 } 171 mTriggerListeners.put(listener, queue); 172 return true; 173 } else { 174 return queue.addSensor(sensor, 0); 175 } 176 } 177 } 178 179 /** @hide */ 180 @Override 181 protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) { 182 if (sensor != null && Sensor.getReportingMode(sensor) != Sensor.REPORTING_MODE_ONE_SHOT) { 183 return false; 184 } 185 synchronized (mTriggerListeners) { 186 TriggerEventQueue queue = mTriggerListeners.get(listener); 187 if (queue != null) { 188 boolean result; 189 if (sensor == null) { 190 result = queue.removeAllSensors(); 191 } else { 192 result = queue.removeSensor(sensor); 193 } 194 if (result && !queue.hasSensors()) { 195 mTriggerListeners.remove(listener); 196 queue.dispose(); 197 } 198 return result; 199 } 200 return false; 201 } 202 } 203 204 /* 205 * BaseEventQueue is the communication channel with the sensor service, 206 * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between 207 * the queues and the listeners. 208 */ 209 private static abstract class BaseEventQueue { 210 private native int nativeInitBaseEventQueue(BaseEventQueue eventQ, MessageQueue msgQ, 211 float[] scratch); 212 private static native int nativeEnableSensor(int eventQ, int handle, int us); 213 private static native int nativeDisableSensor(int eventQ, int handle); 214 private static native void nativeDestroySensorEventQueue(int eventQ); 215 private int nSensorEventQueue; 216 private final SparseBooleanArray mActiveSensors = new SparseBooleanArray(); 217 protected final SparseIntArray mSensorAccuracies = new SparseIntArray(); 218 protected final SparseBooleanArray mFirstEvent = new SparseBooleanArray(); 219 private final CloseGuard mCloseGuard = CloseGuard.get(); 220 private final float[] mScratch = new float[16]; 221 222 BaseEventQueue(Looper looper) { 223 nSensorEventQueue = nativeInitBaseEventQueue(this, looper.getQueue(), mScratch); 224 mCloseGuard.open("dispose"); 225 } 226 227 public void dispose() { 228 dispose(false); 229 } 230 231 public boolean addSensor(Sensor sensor, int delay) { 232 // Check if already present. 233 if (mActiveSensors.get(sensor.getHandle())) return false; 234 235 if (enableSensor(sensor, delay) == 0) { 236 mActiveSensors.put(sensor.getHandle(), true); 237 return true; 238 } 239 return false; 240 } 241 242 public boolean removeAllSensors() { 243 for (int i=0 ; i<mActiveSensors.size(); i++) { 244 if (mActiveSensors.valueAt(i) == true) { 245 int handle = mActiveSensors.keyAt(i); 246 Sensor sensor = sHandleToSensor.get(handle); 247 if (sensor != null) { 248 disableSensor(sensor); 249 mActiveSensors.put(handle, false); 250 } else { 251 // it should never happen -- just ignore. 252 } 253 } 254 } 255 return true; 256 } 257 258 public boolean removeSensor(Sensor sensor) { 259 final int handle = sensor.getHandle(); 260 if (mActiveSensors.get(handle)) { 261 disableSensor(sensor); 262 mActiveSensors.put(sensor.getHandle(), false); 263 return true; 264 } 265 return false; 266 } 267 268 public boolean hasSensors() { 269 // no more sensors are set 270 return mActiveSensors.indexOfValue(true) >= 0; 271 } 272 273 @Override 274 protected void finalize() throws Throwable { 275 try { 276 dispose(true); 277 } finally { 278 super.finalize(); 279 } 280 } 281 282 private void dispose(boolean finalized) { 283 if (mCloseGuard != null) { 284 if (finalized) { 285 mCloseGuard.warnIfOpen(); 286 } 287 mCloseGuard.close(); 288 } 289 if (nSensorEventQueue != 0) { 290 nativeDestroySensorEventQueue(nSensorEventQueue); 291 nSensorEventQueue = 0; 292 } 293 } 294 295 private int enableSensor(Sensor sensor, int us) { 296 if (nSensorEventQueue == 0) throw new NullPointerException(); 297 if (sensor == null) throw new NullPointerException(); 298 return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), us); 299 } 300 private int disableSensor(Sensor sensor) { 301 if (nSensorEventQueue == 0) throw new NullPointerException(); 302 if (sensor == null) throw new NullPointerException(); 303 return nativeDisableSensor(nSensorEventQueue, sensor.getHandle()); 304 } 305 protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy, 306 long timestamp); 307 } 308 309 static final class SensorEventQueue extends BaseEventQueue { 310 private final SensorEventListener mListener; 311 312 public SensorEventQueue(SensorEventListener listener, Looper looper) { 313 super(looper); 314 mListener = listener; 315 } 316 317 // Called from native code. 318 @SuppressWarnings("unused") 319 @Override 320 protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy, 321 long timestamp) { 322 final Sensor sensor = sHandleToSensor.get(handle); 323 SensorEvent t = sSensorEventPool.acquire(); 324 if (t == null) t = new SensorEvent(MAX_EVENTS); 325 try { 326 // Copy the entire values array. 327 // Any changes in length will be handled at the native layer. 328 System.arraycopy(values, 0, t.values, 0, t.values.length); 329 t.timestamp = timestamp; 330 t.accuracy = inAccuracy; 331 t.sensor = sensor; 332 switch (t.sensor.getType()) { 333 // Only report accuracy for sensors that support it. 334 case Sensor.TYPE_MAGNETIC_FIELD: 335 case Sensor.TYPE_ORIENTATION: 336 // call onAccuracyChanged() only if the value changes 337 final int accuracy = mSensorAccuracies.get(handle); 338 if ((t.accuracy >= 0) && (accuracy != t.accuracy)) { 339 mSensorAccuracies.put(handle, t.accuracy); 340 mListener.onAccuracyChanged(t.sensor, t.accuracy); 341 } 342 break; 343 default: 344 // For other sensors, just report the accuracy once 345 if (mFirstEvent.get(handle) == false) { 346 mFirstEvent.put(handle, true); 347 mListener.onAccuracyChanged( 348 t.sensor, SENSOR_STATUS_ACCURACY_HIGH); 349 } 350 break; 351 } 352 mListener.onSensorChanged(t); 353 } finally { 354 sSensorEventPool.release(t); 355 } 356 } 357 } 358 359 static final class TriggerEventQueue extends BaseEventQueue { 360 private final TriggerEventListener mListener; 361 private SensorManager mManager; 362 363 public TriggerEventQueue(TriggerEventListener listener, Looper looper, 364 SensorManager manager) { 365 super(looper); 366 mListener = listener; 367 mManager = manager; 368 } 369 370 // Called from native code. 371 @SuppressWarnings("unused") 372 @Override 373 protected void dispatchSensorEvent(int handle, float[] values, int accuracy, long timestamp) { 374 final Sensor sensor = sHandleToSensor.get(handle); 375 TriggerEvent t = sTriggerEventPool.acquire(); 376 if (t == null) t = new TriggerEvent(MAX_EVENTS); 377 378 try { 379 // Copy the entire values array. 380 // Any changes in length will be handled at the native layer. 381 System.arraycopy(values, 0, t.values, 0, t.values.length); 382 t.timestamp = timestamp; 383 t.sensor = sensor; 384 385 // A trigger sensor should be auto disabled. 386 mManager.cancelTriggerSensorImpl(mListener, sensor); 387 388 mListener.onTrigger(t); 389 } finally { 390 sTriggerEventPool.release(t); 391 } 392 } 393 } 394} 395