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