SensorManager.java revision 287b30920102b5466efa53a2f17ed69f2c776c16
1/* 2 * Copyright (C) 2008 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.Binder; 21import android.os.Looper; 22import android.os.ParcelFileDescriptor; 23import android.os.Process; 24import android.os.RemoteException; 25import android.os.Handler; 26import android.os.Message; 27import android.os.ServiceManager; 28import android.util.Log; 29import android.util.SparseArray; 30import android.view.IRotationWatcher; 31import android.view.IWindowManager; 32import android.view.Surface; 33 34import java.io.FileDescriptor; 35import java.io.IOException; 36import java.util.ArrayList; 37import java.util.Collections; 38import java.util.HashMap; 39import java.util.List; 40 41/** 42 * Class that lets you access the device's sensors. Get an instance of this 43 * class by calling {@link android.content.Context#getSystemService(java.lang.String) 44 * Context.getSystemService()} with an argument of {@link android.content.Context#SENSOR_SERVICE}. 45 */ 46public class SensorManager 47{ 48 private static final String TAG = "SensorManager"; 49 private static final float[] mTempMatrix = new float[16]; 50 51 /* NOTE: sensor IDs must be a power of 2 */ 52 53 /** 54 * A constant describing an orientation sensor. 55 * See {@link android.hardware.SensorListener SensorListener} for more details. 56 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 57 */ 58 @Deprecated 59 public static final int SENSOR_ORIENTATION = 1 << 0; 60 61 /** 62 * A constant describing an accelerometer. 63 * See {@link android.hardware.SensorListener SensorListener} for more details. 64 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 65 */ 66 @Deprecated 67 public static final int SENSOR_ACCELEROMETER = 1 << 1; 68 69 /** 70 * A constant describing a temperature sensor 71 * See {@link android.hardware.SensorListener SensorListener} for more details. 72 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 73 */ 74 @Deprecated 75 public static final int SENSOR_TEMPERATURE = 1 << 2; 76 77 /** 78 * A constant describing a magnetic sensor 79 * See {@link android.hardware.SensorListener SensorListener} for more details. 80 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 81 */ 82 @Deprecated 83 public static final int SENSOR_MAGNETIC_FIELD = 1 << 3; 84 85 /** 86 * A constant describing an ambient light sensor 87 * See {@link android.hardware.SensorListener SensorListener} for more details. 88 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 89 */ 90 @Deprecated 91 public static final int SENSOR_LIGHT = 1 << 4; 92 93 /** 94 * A constant describing a proximity sensor 95 * See {@link android.hardware.SensorListener SensorListener} for more details. 96 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 97 */ 98 @Deprecated 99 public static final int SENSOR_PROXIMITY = 1 << 5; 100 101 /** 102 * A constant describing a Tricorder 103 * See {@link android.hardware.SensorListener SensorListener} for more details. 104 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 105 */ 106 @Deprecated 107 public static final int SENSOR_TRICORDER = 1 << 6; 108 109 /** 110 * A constant describing an orientation sensor. 111 * See {@link android.hardware.SensorListener SensorListener} for more details. 112 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 113 */ 114 @Deprecated 115 public static final int SENSOR_ORIENTATION_RAW = 1 << 7; 116 117 /** A constant that includes all sensors */ 118 @Deprecated 119 public static final int SENSOR_ALL = 0x7F; 120 121 /** Smallest sensor ID */ 122 @Deprecated 123 public static final int SENSOR_MIN = SENSOR_ORIENTATION; 124 125 /** Largest sensor ID */ 126 @Deprecated 127 public static final int SENSOR_MAX = ((SENSOR_ALL + 1)>>1); 128 129 130 /** Index of the X value in the array returned by 131 * {@link android.hardware.SensorListener#onSensorChanged} */ 132 @Deprecated 133 public static final int DATA_X = 0; 134 /** Index of the Y value in the array returned by 135 * {@link android.hardware.SensorListener#onSensorChanged} */ 136 @Deprecated 137 public static final int DATA_Y = 1; 138 /** Index of the Z value in the array returned by 139 * {@link android.hardware.SensorListener#onSensorChanged} */ 140 @Deprecated 141 public static final int DATA_Z = 2; 142 143 /** Offset to the untransformed values in the array returned by 144 * {@link android.hardware.SensorListener#onSensorChanged} */ 145 @Deprecated 146 public static final int RAW_DATA_INDEX = 3; 147 148 /** Index of the untransformed X value in the array returned by 149 * {@link android.hardware.SensorListener#onSensorChanged} */ 150 @Deprecated 151 public static final int RAW_DATA_X = 3; 152 /** Index of the untransformed Y value in the array returned by 153 * {@link android.hardware.SensorListener#onSensorChanged} */ 154 @Deprecated 155 public static final int RAW_DATA_Y = 4; 156 /** Index of the untransformed Z value in the array returned by 157 * {@link android.hardware.SensorListener#onSensorChanged} */ 158 @Deprecated 159 public static final int RAW_DATA_Z = 5; 160 161 162 /** Standard gravity (g) on Earth. This value is equivalent to 1G */ 163 public static final float STANDARD_GRAVITY = 9.80665f; 164 165 /** values returned by the accelerometer in various locations in the universe. 166 * all values are in SI units (m/s^2) */ 167 public static final float GRAVITY_SUN = 275.0f; 168 public static final float GRAVITY_MERCURY = 3.70f; 169 public static final float GRAVITY_VENUS = 8.87f; 170 public static final float GRAVITY_EARTH = 9.80665f; 171 public static final float GRAVITY_MOON = 1.6f; 172 public static final float GRAVITY_MARS = 3.71f; 173 public static final float GRAVITY_JUPITER = 23.12f; 174 public static final float GRAVITY_SATURN = 8.96f; 175 public static final float GRAVITY_URANUS = 8.69f; 176 public static final float GRAVITY_NEPTUNE = 11.0f; 177 public static final float GRAVITY_PLUTO = 0.6f; 178 public static final float GRAVITY_DEATH_STAR_I = 0.000000353036145f; 179 public static final float GRAVITY_THE_ISLAND = 4.815162342f; 180 181 182 /** Maximum magnetic field on Earth's surface */ 183 public static final float MAGNETIC_FIELD_EARTH_MAX = 60.0f; 184 185 /** Minimum magnetic field on Earth's surface */ 186 public static final float MAGNETIC_FIELD_EARTH_MIN = 30.0f; 187 188 189 /** Various luminance values during the day (lux) */ 190 public static final float LIGHT_SUNLIGHT_MAX = 120000.0f; 191 public static final float LIGHT_SUNLIGHT = 110000.0f; 192 public static final float LIGHT_SHADE = 20000.0f; 193 public static final float LIGHT_OVERCAST = 10000.0f; 194 public static final float LIGHT_SUNRISE = 400.0f; 195 public static final float LIGHT_CLOUDY = 100.0f; 196 /** Various luminance values during the night (lux) */ 197 public static final float LIGHT_FULLMOON = 0.25f; 198 public static final float LIGHT_NO_MOON = 0.001f; 199 200 /** get sensor data as fast as possible */ 201 public static final int SENSOR_DELAY_FASTEST = 0; 202 /** rate suitable for games */ 203 public static final int SENSOR_DELAY_GAME = 1; 204 /** rate suitable for the user interface */ 205 public static final int SENSOR_DELAY_UI = 2; 206 /** rate (default) suitable for screen orientation changes */ 207 public static final int SENSOR_DELAY_NORMAL = 3; 208 209 210 /** The values returned by this sensor cannot be trusted, calibration 211 * is needed or the environment doesn't allow readings */ 212 public static final int SENSOR_STATUS_UNRELIABLE = 0; 213 214 /** This sensor is reporting data with low accuracy, calibration with the 215 * environment is needed */ 216 public static final int SENSOR_STATUS_ACCURACY_LOW = 1; 217 218 /** This sensor is reporting data with an average level of accuracy, 219 * calibration with the environment may improve the readings */ 220 public static final int SENSOR_STATUS_ACCURACY_MEDIUM = 2; 221 222 /** This sensor is reporting data with maximum accuracy */ 223 public static final int SENSOR_STATUS_ACCURACY_HIGH = 3; 224 225 /** see {@link #remapCoordinateSystem} */ 226 public static final int AXIS_X = 1; 227 /** see {@link #remapCoordinateSystem} */ 228 public static final int AXIS_Y = 2; 229 /** see {@link #remapCoordinateSystem} */ 230 public static final int AXIS_Z = 3; 231 /** see {@link #remapCoordinateSystem} */ 232 public static final int AXIS_MINUS_X = AXIS_X | 0x80; 233 /** see {@link #remapCoordinateSystem} */ 234 public static final int AXIS_MINUS_Y = AXIS_Y | 0x80; 235 /** see {@link #remapCoordinateSystem} */ 236 public static final int AXIS_MINUS_Z = AXIS_Z | 0x80; 237 238 /*-----------------------------------------------------------------------*/ 239 240 private ISensorService mSensorService; 241 Looper mMainLooper; 242 @SuppressWarnings("deprecation") 243 private HashMap<SensorListener, LegacyListener> mLegacyListenersMap = 244 new HashMap<SensorListener, LegacyListener>(); 245 246 /*-----------------------------------------------------------------------*/ 247 248 private static final int SENSOR_DISABLE = -1; 249 private static boolean sSensorModuleInitialized = false; 250 private static ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>(); 251 private static SparseArray<List<Sensor>> sSensorListByType = new SparseArray<List<Sensor>>(); 252 private static IWindowManager sWindowManager; 253 private static int sRotation = Surface.ROTATION_0; 254 /* The thread and the sensor list are global to the process 255 * but the actual thread is spawned on demand */ 256 private static SensorThread sSensorThread; 257 258 // Used within this module from outside SensorManager, don't make private 259 static SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>(); 260 static final ArrayList<ListenerDelegate> sListeners = 261 new ArrayList<ListenerDelegate>(); 262 263 /*-----------------------------------------------------------------------*/ 264 265 static private class SensorThread { 266 267 Thread mThread; 268 269 SensorThread() { 270 // this gets to the sensor module. We can have only one per process. 271 sensors_data_init(); 272 } 273 274 @Override 275 protected void finalize() { 276 sensors_data_uninit(); 277 } 278 279 // must be called with sListeners lock 280 void startLocked(ISensorService service) { 281 try { 282 if (mThread == null) { 283 ParcelFileDescriptor fd = service.getDataChanel(); 284 mThread = new Thread(new SensorThreadRunnable(fd), 285 SensorThread.class.getName()); 286 mThread.start(); 287 } 288 } catch (RemoteException e) { 289 Log.e(TAG, "RemoteException in startLocked: ", e); 290 } 291 } 292 293 private class SensorThreadRunnable implements Runnable { 294 private ParcelFileDescriptor mSensorDataFd; 295 SensorThreadRunnable(ParcelFileDescriptor fd) { 296 mSensorDataFd = fd; 297 } 298 public void run() { 299 //Log.d(TAG, "entering main sensor thread"); 300 final float[] values = new float[3]; 301 final int[] status = new int[1]; 302 final long timestamp[] = new long[1]; 303 Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY); 304 305 if (mSensorDataFd == null) { 306 Log.e(TAG, "mSensorDataFd == NULL, exiting"); 307 synchronized (sListeners) { 308 mThread = null; 309 } 310 return; 311 } 312 // this thread is guaranteed to be unique 313 sensors_data_open(mSensorDataFd.getFileDescriptor()); 314 try { 315 mSensorDataFd.close(); 316 } catch (IOException e) { 317 // *shrug* 318 Log.e(TAG, "IOException: ", e); 319 } 320 mSensorDataFd = null; 321 322 323 while (true) { 324 // wait for an event 325 final int sensor = sensors_data_poll(values, status, timestamp); 326 327 int accuracy = status[0]; 328 synchronized (sListeners) { 329 if (sensor == -1 || sListeners.isEmpty()) { 330 if (sensor == -1) { 331 // we lost the connection to the event stream. this happens 332 // when the last listener is removed. 333 Log.d(TAG, "_sensors_data_poll() failed, we bail out."); 334 } 335 336 // we have no more listeners or polling failed, terminate the thread 337 sensors_data_close(); 338 mThread = null; 339 break; 340 } 341 final Sensor sensorObject = sHandleToSensor.get(sensor); 342 if (sensorObject != null) { 343 // report the sensor event to all listeners that 344 // care about it. 345 final int size = sListeners.size(); 346 for (int i=0 ; i<size ; i++) { 347 ListenerDelegate listener = sListeners.get(i); 348 if (listener.hasSensor(sensorObject)) { 349 // this is asynchronous (okay to call 350 // with sListeners lock held). 351 listener.onSensorChangedLocked(sensorObject, 352 values, timestamp, accuracy); 353 } 354 } 355 } 356 } 357 } 358 //Log.d(TAG, "exiting main sensor thread"); 359 } 360 } 361 } 362 363 /*-----------------------------------------------------------------------*/ 364 365 private class ListenerDelegate extends Binder { 366 final SensorEventListener mSensorEventListener; 367 private final ArrayList<Sensor> mSensorList = new ArrayList<Sensor>(); 368 private final Handler mHandler; 369 private SensorEvent mValuesPool; 370 public int mSensors; 371 372 ListenerDelegate(SensorEventListener listener, Sensor sensor, Handler handler) { 373 mSensorEventListener = listener; 374 Looper looper = (handler != null) ? handler.getLooper() : mMainLooper; 375 // currently we create one Handler instance per listener, but we could 376 // have one per looper (we'd need to pass the ListenerDelegate 377 // instance to handleMessage and keep track of them separately). 378 mHandler = new Handler(looper) { 379 @Override 380 public void handleMessage(Message msg) { 381 SensorEvent t = (SensorEvent)msg.obj; 382 if (t.accuracy >= 0) { 383 mSensorEventListener.onAccuracyChanged(t.sensor, t.accuracy); 384 } 385 mSensorEventListener.onSensorChanged(t); 386 returnToPool(t); 387 } 388 }; 389 addSensor(sensor); 390 } 391 392 protected SensorEvent createSensorEvent() { 393 // maximal size for all legacy events is 3 394 return new SensorEvent(3); 395 } 396 397 protected SensorEvent getFromPool() { 398 SensorEvent t = null; 399 synchronized (this) { 400 // remove the array from the pool 401 t = mValuesPool; 402 mValuesPool = null; 403 } 404 if (t == null) { 405 // the pool was empty, we need a new one 406 t = createSensorEvent(); 407 } 408 return t; 409 } 410 411 protected void returnToPool(SensorEvent t) { 412 synchronized (this) { 413 // put back the array into the pool 414 if (mValuesPool == null) { 415 mValuesPool = t; 416 } 417 } 418 } 419 420 Object getListener() { 421 return mSensorEventListener; 422 } 423 424 int addSensor(Sensor sensor) { 425 mSensors |= 1<<sensor.getHandle(); 426 mSensorList.add(sensor); 427 return mSensors; 428 } 429 int removeSensor(Sensor sensor) { 430 mSensors &= ~(1<<sensor.getHandle()); 431 mSensorList.remove(sensor); 432 return mSensors; 433 } 434 boolean hasSensor(Sensor sensor) { 435 return ((mSensors & (1<<sensor.getHandle())) != 0); 436 } 437 List<Sensor> getSensors() { 438 return mSensorList; 439 } 440 441 void onSensorChangedLocked(Sensor sensor, float[] values, long[] timestamp, int accuracy) { 442 SensorEvent t = getFromPool(); 443 final float[] v = t.values; 444 v[0] = values[0]; 445 v[1] = values[1]; 446 v[2] = values[2]; 447 t.timestamp = timestamp[0]; 448 t.accuracy = accuracy; 449 t.sensor = sensor; 450 Message msg = Message.obtain(); 451 msg.what = 0; 452 msg.obj = t; 453 mHandler.sendMessage(msg); 454 } 455 } 456 457 /** 458 * {@hide} 459 */ 460 public SensorManager(Looper mainLooper) { 461 mSensorService = ISensorService.Stub.asInterface( 462 ServiceManager.getService(Context.SENSOR_SERVICE)); 463 mMainLooper = mainLooper; 464 465 466 synchronized(sListeners) { 467 if (!sSensorModuleInitialized) { 468 sSensorModuleInitialized = true; 469 470 nativeClassInit(); 471 472 sWindowManager = IWindowManager.Stub.asInterface( 473 ServiceManager.getService("window")); 474 if (sWindowManager != null) { 475 // if it's null we're running in the system process 476 // which won't get the rotated values 477 try { 478 sRotation = sWindowManager.watchRotation( 479 new IRotationWatcher.Stub() { 480 public void onRotationChanged(int rotation) { 481 SensorManager.this.onRotationChanged(rotation); 482 } 483 } 484 ); 485 } catch (RemoteException e) { 486 } 487 } 488 489 // initialize the sensor list 490 sensors_module_init(); 491 final ArrayList<Sensor> fullList = sFullSensorsList; 492 int i = 0; 493 do { 494 Sensor sensor = new Sensor(); 495 i = sensors_module_get_next_sensor(sensor, i); 496 497 if (i>=0) { 498 Log.d(TAG, "found sensor: " + sensor.getName() + 499 ", handle=" + sensor.getHandle()); 500 sensor.setLegacyType(getLegacySensorType(sensor.getType())); 501 fullList.add(sensor); 502 sHandleToSensor.append(sensor.getHandle(), sensor); 503 } 504 } while (i>0); 505 506 sSensorThread = new SensorThread(); 507 } 508 } 509 } 510 511 private int getLegacySensorType(int type) { 512 switch (type) { 513 case Sensor.TYPE_ACCELEROMETER: 514 return SENSOR_ACCELEROMETER; 515 case Sensor.TYPE_MAGNETIC_FIELD: 516 return SENSOR_MAGNETIC_FIELD; 517 case Sensor.TYPE_ORIENTATION: 518 return SENSOR_ORIENTATION_RAW; 519 case Sensor.TYPE_TEMPERATURE: 520 return SENSOR_TEMPERATURE; 521 } 522 return 0; 523 } 524 525 /** @return available sensors. 526 * @deprecated This method is deprecated, use 527 * {@link SensorManager#getSensorList(int)} instead 528 */ 529 @Deprecated 530 public int getSensors() { 531 int result = 0; 532 final ArrayList<Sensor> fullList = sFullSensorsList; 533 for (Sensor i : fullList) { 534 switch (i.getType()) { 535 case Sensor.TYPE_ACCELEROMETER: 536 result |= SensorManager.SENSOR_ACCELEROMETER; 537 break; 538 case Sensor.TYPE_MAGNETIC_FIELD: 539 result |= SensorManager.SENSOR_MAGNETIC_FIELD; 540 break; 541 case Sensor.TYPE_ORIENTATION: 542 result |= SensorManager.SENSOR_ORIENTATION | 543 SensorManager.SENSOR_ORIENTATION_RAW; 544 break; 545 } 546 } 547 return result; 548 } 549 550 /** 551 * Use this method to get the list of available sensors of a certain 552 * type. Make multiple calls to get sensors of different types or use 553 * {@link android.hardware.Sensor#TYPE_ALL Sensor.TYPE_ALL} to get all 554 * the sensors. 555 * 556 * @param type of sensors requested 557 * @return a list of sensors matching the asked type. 558 */ 559 public List<Sensor> getSensorList(int type) { 560 // cache the returned lists the first time 561 List<Sensor> list; 562 final ArrayList<Sensor> fullList = sFullSensorsList; 563 synchronized(fullList) { 564 list = sSensorListByType.get(type); 565 if (list == null) { 566 if (type == Sensor.TYPE_ALL) { 567 list = fullList; 568 } else { 569 list = new ArrayList<Sensor>(); 570 for (Sensor i : fullList) { 571 if (i.getType() == type) 572 list.add(i); 573 } 574 } 575 list = Collections.unmodifiableList(list); 576 sSensorListByType.append(type, list); 577 } 578 } 579 return list; 580 } 581 582 /** 583 * Use this method to get the default sensor for a given type. Note that 584 * the returned sensor could be a composite sensor, and its data could be 585 * averaged or filtered. If you need to access the raw sensors use 586 * {@link SensorManager#getSensorList(int) getSensorList}. 587 * 588 * 589 * @param type of sensors requested 590 * @return the default sensors matching the asked type. 591 */ 592 public Sensor getDefaultSensor(int type) { 593 // TODO: need to be smarter, for now, just return the 1st sensor 594 List<Sensor> l = getSensorList(type); 595 return l.isEmpty() ? null : l.get(0); 596 } 597 598 599 /** 600 * Registers a listener for given sensors. 601 * @deprecated This method is deprecated, use 602 * {@link SensorManager#registerListener(SensorEventListener, Sensor, int)} 603 * instead. 604 * 605 * @param listener sensor listener object 606 * @param sensors a bit masks of the sensors to register to 607 * 608 * @return true if the sensor is supported and successfully enabled 609 */ 610 @Deprecated 611 public boolean registerListener(SensorListener listener, int sensors) { 612 return registerListener(listener, sensors, SENSOR_DELAY_NORMAL); 613 } 614 615 /** 616 * Registers a SensorListener for given sensors. 617 * @deprecated This method is deprecated, use 618 * {@link SensorManager#registerListener(SensorEventListener, Sensor, int)} 619 * instead. 620 * 621 * @param listener sensor listener object 622 * @param sensors a bit masks of the sensors to register to 623 * @param rate rate of events. This is only a hint to the system. events 624 * may be received faster or slower than the specified rate. Usually events 625 * are received faster. The value must be one of {@link #SENSOR_DELAY_NORMAL}, 626 * {@link #SENSOR_DELAY_UI}, {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}. 627 * 628 * @return true if the sensor is supported and successfully enabled 629 */ 630 @Deprecated 631 public boolean registerListener(SensorListener listener, int sensors, int rate) { 632 if (listener == null) { 633 return false; 634 } 635 boolean result = false; 636 result = registerLegacyListener(SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER, 637 listener, sensors, rate) || result; 638 result = registerLegacyListener(SENSOR_MAGNETIC_FIELD, Sensor.TYPE_MAGNETIC_FIELD, 639 listener, sensors, rate) || result; 640 result = registerLegacyListener(SENSOR_ORIENTATION_RAW, Sensor.TYPE_ORIENTATION, 641 listener, sensors, rate) || result; 642 result = registerLegacyListener(SENSOR_ORIENTATION, Sensor.TYPE_ORIENTATION, 643 listener, sensors, rate) || result; 644 result = registerLegacyListener(SENSOR_TEMPERATURE, Sensor.TYPE_TEMPERATURE, 645 listener, sensors, rate) || result; 646 return result; 647 } 648 649 @SuppressWarnings("deprecation") 650 private boolean registerLegacyListener(int legacyType, int type, 651 SensorListener listener, int sensors, int rate) 652 { 653 if (listener == null) { 654 return false; 655 } 656 boolean result = false; 657 // Are we activating this legacy sensor? 658 if ((sensors & legacyType) != 0) { 659 // if so, find a suitable Sensor 660 Sensor sensor = getDefaultSensor(type); 661 if (sensor != null) { 662 // If we don't already have one, create a LegacyListener 663 // to wrap this listener and process the events as 664 // they are expected by legacy apps. 665 LegacyListener legacyListener = null; 666 synchronized (mLegacyListenersMap) { 667 legacyListener = mLegacyListenersMap.get(listener); 668 if (legacyListener == null) { 669 // we didn't find a LegacyListener for this client, 670 // create one, and put it in our list. 671 legacyListener = new LegacyListener(listener); 672 mLegacyListenersMap.put(listener, legacyListener); 673 } 674 } 675 // register this legacy sensor with this legacy listener 676 legacyListener.registerSensor(legacyType); 677 // and finally, register the legacy listener with the new apis 678 result = registerListener(legacyListener, sensor, rate); 679 } 680 } 681 return result; 682 } 683 684 /** 685 * Unregisters a listener for the sensors with which it is registered. 686 * @deprecated This method is deprecated, use 687 * {@link SensorManager#unregisterListener(SensorEventListener, Sensor)} 688 * instead. 689 * 690 * @param listener a SensorListener object 691 * @param sensors a bit masks of the sensors to unregister from 692 */ 693 @Deprecated 694 public void unregisterListener(SensorListener listener, int sensors) { 695 unregisterLegacyListener(SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER, 696 listener, sensors); 697 unregisterLegacyListener(SENSOR_MAGNETIC_FIELD, Sensor.TYPE_MAGNETIC_FIELD, 698 listener, sensors); 699 unregisterLegacyListener(SENSOR_ORIENTATION_RAW, Sensor.TYPE_ORIENTATION, 700 listener, sensors); 701 unregisterLegacyListener(SENSOR_ORIENTATION, Sensor.TYPE_ORIENTATION, 702 listener, sensors); 703 unregisterLegacyListener(SENSOR_TEMPERATURE, Sensor.TYPE_TEMPERATURE, 704 listener, sensors); 705 } 706 707 @SuppressWarnings("deprecation") 708 private void unregisterLegacyListener(int legacyType, int type, 709 SensorListener listener, int sensors) 710 { 711 if (listener == null) { 712 return; 713 } 714 // do we know about this listener? 715 LegacyListener legacyListener = null; 716 synchronized (mLegacyListenersMap) { 717 legacyListener = mLegacyListenersMap.get(listener); 718 } 719 if (legacyListener != null) { 720 // Are we deactivating this legacy sensor? 721 if ((sensors & legacyType) != 0) { 722 // if so, find the corresponding Sensor 723 Sensor sensor = getDefaultSensor(type); 724 if (sensor != null) { 725 // unregister this legacy sensor and if we don't 726 // need the corresponding Sensor, unregister it too 727 if (legacyListener.unregisterSensor(legacyType)) { 728 // corresponding sensor not needed, unregister 729 unregisterListener(legacyListener, sensor); 730 // finally check if we still need the legacyListener 731 // in our mapping, if not, get rid of it too. 732 synchronized(sListeners) { 733 boolean found = false; 734 for (ListenerDelegate i : sListeners) { 735 if (i.getListener() == legacyListener) { 736 found = true; 737 break; 738 } 739 } 740 if (!found) { 741 synchronized (mLegacyListenersMap) { 742 mLegacyListenersMap.remove(listener); 743 } 744 } 745 } 746 } 747 } 748 } 749 } 750 } 751 752 /** 753 * Unregisters a listener for all sensors. 754 * @deprecated This method is deprecated, use 755 * {@link SensorManager#unregisterListener(SensorEventListener)} 756 * instead. 757 * 758 * @param listener a SensorListener object 759 */ 760 @Deprecated 761 public void unregisterListener(SensorListener listener) { 762 unregisterListener(listener, SENSOR_ALL | SENSOR_ORIENTATION_RAW); 763 } 764 765 /** 766 * Unregisters a listener for the sensors with which it is registered. 767 * 768 * @param listener a SensorEventListener object 769 * @param sensor the sensor to unregister from 770 * 771 */ 772 public void unregisterListener(SensorEventListener listener, Sensor sensor) { 773 unregisterListener((Object)listener, sensor); 774 } 775 776 /** 777 * Unregisters a listener for all sensors. 778 * 779 * @param listener a SensorListener object 780 * 781 */ 782 public void unregisterListener(SensorEventListener listener) { 783 unregisterListener((Object)listener); 784 } 785 786 787 /** 788 * Registers a {@link android.hardware.SensorEventListener SensorEventListener} 789 * for the given sensor. 790 * 791 * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object. 792 * @param sensor The {@link android.hardware.Sensor Sensor} to register to. 793 * @param rate The rate {@link android.hardware.SensorEvent sensor events} are delivered at. 794 * This is only a hint to the system. Events may be received faster or 795 * slower than the specified rate. Usually events are received faster. The value must be 796 * one of {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI}, {@link #SENSOR_DELAY_GAME}, 797 * or {@link #SENSOR_DELAY_FASTEST}. 798 * 799 * @return true if the sensor is supported and successfully enabled. 800 * 801 */ 802 public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate) { 803 return registerListener(listener, sensor, rate, null); 804 } 805 806 /** 807 * Registers a {@link android.hardware.SensorEventListener SensorEventListener} 808 * for the given sensor. 809 * 810 * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object. 811 * @param sensor The {@link android.hardware.Sensor Sensor} to register to. 812 * @param rate The rate {@link android.hardware.SensorEvent sensor events} are delivered at. 813 * This is only a hint to the system. Events may be received faster or 814 * slower than the specified rate. Usually events are received faster. The value must be one 815 * of {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI}, {@link #SENSOR_DELAY_GAME}, or 816 * {@link #SENSOR_DELAY_FASTEST}. 817 * @param handler The {@link android.os.Handler Handler} the 818 * {@link android.hardware.SensorEvent sensor events} will be delivered to. 819 * 820 * @return true if the sensor is supported and successfully enabled. 821 * 822 */ 823 public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate, 824 Handler handler) { 825 if (listener == null || sensor == null) { 826 return false; 827 } 828 boolean result; 829 int delay = -1; 830 switch (rate) { 831 case SENSOR_DELAY_FASTEST: 832 delay = 0; 833 break; 834 case SENSOR_DELAY_GAME: 835 delay = 20; 836 break; 837 case SENSOR_DELAY_UI: 838 delay = 60; 839 break; 840 case SENSOR_DELAY_NORMAL: 841 delay = 200; 842 break; 843 default: 844 return false; 845 } 846 847 try { 848 synchronized (sListeners) { 849 ListenerDelegate l = null; 850 for (ListenerDelegate i : sListeners) { 851 if (i.getListener() == listener) { 852 l = i; 853 break; 854 } 855 } 856 857 String name = sensor.getName(); 858 int handle = sensor.getHandle(); 859 if (l == null) { 860 l = new ListenerDelegate(listener, sensor, handler); 861 result = mSensorService.enableSensor(l, name, handle, delay); 862 if (result) { 863 sListeners.add(l); 864 sListeners.notify(); 865 } 866 if (!sListeners.isEmpty()) { 867 sSensorThread.startLocked(mSensorService); 868 } 869 } else { 870 result = mSensorService.enableSensor(l, name, handle, delay); 871 if (result) { 872 l.addSensor(sensor); 873 } 874 } 875 } 876 } catch (RemoteException e) { 877 Log.e(TAG, "RemoteException in registerListener: ", e); 878 result = false; 879 } 880 return result; 881 } 882 883 private void unregisterListener(Object listener, Sensor sensor) { 884 if (listener == null || sensor == null) { 885 return; 886 } 887 try { 888 synchronized (sListeners) { 889 final int size = sListeners.size(); 890 for (int i=0 ; i<size ; i++) { 891 ListenerDelegate l = sListeners.get(i); 892 if (l.getListener() == listener) { 893 // disable these sensors 894 String name = sensor.getName(); 895 int handle = sensor.getHandle(); 896 mSensorService.enableSensor(l, name, handle, SENSOR_DISABLE); 897 // if we have no more sensors enabled on this listener, 898 // take it off the list. 899 if (l.removeSensor(sensor) == 0) { 900 sListeners.remove(i); 901 } 902 break; 903 } 904 } 905 } 906 } catch (RemoteException e) { 907 Log.e(TAG, "RemoteException in unregisterListener: ", e); 908 } 909 } 910 911 private void unregisterListener(Object listener) { 912 if (listener == null) { 913 return; 914 } 915 try { 916 synchronized (sListeners) { 917 final int size = sListeners.size(); 918 for (int i=0 ; i<size ; i++) { 919 ListenerDelegate l = sListeners.get(i); 920 if (l.getListener() == listener) { 921 // disable all sensors for this listener 922 for (Sensor sensor : l.getSensors()) { 923 String name = sensor.getName(); 924 int handle = sensor.getHandle(); 925 mSensorService.enableSensor(l, name, handle, SENSOR_DISABLE); 926 } 927 sListeners.remove(i); 928 break; 929 } 930 } 931 } 932 } catch (RemoteException e) { 933 Log.e(TAG, "RemoteException in unregisterListener: ", e); 934 } 935 } 936 937 /** 938 * Computes the inclination matrix <b>I</b> as well as the rotation 939 * matrix <b>R</b> transforming a vector from the 940 * device coordinate system to the world's coordinate system which is 941 * defined as a direct orthonormal basis, where: 942 * 943 * <li>X is defined as the vector product <b>Y.Z</b> (It is tangential to 944 * the ground at the device's current location and roughly points East).</li> 945 * <li>Y is tangential to the ground at the device's current location and 946 * points towards the magnetic North Pole.</li> 947 * <li>Z points towards the sky and is perpendicular to the ground.</li> 948 * <p> 949 * <hr> 950 * <p>By definition: 951 * <p>[0 0 g] = <b>R</b> * <b>gravity</b> (g = magnitude of gravity) 952 * <p>[0 m 0] = <b>I</b> * <b>R</b> * <b>geomagnetic</b> 953 * (m = magnitude of geomagnetic field) 954 * <p><b>R</b> is the identity matrix when the device is aligned with the 955 * world's coordinate system, that is, when the device's X axis points 956 * toward East, the Y axis points to the North Pole and the device is facing 957 * the sky. 958 * 959 * <p><b>I</b> is a rotation matrix transforming the geomagnetic 960 * vector into the same coordinate space as gravity (the world's coordinate 961 * space). <b>I</b> is a simple rotation around the X axis. 962 * The inclination angle in radians can be computed with 963 * {@link #getInclination}. 964 * <hr> 965 * 966 * <p> Each matrix is returned either as a 3x3 or 4x4 row-major matrix 967 * depending on the length of the passed array: 968 * <p><u>If the array length is 16:</u> 969 * <pre> 970 * / M[ 0] M[ 1] M[ 2] M[ 3] \ 971 * | M[ 4] M[ 5] M[ 6] M[ 7] | 972 * | M[ 8] M[ 9] M[10] M[11] | 973 * \ M[12] M[13] M[14] M[15] / 974 *</pre> 975 * This matrix is ready to be used by OpenGL ES's 976 * {@link javax.microedition.khronos.opengles.GL10#glLoadMatrixf(float[], int) 977 * glLoadMatrixf(float[], int)}. 978 * <p>Note that because OpenGL matrices are column-major matrices you must 979 * transpose the matrix before using it. However, since the matrix is a 980 * rotation matrix, its transpose is also its inverse, conveniently, it is 981 * often the inverse of the rotation that is needed for rendering; it can 982 * therefore be used with OpenGL ES directly. 983 * <p> 984 * Also note that the returned matrices always have this form: 985 * <pre> 986 * / M[ 0] M[ 1] M[ 2] 0 \ 987 * | M[ 4] M[ 5] M[ 6] 0 | 988 * | M[ 8] M[ 9] M[10] 0 | 989 * \ 0 0 0 1 / 990 *</pre> 991 * <p><u>If the array length is 9:</u> 992 * <pre> 993 * / M[ 0] M[ 1] M[ 2] \ 994 * | M[ 3] M[ 4] M[ 5] | 995 * \ M[ 6] M[ 7] M[ 8] / 996 *</pre> 997 * 998 * <hr> 999 * <p>The inverse of each matrix can be computed easily by taking its 1000 * transpose. 1001 * 1002 * <p>The matrices returned by this function are meaningful only when the 1003 * device is not free-falling and it is not close to the magnetic north. 1004 * If the device is accelerating, or placed into a strong magnetic field, 1005 * the returned matrices may be inaccurate. 1006 * 1007 * @param R is an array of 9 floats holding the rotation matrix <b>R</b> 1008 * when this function returns. R can be null.<p> 1009 * @param I is an array of 9 floats holding the rotation matrix <b>I</b> 1010 * when this function returns. I can be null.<p> 1011 * @param gravity is an array of 3 floats containing the gravity vector 1012 * expressed in the device's coordinate. You can simply use the 1013 * {@link android.hardware.SensorEvent#values values} 1014 * returned by a {@link android.hardware.SensorEvent SensorEvent} of a 1015 * {@link android.hardware.Sensor Sensor} of type 1016 * {@link android.hardware.Sensor#TYPE_ACCELEROMETER TYPE_ACCELEROMETER}.<p> 1017 * @param geomagnetic is an array of 3 floats containing the geomagnetic 1018 * vector expressed in the device's coordinate. You can simply use the 1019 * {@link android.hardware.SensorEvent#values values} 1020 * returned by a {@link android.hardware.SensorEvent SensorEvent} of a 1021 * {@link android.hardware.Sensor Sensor} of type 1022 * {@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD TYPE_MAGNETIC_FIELD}. 1023 * @return 1024 * true on success<p> 1025 * false on failure (for instance, if the device is in free fall). 1026 * On failure the output matrices are not modified. 1027 */ 1028 1029 public static boolean getRotationMatrix(float[] R, float[] I, 1030 float[] gravity, float[] geomagnetic) { 1031 // TODO: move this to native code for efficiency 1032 float Ax = gravity[0]; 1033 float Ay = gravity[1]; 1034 float Az = gravity[2]; 1035 final float Ex = geomagnetic[0]; 1036 final float Ey = geomagnetic[1]; 1037 final float Ez = geomagnetic[2]; 1038 float Hx = Ey*Az - Ez*Ay; 1039 float Hy = Ez*Ax - Ex*Az; 1040 float Hz = Ex*Ay - Ey*Ax; 1041 final float normH = (float)Math.sqrt(Hx*Hx + Hy*Hy + Hz*Hz); 1042 if (normH < 0.1f) { 1043 // device is close to free fall (or in space?), or close to 1044 // magnetic north pole. Typical values are > 100. 1045 return false; 1046 } 1047 final float invH = 1.0f / normH; 1048 Hx *= invH; 1049 Hy *= invH; 1050 Hz *= invH; 1051 final float invA = 1.0f / (float)Math.sqrt(Ax*Ax + Ay*Ay + Az*Az); 1052 Ax *= invA; 1053 Ay *= invA; 1054 Az *= invA; 1055 final float Mx = Ay*Hz - Az*Hy; 1056 final float My = Az*Hx - Ax*Hz; 1057 final float Mz = Ax*Hy - Ay*Hx; 1058 if (R != null) { 1059 if (R.length == 9) { 1060 R[0] = Hx; R[1] = Hy; R[2] = Hz; 1061 R[3] = Mx; R[4] = My; R[5] = Mz; 1062 R[6] = Ax; R[7] = Ay; R[8] = Az; 1063 } else if (R.length == 16) { 1064 R[0] = Hx; R[1] = Hy; R[2] = Hz; R[3] = 0; 1065 R[4] = Mx; R[5] = My; R[6] = Mz; R[7] = 0; 1066 R[8] = Ax; R[9] = Ay; R[10] = Az; R[11] = 0; 1067 R[12] = 0; R[13] = 0; R[14] = 0; R[15] = 1; 1068 } 1069 } 1070 if (I != null) { 1071 // compute the inclination matrix by projecting the geomagnetic 1072 // vector onto the Z (gravity) and X (horizontal component 1073 // of geomagnetic vector) axes. 1074 final float invE = 1.0f / (float)Math.sqrt(Ex*Ex + Ey*Ey + Ez*Ez); 1075 final float c = (Ex*Mx + Ey*My + Ez*Mz) * invE; 1076 final float s = (Ex*Ax + Ey*Ay + Ez*Az) * invE; 1077 if (I.length == 9) { 1078 I[0] = 1; I[1] = 0; I[2] = 0; 1079 I[3] = 0; I[4] = c; I[5] = s; 1080 I[6] = 0; I[7] =-s; I[8] = c; 1081 } else if (I.length == 16) { 1082 I[0] = 1; I[1] = 0; I[2] = 0; 1083 I[4] = 0; I[5] = c; I[6] = s; 1084 I[8] = 0; I[9] =-s; I[10]= c; 1085 I[3] = I[7] = I[11] = I[12] = I[13] = I[14] = 0; 1086 I[15] = 1; 1087 } 1088 } 1089 return true; 1090 } 1091 1092 /** 1093 * Computes the geomagnetic inclination angle in radians from the 1094 * inclination matrix <b>I</b> returned by {@link #getRotationMatrix}. 1095 * @param I inclination matrix see {@link #getRotationMatrix}. 1096 * @return The geomagnetic inclination angle in radians. 1097 */ 1098 public static float getInclination(float[] I) { 1099 if (I.length == 9) { 1100 return (float)Math.atan2(I[5], I[4]); 1101 } else { 1102 return (float)Math.atan2(I[6], I[5]); 1103 } 1104 } 1105 1106 /** 1107 * Rotates the supplied rotation matrix so it is expressed in a 1108 * different coordinate system. This is typically used when an application 1109 * needs to compute the three orientation angles of the device (see 1110 * {@link #getOrientation}) in a different coordinate system. 1111 * 1112 * <p>When the rotation matrix is used for drawing (for instance with 1113 * OpenGL ES), it usually <b>doesn't need</b> to be transformed by this 1114 * function, unless the screen is physically rotated, such as when used 1115 * in landscape mode. 1116 * 1117 * <p><u>Examples:</u><p> 1118 * 1119 * <li>Using the camera (Y axis along the camera's axis) for an augmented 1120 * reality application where the rotation angles are needed :</li><p> 1121 * 1122 * <code>remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR);</code><p> 1123 * 1124 * <li>Using the device as a mechanical compass in landscape mode:</li><p> 1125 * 1126 * <code>remapCoordinateSystem(inR, AXIS_Y, AXIS_MINUS_X, outR);</code><p> 1127 * 1128 * Beware of the above example. This call is needed only if the device is 1129 * physically used in landscape mode to calculate the rotation angles (see 1130 * {@link #getOrientation}). 1131 * If the rotation matrix is also used for rendering, it may not need to 1132 * be transformed, for instance if your {@link android.app.Activity 1133 * Activity} is running in landscape mode. 1134 * 1135 * <p>Since the resulting coordinate system is orthonormal, only two axes 1136 * need to be specified. 1137 * 1138 * @param inR the rotation matrix to be transformed. Usually it is the 1139 * matrix returned by {@link #getRotationMatrix}. 1140 * @param X defines on which world axis and direction the X axis of the 1141 * device is mapped. 1142 * @param Y defines on which world axis and direction the Y axis of the 1143 * device is mapped. 1144 * @param outR the transformed rotation matrix. inR and outR can be the same 1145 * array, but it is not recommended for performance reason. 1146 * @return true on success. false if the input parameters are incorrect, for 1147 * instance if X and Y define the same axis. Or if inR and outR don't have 1148 * the same length. 1149 */ 1150 1151 public static boolean remapCoordinateSystem(float[] inR, int X, int Y, 1152 float[] outR) 1153 { 1154 if (inR == outR) { 1155 final float[] temp = mTempMatrix; 1156 synchronized(temp) { 1157 // we don't expect to have a lot of contention 1158 if (remapCoordinateSystemImpl(inR, X, Y, temp)) { 1159 final int size = outR.length; 1160 for (int i=0 ; i<size ; i++) 1161 outR[i] = temp[i]; 1162 return true; 1163 } 1164 } 1165 } 1166 return remapCoordinateSystemImpl(inR, X, Y, outR); 1167 } 1168 1169 private static boolean remapCoordinateSystemImpl(float[] inR, int X, int Y, 1170 float[] outR) 1171 { 1172 /* 1173 * X and Y define a rotation matrix 'r': 1174 * 1175 * (X==1)?((X&0x80)?-1:1):0 (X==2)?((X&0x80)?-1:1):0 (X==3)?((X&0x80)?-1:1):0 1176 * (Y==1)?((Y&0x80)?-1:1):0 (Y==2)?((Y&0x80)?-1:1):0 (Y==3)?((X&0x80)?-1:1):0 1177 * r[0] ^ r[1] 1178 * 1179 * where the 3rd line is the vector product of the first 2 lines 1180 * 1181 */ 1182 1183 final int length = outR.length; 1184 if (inR.length != length) 1185 return false; // invalid parameter 1186 if ((X & 0x7C)!=0 || (Y & 0x7C)!=0) 1187 return false; // invalid parameter 1188 if (((X & 0x3)==0) || ((Y & 0x3)==0)) 1189 return false; // no axis specified 1190 if ((X & 0x3) == (Y & 0x3)) 1191 return false; // same axis specified 1192 1193 // Z is "the other" axis, its sign is either +/- sign(X)*sign(Y) 1194 // this can be calculated by exclusive-or'ing X and Y; except for 1195 // the sign inversion (+/-) which is calculated below. 1196 int Z = X ^ Y; 1197 1198 // extract the axis (remove the sign), offset in the range 0 to 2. 1199 final int x = (X & 0x3)-1; 1200 final int y = (Y & 0x3)-1; 1201 final int z = (Z & 0x3)-1; 1202 1203 // compute the sign of Z (whether it needs to be inverted) 1204 final int axis_y = (z+1)%3; 1205 final int axis_z = (z+2)%3; 1206 if (((x^axis_y)|(y^axis_z)) != 0) 1207 Z ^= 0x80; 1208 1209 final boolean sx = (X>=0x80); 1210 final boolean sy = (Y>=0x80); 1211 final boolean sz = (Z>=0x80); 1212 1213 // Perform R * r, in avoiding actual muls and adds. 1214 final int rowLength = ((length==16)?4:3); 1215 for (int j=0 ; j<3 ; j++) { 1216 final int offset = j*rowLength; 1217 for (int i=0 ; i<3 ; i++) { 1218 if (x==i) outR[offset+i] = sx ? -inR[offset+0] : inR[offset+0]; 1219 if (y==i) outR[offset+i] = sy ? -inR[offset+1] : inR[offset+1]; 1220 if (z==i) outR[offset+i] = sz ? -inR[offset+2] : inR[offset+2]; 1221 } 1222 } 1223 if (length == 16) { 1224 outR[3] = outR[7] = outR[11] = outR[12] = outR[13] = outR[14] = 0; 1225 outR[15] = 1; 1226 } 1227 return true; 1228 } 1229 1230 /** 1231 * Computes the device's orientation based on the rotation matrix. 1232 * <p> When it returns, the array values is filled with the result: 1233 * <li>values[0]: <i>azimuth</i>, rotation around the Z axis.</li> 1234 * <li>values[1]: <i>pitch</i>, rotation around the X axis.</li> 1235 * <li>values[2]: <i>roll</i>, rotation around the Y axis.</li> 1236 * <p> 1237 * 1238 * @param R rotation matrix see {@link #getRotationMatrix}. 1239 * @param values an array of 3 floats to hold the result. 1240 * @return The array values passed as argument. 1241 */ 1242 public static float[] getOrientation(float[] R, float values[]) { 1243 /* 1244 * 4x4 (length=16) case: 1245 * / R[ 0] R[ 1] R[ 2] 0 \ 1246 * | R[ 4] R[ 5] R[ 6] 0 | 1247 * | R[ 8] R[ 9] R[10] 0 | 1248 * \ 0 0 0 1 / 1249 * 1250 * 3x3 (length=9) case: 1251 * / R[ 0] R[ 1] R[ 2] \ 1252 * | R[ 3] R[ 4] R[ 5] | 1253 * \ R[ 6] R[ 7] R[ 8] / 1254 * 1255 */ 1256 if (R.length == 9) { 1257 values[0] = (float)Math.atan2(R[1], R[4]); 1258 values[1] = (float)Math.asin(-R[7]); 1259 values[2] = (float)Math.atan2(-R[6], R[8]); 1260 } else { 1261 values[0] = (float)Math.atan2(R[1], R[5]); 1262 values[1] = (float)Math.asin(-R[9]); 1263 values[2] = (float)Math.atan2(-R[8], R[10]); 1264 } 1265 return values; 1266 } 1267 1268 1269 /** 1270 * {@hide} 1271 */ 1272 public void onRotationChanged(int rotation) { 1273 synchronized(sListeners) { 1274 sRotation = rotation; 1275 } 1276 } 1277 1278 static int getRotation() { 1279 synchronized(sListeners) { 1280 return sRotation; 1281 } 1282 } 1283 1284 private class LegacyListener implements SensorEventListener { 1285 private float mValues[] = new float[6]; 1286 @SuppressWarnings("deprecation") 1287 private SensorListener mTarget; 1288 private int mSensors; 1289 private final LmsFilter mYawfilter = new LmsFilter(); 1290 1291 @SuppressWarnings("deprecation") 1292 LegacyListener(SensorListener target) { 1293 mTarget = target; 1294 mSensors = 0; 1295 } 1296 1297 void registerSensor(int legacyType) { 1298 mSensors |= legacyType; 1299 } 1300 1301 boolean unregisterSensor(int legacyType) { 1302 mSensors &= ~legacyType; 1303 int mask = SENSOR_ORIENTATION|SENSOR_ORIENTATION_RAW; 1304 if (((legacyType&mask)!=0) && ((mSensors&mask)!=0)) { 1305 return false; 1306 } 1307 return true; 1308 } 1309 1310 @SuppressWarnings("deprecation") 1311 public void onAccuracyChanged(Sensor sensor, int accuracy) { 1312 try { 1313 mTarget.onAccuracyChanged(sensor.getLegacyType(), accuracy); 1314 } catch (AbstractMethodError e) { 1315 // old app that doesn't implement this method 1316 // just ignore it. 1317 } 1318 } 1319 1320 @SuppressWarnings("deprecation") 1321 public void onSensorChanged(SensorEvent event) { 1322 final float v[] = mValues; 1323 v[0] = event.values[0]; 1324 v[1] = event.values[1]; 1325 v[2] = event.values[2]; 1326 int legacyType = event.sensor.getLegacyType(); 1327 mapSensorDataToWindow(legacyType, v, SensorManager.getRotation()); 1328 if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) { 1329 if ((mSensors & SENSOR_ORIENTATION_RAW)!=0) { 1330 mTarget.onSensorChanged(SENSOR_ORIENTATION_RAW, v); 1331 } 1332 if ((mSensors & SENSOR_ORIENTATION)!=0) { 1333 v[0] = mYawfilter.filter(event.timestamp, v[0]); 1334 mTarget.onSensorChanged(SENSOR_ORIENTATION, v); 1335 } 1336 } else { 1337 mTarget.onSensorChanged(legacyType, v); 1338 } 1339 } 1340 1341 /* 1342 * Helper function to convert the specified sensor's data to the windows's 1343 * coordinate space from the device's coordinate space. 1344 * 1345 * output: 3,4,5: values in the old API format 1346 * 0,1,2: transformed values in the old API format 1347 * 1348 */ 1349 private void mapSensorDataToWindow(int sensor, 1350 float[] values, int orientation) { 1351 float x = values[0]; 1352 float y = values[1]; 1353 float z = values[2]; 1354 1355 switch (sensor) { 1356 case SensorManager.SENSOR_ORIENTATION: 1357 case SensorManager.SENSOR_ORIENTATION_RAW: 1358 z = -z; 1359 break; 1360 case SensorManager.SENSOR_ACCELEROMETER: 1361 x = -x; 1362 y = -y; 1363 z = -z; 1364 break; 1365 case SensorManager.SENSOR_MAGNETIC_FIELD: 1366 x = -x; 1367 y = -y; 1368 break; 1369 } 1370 values[0] = x; 1371 values[1] = y; 1372 values[2] = z; 1373 values[3] = x; 1374 values[4] = y; 1375 values[5] = z; 1376 // TODO: add support for 180 and 270 orientations 1377 if (orientation == Surface.ROTATION_90) { 1378 switch (sensor) { 1379 case SENSOR_ACCELEROMETER: 1380 case SENSOR_MAGNETIC_FIELD: 1381 values[0] =-y; 1382 values[1] = x; 1383 values[2] = z; 1384 break; 1385 case SENSOR_ORIENTATION: 1386 case SENSOR_ORIENTATION_RAW: 1387 values[0] = x + ((x < 270) ? 90 : -270); 1388 values[1] = z; 1389 values[2] = y; 1390 break; 1391 } 1392 } 1393 } 1394 } 1395 1396 class LmsFilter { 1397 private static final int SENSORS_RATE_MS = 20; 1398 private static final int COUNT = 12; 1399 private static final float PREDICTION_RATIO = 1.0f/3.0f; 1400 private static final float PREDICTION_TIME = (SENSORS_RATE_MS*COUNT/1000.0f)*PREDICTION_RATIO; 1401 private float mV[] = new float[COUNT*2]; 1402 private float mT[] = new float[COUNT*2]; 1403 private int mIndex; 1404 1405 public LmsFilter() { 1406 mIndex = COUNT; 1407 } 1408 1409 public float filter(long time, float in) { 1410 float v = in; 1411 final float ns = 1.0f / 1000000000.0f; 1412 final float t = time*ns; 1413 float v1 = mV[mIndex]; 1414 if ((v-v1) > 180) { 1415 v -= 360; 1416 } else if ((v1-v) > 180) { 1417 v += 360; 1418 } 1419 /* Manage the circular buffer, we write the data twice spaced 1420 * by COUNT values, so that we don't have to copy the array 1421 * when it's full 1422 */ 1423 mIndex++; 1424 if (mIndex >= COUNT*2) 1425 mIndex = COUNT; 1426 mV[mIndex] = v; 1427 mT[mIndex] = t; 1428 mV[mIndex-COUNT] = v; 1429 mT[mIndex-COUNT] = t; 1430 1431 float A, B, C, D, E; 1432 float a, b; 1433 int i; 1434 1435 A = B = C = D = E = 0; 1436 for (i=0 ; i<COUNT-1 ; i++) { 1437 final int j = mIndex - 1 - i; 1438 final float Z = mV[j]; 1439 final float T = 0.5f*(mT[j] + mT[j+1]) - t; 1440 float dT = mT[j] - mT[j+1]; 1441 dT *= dT; 1442 A += Z*dT; 1443 B += T*(T*dT); 1444 C += (T*dT); 1445 D += Z*(T*dT); 1446 E += dT; 1447 } 1448 b = (A*B + C*D) / (E*B + C*C); 1449 a = (E*b - A) / C; 1450 float f = b + PREDICTION_TIME*a; 1451 1452 // Normalize 1453 f *= (1.0f / 360.0f); 1454 if (((f>=0)?f:-f) >= 0.5f) 1455 f = f - (float)Math.ceil(f + 0.5f) + 1.0f; 1456 if (f < 0) 1457 f += 1.0f; 1458 f *= 360.0f; 1459 return f; 1460 } 1461 } 1462 1463 1464 private static native void nativeClassInit(); 1465 1466 private static native int sensors_module_init(); 1467 private static native int sensors_module_get_next_sensor(Sensor sensor, int next); 1468 1469 // Used within this module from outside SensorManager, don't make private 1470 static native int sensors_data_init(); 1471 static native int sensors_data_uninit(); 1472 static native int sensors_data_open(FileDescriptor fd); 1473 static native int sensors_data_close(); 1474 static native int sensors_data_poll(float[] values, int[] status, long[] timestamp); 1475} 1476