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