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