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