SystemSensorManager.java revision 25157e458d6e10b027d1ba6b78b0487156c9f57a
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.Looper; 20import android.os.Process; 21import android.os.Handler; 22import android.os.Message; 23import android.util.Log; 24import android.util.SparseArray; 25import android.util.SparseBooleanArray; 26import android.util.SparseIntArray; 27 28import java.util.ArrayList; 29import java.util.List; 30 31/** 32 * Sensor manager implementation that communicates with the built-in 33 * system sensors. 34 * 35 * @hide 36 */ 37public class SystemSensorManager extends SensorManager { 38 private static final String TAG = "SensorManager"; 39 40 /*-----------------------------------------------------------------------*/ 41 42 final Looper mMainLooper; 43 44 /*-----------------------------------------------------------------------*/ 45 46 private static final int SENSOR_DISABLE = -1; 47 private static boolean sSensorModuleInitialized = false; 48 private static ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>(); 49 /* The thread and the sensor list are global to the process 50 * but the actual thread is spawned on demand */ 51 private static SensorThread sSensorThread; 52 private static int sQueue; 53 54 // Used within this module from outside SensorManager, don't make private 55 static SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>(); 56 static final ArrayList<ListenerDelegate> sListeners = 57 new ArrayList<ListenerDelegate>(); 58 59 /*-----------------------------------------------------------------------*/ 60 61 private static SensorEventPool sPool; 62 63 /*-----------------------------------------------------------------------*/ 64 65 static private class SensorThread { 66 67 Thread mThread; 68 boolean mSensorsReady; 69 70 SensorThread() { 71 } 72 73 @Override 74 protected void finalize() { 75 } 76 77 // must be called with sListeners lock 78 boolean startLocked() { 79 try { 80 if (mThread == null) { 81 mSensorsReady = false; 82 SensorThreadRunnable runnable = new SensorThreadRunnable(); 83 Thread thread = new Thread(runnable, SensorThread.class.getName()); 84 thread.start(); 85 synchronized (runnable) { 86 while (mSensorsReady == false) { 87 runnable.wait(); 88 } 89 } 90 mThread = thread; 91 } 92 } catch (InterruptedException e) { 93 } 94 return mThread == null ? false : true; 95 } 96 97 private class SensorThreadRunnable implements Runnable { 98 SensorThreadRunnable() { 99 } 100 101 private boolean open() { 102 // NOTE: this cannot synchronize on sListeners, since 103 // it's held in the main thread at least until we 104 // return from here. 105 sQueue = sensors_create_queue(); 106 return true; 107 } 108 109 public void run() { 110 //Log.d(TAG, "entering main sensor thread"); 111 final float[] values = new float[3]; 112 final int[] status = new int[1]; 113 final long timestamp[] = new long[1]; 114 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); 115 116 if (!open()) { 117 return; 118 } 119 120 synchronized (this) { 121 // we've open the driver, we're ready to open the sensors 122 mSensorsReady = true; 123 this.notify(); 124 } 125 126 while (true) { 127 // wait for an event 128 final int sensor = sensors_data_poll(sQueue, values, status, timestamp); 129 130 int accuracy = status[0]; 131 synchronized (sListeners) { 132 if (sensor == -1 || sListeners.isEmpty()) { 133 // we lost the connection to the event stream. this happens 134 // when the last listener is removed or if there is an error 135 if (sensor == -1 && !sListeners.isEmpty()) { 136 // log a warning in case of abnormal termination 137 Log.e(TAG, "_sensors_data_poll() failed, we bail out: sensors=" + sensor); 138 } 139 // we have no more listeners or polling failed, terminate the thread 140 sensors_destroy_queue(sQueue); 141 sQueue = 0; 142 mThread = null; 143 break; 144 } 145 final Sensor sensorObject = sHandleToSensor.get(sensor); 146 if (sensorObject != null) { 147 // report the sensor event to all listeners that 148 // care about it. 149 final int size = sListeners.size(); 150 for (int i=0 ; i<size ; i++) { 151 ListenerDelegate listener = sListeners.get(i); 152 if (listener.hasSensor(sensorObject)) { 153 // this is asynchronous (okay to call 154 // with sListeners lock held). 155 listener.onSensorChangedLocked(sensorObject, 156 values, timestamp, accuracy); 157 } 158 } 159 } 160 } 161 } 162 //Log.d(TAG, "exiting main sensor thread"); 163 } 164 } 165 } 166 167 /*-----------------------------------------------------------------------*/ 168 169 private class ListenerDelegate { 170 private final SensorEventListener mSensorEventListener; 171 private final ArrayList<Sensor> mSensorList = new ArrayList<Sensor>(); 172 private final Handler mHandler; 173 public SparseBooleanArray mSensors = new SparseBooleanArray(); 174 public SparseBooleanArray mFirstEvent = new SparseBooleanArray(); 175 public SparseIntArray mSensorAccuracies = new SparseIntArray(); 176 177 ListenerDelegate(SensorEventListener listener, Sensor sensor, Handler handler) { 178 mSensorEventListener = listener; 179 Looper looper = (handler != null) ? handler.getLooper() : mMainLooper; 180 // currently we create one Handler instance per listener, but we could 181 // have one per looper (we'd need to pass the ListenerDelegate 182 // instance to handleMessage and keep track of them separately). 183 mHandler = new Handler(looper) { 184 @Override 185 public void handleMessage(Message msg) { 186 final SensorEvent t = (SensorEvent)msg.obj; 187 final int handle = t.sensor.getHandle(); 188 189 switch (t.sensor.getType()) { 190 // Only report accuracy for sensors that support it. 191 case Sensor.TYPE_MAGNETIC_FIELD: 192 case Sensor.TYPE_ORIENTATION: 193 // call onAccuracyChanged() only if the value changes 194 final int accuracy = mSensorAccuracies.get(handle); 195 if ((t.accuracy >= 0) && (accuracy != t.accuracy)) { 196 mSensorAccuracies.put(handle, t.accuracy); 197 mSensorEventListener.onAccuracyChanged(t.sensor, t.accuracy); 198 } 199 break; 200 default: 201 // For other sensors, just report the accuracy once 202 if (mFirstEvent.get(handle) == false) { 203 mFirstEvent.put(handle, true); 204 mSensorEventListener.onAccuracyChanged( 205 t.sensor, SENSOR_STATUS_ACCURACY_HIGH); 206 } 207 break; 208 } 209 210 mSensorEventListener.onSensorChanged(t); 211 sPool.returnToPool(t); 212 } 213 }; 214 addSensor(sensor); 215 } 216 217 Object getListener() { 218 return mSensorEventListener; 219 } 220 221 void addSensor(Sensor sensor) { 222 mSensors.put(sensor.getHandle(), true); 223 mSensorList.add(sensor); 224 } 225 int removeSensor(Sensor sensor) { 226 mSensors.delete(sensor.getHandle()); 227 mSensorList.remove(sensor); 228 return mSensors.size(); 229 } 230 boolean hasSensor(Sensor sensor) { 231 return mSensors.get(sensor.getHandle()); 232 } 233 List<Sensor> getSensors() { 234 return mSensorList; 235 } 236 237 void onSensorChangedLocked(Sensor sensor, float[] values, long[] timestamp, int accuracy) { 238 SensorEvent t = sPool.getFromPool(); 239 final float[] v = t.values; 240 v[0] = values[0]; 241 v[1] = values[1]; 242 v[2] = values[2]; 243 t.timestamp = timestamp[0]; 244 t.accuracy = accuracy; 245 t.sensor = sensor; 246 Message msg = Message.obtain(); 247 msg.what = 0; 248 msg.obj = t; 249 msg.setAsynchronous(true); 250 mHandler.sendMessage(msg); 251 } 252 } 253 254 /** 255 * {@hide} 256 */ 257 public SystemSensorManager(Looper mainLooper) { 258 mMainLooper = mainLooper; 259 260 synchronized(sListeners) { 261 if (!sSensorModuleInitialized) { 262 sSensorModuleInitialized = true; 263 264 nativeClassInit(); 265 266 // initialize the sensor list 267 sensors_module_init(); 268 final ArrayList<Sensor> fullList = sFullSensorsList; 269 int i = 0; 270 do { 271 Sensor sensor = new Sensor(); 272 i = sensors_module_get_next_sensor(sensor, i); 273 274 if (i>=0) { 275 //Log.d(TAG, "found sensor: " + sensor.getName() + 276 // ", handle=" + sensor.getHandle()); 277 fullList.add(sensor); 278 sHandleToSensor.append(sensor.getHandle(), sensor); 279 } 280 } while (i>0); 281 282 sPool = new SensorEventPool( sFullSensorsList.size()*2 ); 283 sSensorThread = new SensorThread(); 284 } 285 } 286 } 287 288 /** @hide */ 289 @Override 290 protected List<Sensor> getFullSensorList() { 291 return sFullSensorsList; 292 } 293 294 private boolean enableSensorLocked(Sensor sensor, int delay) { 295 boolean result = false; 296 for (ListenerDelegate i : sListeners) { 297 if (i.hasSensor(sensor)) { 298 String name = sensor.getName(); 299 int handle = sensor.getHandle(); 300 result = sensors_enable_sensor(sQueue, name, handle, delay); 301 break; 302 } 303 } 304 return result; 305 } 306 307 private boolean disableSensorLocked(Sensor sensor) { 308 for (ListenerDelegate i : sListeners) { 309 if (i.hasSensor(sensor)) { 310 // not an error, it's just that this sensor is still in use 311 return true; 312 } 313 } 314 String name = sensor.getName(); 315 int handle = sensor.getHandle(); 316 return sensors_enable_sensor(sQueue, name, handle, SENSOR_DISABLE); 317 } 318 319 /** @hide */ 320 protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor, 321 int delay, Handler handler) { 322 boolean result = true; 323 synchronized (sListeners) { 324 // look for this listener in our list 325 ListenerDelegate l = null; 326 for (ListenerDelegate i : sListeners) { 327 if (i.getListener() == listener) { 328 l = i; 329 break; 330 } 331 } 332 333 // if we don't find it, add it to the list 334 if (l == null) { 335 l = new ListenerDelegate(listener, sensor, handler); 336 sListeners.add(l); 337 // if the list is not empty, start our main thread 338 if (!sListeners.isEmpty()) { 339 if (sSensorThread.startLocked()) { 340 if (!enableSensorLocked(sensor, delay)) { 341 // oops. there was an error 342 sListeners.remove(l); 343 result = false; 344 } 345 } else { 346 // there was an error, remove the listener 347 sListeners.remove(l); 348 result = false; 349 } 350 } else { 351 // weird, we couldn't add the listener 352 result = false; 353 } 354 } else if (!l.hasSensor(sensor)) { 355 l.addSensor(sensor); 356 if (!enableSensorLocked(sensor, delay)) { 357 // oops. there was an error 358 l.removeSensor(sensor); 359 result = false; 360 } 361 } 362 } 363 364 return result; 365 } 366 367 /** @hide */ 368 @Override 369 protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) { 370 synchronized (sListeners) { 371 final int size = sListeners.size(); 372 for (int i=0 ; i<size ; i++) { 373 ListenerDelegate l = sListeners.get(i); 374 if (l.getListener() == listener) { 375 if (sensor == null) { 376 sListeners.remove(i); 377 // disable all sensors for this listener 378 for (Sensor s : l.getSensors()) { 379 disableSensorLocked(s); 380 } 381 } else if (l.removeSensor(sensor) == 0) { 382 // if we have no more sensors enabled on this listener, 383 // take it off the list. 384 sListeners.remove(i); 385 disableSensorLocked(sensor); 386 } 387 break; 388 } 389 } 390 } 391 } 392 393 private static native void nativeClassInit(); 394 395 private static native int sensors_module_init(); 396 private static native int sensors_module_get_next_sensor(Sensor sensor, int next); 397 398 // Used within this module from outside SensorManager, don't make private 399 static native int sensors_create_queue(); 400 static native void sensors_destroy_queue(int queue); 401 static native boolean sensors_enable_sensor(int queue, String name, int sensor, int enable); 402 static native int sensors_data_poll(int queue, float[] values, int[] status, long[] timestamp); 403} 404