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