SystemSensorManager.java revision 88445990b426499f25a9f37bc3b75f6e0267b4cb
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.content.Context; 20import android.os.Handler; 21import android.os.Looper; 22import android.os.MessageQueue; 23import android.util.Log; 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 // Looper associated with the context in which this instance was created. 55 private final Looper mMainLooper; 56 private final int mTargetSdkLevel; 57 private final String mPackageName; 58 59 /** {@hide} */ 60 public SystemSensorManager(Context context, Looper mainLooper) { 61 mMainLooper = mainLooper; 62 mTargetSdkLevel = context.getApplicationInfo().targetSdkVersion; 63 mPackageName = context.getPackageName(); 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 } 85 } 86 87 88 /** @hide */ 89 @Override 90 protected List<Sensor> getFullSensorList() { 91 return sFullSensorsList; 92 } 93 94 95 /** @hide */ 96 @Override 97 protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor, 98 int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) { 99 if (listener == null || sensor == null) { 100 Log.e(TAG, "sensor or listener is null"); 101 return false; 102 } 103 // Trigger Sensors should use the requestTriggerSensor call. 104 if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) { 105 Log.e(TAG, "Trigger Sensors should use the requestTriggerSensor."); 106 return false; 107 } 108 if (maxBatchReportLatencyUs < 0 || delayUs < 0) { 109 Log.e(TAG, "maxBatchReportLatencyUs and delayUs should be non-negative"); 110 return false; 111 } 112 113 // Invariants to preserve: 114 // - one Looper per SensorEventListener 115 // - one Looper per SensorEventQueue 116 // We map SensorEventListener to a SensorEventQueue, which holds the looper 117 synchronized (mSensorListeners) { 118 SensorEventQueue queue = mSensorListeners.get(listener); 119 if (queue == null) { 120 Looper looper = (handler != null) ? handler.getLooper() : mMainLooper; 121 queue = new SensorEventQueue(listener, looper, this); 122 if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) { 123 queue.dispose(); 124 return false; 125 } 126 mSensorListeners.put(listener, queue); 127 return true; 128 } else { 129 return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs); 130 } 131 } 132 } 133 134 /** @hide */ 135 @Override 136 protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) { 137 // Trigger Sensors should use the cancelTriggerSensor call. 138 if (sensor != null && sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) { 139 return; 140 } 141 142 synchronized (mSensorListeners) { 143 SensorEventQueue queue = mSensorListeners.get(listener); 144 if (queue != null) { 145 boolean result; 146 if (sensor == null) { 147 result = queue.removeAllSensors(); 148 } else { 149 result = queue.removeSensor(sensor, true); 150 } 151 if (result && !queue.hasSensors()) { 152 mSensorListeners.remove(listener); 153 queue.dispose(); 154 } 155 } 156 } 157 } 158 159 /** @hide */ 160 @Override 161 protected boolean requestTriggerSensorImpl(TriggerEventListener listener, Sensor sensor) { 162 if (sensor == null) throw new IllegalArgumentException("sensor cannot be null"); 163 164 if (sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) return false; 165 166 synchronized (mTriggerListeners) { 167 TriggerEventQueue queue = mTriggerListeners.get(listener); 168 if (queue == null) { 169 queue = new TriggerEventQueue(listener, mMainLooper, this); 170 if (!queue.addSensor(sensor, 0, 0)) { 171 queue.dispose(); 172 return false; 173 } 174 mTriggerListeners.put(listener, queue); 175 return true; 176 } else { 177 return queue.addSensor(sensor, 0, 0); 178 } 179 } 180 } 181 182 /** @hide */ 183 @Override 184 protected boolean cancelTriggerSensorImpl(TriggerEventListener listener, Sensor sensor, 185 boolean disable) { 186 if (sensor != null && sensor.getReportingMode() != Sensor.REPORTING_MODE_ONE_SHOT) { 187 return false; 188 } 189 synchronized (mTriggerListeners) { 190 TriggerEventQueue queue = mTriggerListeners.get(listener); 191 if (queue != null) { 192 boolean result; 193 if (sensor == null) { 194 result = queue.removeAllSensors(); 195 } else { 196 result = queue.removeSensor(sensor, disable); 197 } 198 if (result && !queue.hasSensors()) { 199 mTriggerListeners.remove(listener); 200 queue.dispose(); 201 } 202 return result; 203 } 204 return false; 205 } 206 } 207 208 protected boolean flushImpl(SensorEventListener listener) { 209 if (listener == null) throw new IllegalArgumentException("listener cannot be null"); 210 211 synchronized (mSensorListeners) { 212 SensorEventQueue queue = mSensorListeners.get(listener); 213 if (queue == null) { 214 return false; 215 } else { 216 return (queue.flush() == 0); 217 } 218 } 219 } 220 221 /* 222 * BaseEventQueue is the communication channel with the sensor service, 223 * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between 224 * the queues and the listeners. 225 */ 226 private static abstract class BaseEventQueue { 227 private native long nativeInitBaseEventQueue(BaseEventQueue eventQ, MessageQueue msgQ, 228 float[] scratch, String packageName); 229 private static native int nativeEnableSensor(long eventQ, int handle, int rateUs, 230 int maxBatchReportLatencyUs); 231 private static native int nativeDisableSensor(long eventQ, int handle); 232 private static native void nativeDestroySensorEventQueue(long eventQ); 233 private static native int nativeFlushSensor(long eventQ); 234 private long nSensorEventQueue; 235 private final SparseBooleanArray mActiveSensors = new SparseBooleanArray(); 236 protected final SparseIntArray mSensorAccuracies = new SparseIntArray(); 237 protected final SparseBooleanArray mFirstEvent = new SparseBooleanArray(); 238 private final CloseGuard mCloseGuard = CloseGuard.get(); 239 private final float[] mScratch = new float[16]; 240 protected final SystemSensorManager mManager; 241 242 BaseEventQueue(Looper looper, SystemSensorManager manager) { 243 nSensorEventQueue = nativeInitBaseEventQueue(this, looper.getQueue(), mScratch, 244 manager.mPackageName); 245 mCloseGuard.open("dispose"); 246 mManager = manager; 247 } 248 249 public void dispose() { 250 dispose(false); 251 } 252 253 public boolean addSensor( 254 Sensor sensor, int delayUs, int maxBatchReportLatencyUs) { 255 // Check if already present. 256 int handle = sensor.getHandle(); 257 if (mActiveSensors.get(handle)) return false; 258 259 // Get ready to receive events before calling enable. 260 mActiveSensors.put(handle, true); 261 addSensorEvent(sensor); 262 if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs) != 0) { 263 // Try continuous mode if batching fails. 264 if (maxBatchReportLatencyUs == 0 || 265 maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0) != 0) { 266 removeSensor(sensor, false); 267 return false; 268 } 269 } 270 return true; 271 } 272 273 public boolean removeAllSensors() { 274 for (int i=0 ; i<mActiveSensors.size(); i++) { 275 if (mActiveSensors.valueAt(i) == true) { 276 int handle = mActiveSensors.keyAt(i); 277 Sensor sensor = sHandleToSensor.get(handle); 278 if (sensor != null) { 279 disableSensor(sensor); 280 mActiveSensors.put(handle, false); 281 removeSensorEvent(sensor); 282 } else { 283 // it should never happen -- just ignore. 284 } 285 } 286 } 287 return true; 288 } 289 290 public boolean removeSensor(Sensor sensor, boolean disable) { 291 final int handle = sensor.getHandle(); 292 if (mActiveSensors.get(handle)) { 293 if (disable) disableSensor(sensor); 294 mActiveSensors.put(sensor.getHandle(), false); 295 removeSensorEvent(sensor); 296 return true; 297 } 298 return false; 299 } 300 301 public int flush() { 302 if (nSensorEventQueue == 0) throw new NullPointerException(); 303 return nativeFlushSensor(nSensorEventQueue); 304 } 305 306 public boolean hasSensors() { 307 // no more sensors are set 308 return mActiveSensors.indexOfValue(true) >= 0; 309 } 310 311 @Override 312 protected void finalize() throws Throwable { 313 try { 314 dispose(true); 315 } finally { 316 super.finalize(); 317 } 318 } 319 320 private void dispose(boolean finalized) { 321 if (mCloseGuard != null) { 322 if (finalized) { 323 mCloseGuard.warnIfOpen(); 324 } 325 mCloseGuard.close(); 326 } 327 if (nSensorEventQueue != 0) { 328 nativeDestroySensorEventQueue(nSensorEventQueue); 329 nSensorEventQueue = 0; 330 } 331 } 332 333 private int enableSensor( 334 Sensor sensor, int rateUs, int maxBatchReportLatencyUs) { 335 if (nSensorEventQueue == 0) throw new NullPointerException(); 336 if (sensor == null) throw new NullPointerException(); 337 return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), rateUs, 338 maxBatchReportLatencyUs); 339 } 340 341 private int disableSensor(Sensor sensor) { 342 if (nSensorEventQueue == 0) throw new NullPointerException(); 343 if (sensor == null) throw new NullPointerException(); 344 return nativeDisableSensor(nSensorEventQueue, sensor.getHandle()); 345 } 346 protected abstract void dispatchSensorEvent(int handle, float[] values, int accuracy, 347 long timestamp); 348 protected abstract void dispatchFlushCompleteEvent(int handle); 349 350 protected abstract void addSensorEvent(Sensor sensor); 351 protected abstract void removeSensorEvent(Sensor sensor); 352 } 353 354 static final class SensorEventQueue extends BaseEventQueue { 355 private final SensorEventListener mListener; 356 private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>(); 357 358 public SensorEventQueue(SensorEventListener listener, Looper looper, 359 SystemSensorManager manager) { 360 super(looper, manager); 361 mListener = listener; 362 } 363 364 @Override 365 public void addSensorEvent(Sensor sensor) { 366 SensorEvent t = new SensorEvent(Sensor.getMaxLengthValuesArray(sensor, 367 mManager.mTargetSdkLevel)); 368 synchronized (mSensorsEvents) { 369 mSensorsEvents.put(sensor.getHandle(), t); 370 } 371 } 372 373 @Override 374 public void removeSensorEvent(Sensor sensor) { 375 synchronized (mSensorsEvents) { 376 mSensorsEvents.delete(sensor.getHandle()); 377 } 378 } 379 380 // Called from native code. 381 @SuppressWarnings("unused") 382 @Override 383 protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy, 384 long timestamp) { 385 final Sensor sensor = sHandleToSensor.get(handle); 386 SensorEvent t = null; 387 synchronized (mSensorsEvents) { 388 t = mSensorsEvents.get(handle); 389 } 390 391 if (t == null) { 392 // This may happen if the client has unregistered and there are pending events in 393 // the queue waiting to be delivered. Ignore. 394 return; 395 } 396 // Copy from the values array. 397 System.arraycopy(values, 0, t.values, 0, t.values.length); 398 t.timestamp = timestamp; 399 t.accuracy = inAccuracy; 400 t.sensor = sensor; 401 402 // call onAccuracyChanged() only if the value changes 403 final int accuracy = mSensorAccuracies.get(handle); 404 if ((t.accuracy >= 0) && (accuracy != t.accuracy)) { 405 mSensorAccuracies.put(handle, t.accuracy); 406 mListener.onAccuracyChanged(t.sensor, t.accuracy); 407 } 408 mListener.onSensorChanged(t); 409 } 410 411 @SuppressWarnings("unused") 412 protected void dispatchFlushCompleteEvent(int handle) { 413 if (mListener instanceof SensorEventListener2) { 414 final Sensor sensor = sHandleToSensor.get(handle); 415 ((SensorEventListener2)mListener).onFlushCompleted(sensor); 416 } 417 return; 418 } 419 } 420 421 static final class TriggerEventQueue extends BaseEventQueue { 422 private final TriggerEventListener mListener; 423 private final SparseArray<TriggerEvent> mTriggerEvents = new SparseArray<TriggerEvent>(); 424 425 public TriggerEventQueue(TriggerEventListener listener, Looper looper, 426 SystemSensorManager manager) { 427 super(looper, manager); 428 mListener = listener; 429 } 430 431 @Override 432 public void addSensorEvent(Sensor sensor) { 433 TriggerEvent t = new TriggerEvent(Sensor.getMaxLengthValuesArray(sensor, 434 mManager.mTargetSdkLevel)); 435 synchronized (mTriggerEvents) { 436 mTriggerEvents.put(sensor.getHandle(), t); 437 } 438 } 439 440 @Override 441 public void removeSensorEvent(Sensor sensor) { 442 synchronized (mTriggerEvents) { 443 mTriggerEvents.delete(sensor.getHandle()); 444 } 445 } 446 447 // Called from native code. 448 @SuppressWarnings("unused") 449 @Override 450 protected void dispatchSensorEvent(int handle, float[] values, int accuracy, 451 long timestamp) { 452 final Sensor sensor = sHandleToSensor.get(handle); 453 TriggerEvent t = null; 454 synchronized (mTriggerEvents) { 455 t = mTriggerEvents.get(handle); 456 } 457 if (t == null) { 458 Log.e(TAG, "Error: Trigger Event is null for Sensor: " + sensor); 459 return; 460 } 461 462 // Copy from the values array. 463 System.arraycopy(values, 0, t.values, 0, t.values.length); 464 t.timestamp = timestamp; 465 t.sensor = sensor; 466 467 // A trigger sensor is auto disabled. So just clean up and don't call native 468 // disable. 469 mManager.cancelTriggerSensorImpl(mListener, sensor, false); 470 471 mListener.onTrigger(t); 472 } 473 474 @SuppressWarnings("unused") 475 protected void dispatchFlushCompleteEvent(int handle) { 476 } 477 } 478} 479