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