SensorManager.java revision 43c87e44fc0d7d7b37e039752c0dec093e227381
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.hardware; 18 19import android.os.Looper; 20import android.os.Process; 21import android.os.RemoteException; 22import android.os.Handler; 23import android.os.Message; 24import android.os.ServiceManager; 25import android.util.Log; 26import android.util.SparseArray; 27import android.view.IRotationWatcher; 28import android.view.IWindowManager; 29import android.view.Surface; 30 31import java.util.ArrayList; 32import java.util.Collections; 33import java.util.HashMap; 34import java.util.List; 35 36/** 37 * <p> 38 * SensorManager lets you access the device's {@link android.hardware.Sensor 39 * sensors}. Get an instance of this class by calling 40 * {@link android.content.Context#getSystemService(java.lang.String) 41 * Context.getSystemService()} with the argument 42 * {@link android.content.Context#SENSOR_SERVICE}. 43 * </p> 44 * <p> 45 * Always make sure to disable sensors you don't need, especially when your 46 * activity is paused. Failing to do so can drain the battery in just a few 47 * hours. Note that the system will <i>not</i> disable sensors automatically when 48 * the screen turns off. 49 * </p> 50 * 51 * <pre class="prettyprint"> 52 * public class SensorActivity extends Activity, implements SensorEventListener { 53 * private final SensorManager mSensorManager; 54 * private final Sensor mAccelerometer; 55 * 56 * public SensorActivity() { 57 * mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE); 58 * mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); 59 * } 60 * 61 * protected void onResume() { 62 * super.onResume(); 63 * mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL); 64 * } 65 * 66 * protected void onPause() { 67 * super.onPause(); 68 * mSensorManager.unregisterListener(this); 69 * } 70 * 71 * public void onAccuracyChanged(Sensor sensor, int accuracy) { 72 * } 73 * 74 * public void onSensorChanged(SensorEvent event) { 75 * } 76 * } 77 * </pre> 78 * 79 * @see SensorEventListener 80 * @see SensorEvent 81 * @see Sensor 82 * 83 */ 84public class SensorManager 85{ 86 private static final String TAG = "SensorManager"; 87 private static final float[] mTempMatrix = new float[16]; 88 89 /* NOTE: sensor IDs must be a power of 2 */ 90 91 /** 92 * A constant describing an orientation sensor. See 93 * {@link android.hardware.SensorListener SensorListener} for more details. 94 * 95 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 96 */ 97 @Deprecated 98 public static final int SENSOR_ORIENTATION = 1 << 0; 99 100 /** 101 * A constant describing an accelerometer. See 102 * {@link android.hardware.SensorListener SensorListener} for more details. 103 * 104 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 105 */ 106 @Deprecated 107 public static final int SENSOR_ACCELEROMETER = 1 << 1; 108 109 /** 110 * A constant describing a temperature sensor See 111 * {@link android.hardware.SensorListener SensorListener} for more details. 112 * 113 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 114 */ 115 @Deprecated 116 public static final int SENSOR_TEMPERATURE = 1 << 2; 117 118 /** 119 * A constant describing a magnetic sensor See 120 * {@link android.hardware.SensorListener SensorListener} for more details. 121 * 122 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 123 */ 124 @Deprecated 125 public static final int SENSOR_MAGNETIC_FIELD = 1 << 3; 126 127 /** 128 * A constant describing an ambient light sensor See 129 * {@link android.hardware.SensorListener SensorListener} for more details. 130 * 131 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 132 */ 133 @Deprecated 134 public static final int SENSOR_LIGHT = 1 << 4; 135 136 /** 137 * A constant describing a proximity sensor See 138 * {@link android.hardware.SensorListener SensorListener} for more details. 139 * 140 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 141 */ 142 @Deprecated 143 public static final int SENSOR_PROXIMITY = 1 << 5; 144 145 /** 146 * A constant describing a Tricorder See 147 * {@link android.hardware.SensorListener SensorListener} for more details. 148 * 149 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 150 */ 151 @Deprecated 152 public static final int SENSOR_TRICORDER = 1 << 6; 153 154 /** 155 * A constant describing an orientation sensor. See 156 * {@link android.hardware.SensorListener SensorListener} for more details. 157 * 158 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 159 */ 160 @Deprecated 161 public static final int SENSOR_ORIENTATION_RAW = 1 << 7; 162 163 /** 164 * A constant that includes all sensors 165 * 166 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 167 */ 168 @Deprecated 169 public static final int SENSOR_ALL = 0x7F; 170 171 /** 172 * Smallest sensor ID 173 * 174 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 175 */ 176 @Deprecated 177 public static final int SENSOR_MIN = SENSOR_ORIENTATION; 178 179 /** 180 * Largest sensor ID 181 * 182 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 183 */ 184 @Deprecated 185 public static final int SENSOR_MAX = ((SENSOR_ALL + 1)>>1); 186 187 188 /** 189 * Index of the X value in the array returned by 190 * {@link android.hardware.SensorListener#onSensorChanged} 191 * 192 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 193 */ 194 @Deprecated 195 public static final int DATA_X = 0; 196 197 /** 198 * Index of the Y value in the array returned by 199 * {@link android.hardware.SensorListener#onSensorChanged} 200 * 201 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 202 */ 203 @Deprecated 204 public static final int DATA_Y = 1; 205 206 /** 207 * Index of the Z value in the array returned by 208 * {@link android.hardware.SensorListener#onSensorChanged} 209 * 210 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 211 */ 212 @Deprecated 213 public static final int DATA_Z = 2; 214 215 /** 216 * Offset to the untransformed values in the array returned by 217 * {@link android.hardware.SensorListener#onSensorChanged} 218 * 219 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 220 */ 221 @Deprecated 222 public static final int RAW_DATA_INDEX = 3; 223 224 /** 225 * Index of the untransformed X value in the array returned by 226 * {@link android.hardware.SensorListener#onSensorChanged} 227 * 228 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 229 */ 230 @Deprecated 231 public static final int RAW_DATA_X = 3; 232 233 /** 234 * Index of the untransformed Y value in the array returned by 235 * {@link android.hardware.SensorListener#onSensorChanged} 236 * 237 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 238 */ 239 @Deprecated 240 public static final int RAW_DATA_Y = 4; 241 242 /** 243 * Index of the untransformed Z value in the array returned by 244 * {@link android.hardware.SensorListener#onSensorChanged} 245 * 246 * @deprecated use {@link android.hardware.Sensor Sensor} instead. 247 */ 248 @Deprecated 249 public static final int RAW_DATA_Z = 5; 250 251 /** Standard gravity (g) on Earth. This value is equivalent to 1G */ 252 public static final float STANDARD_GRAVITY = 9.80665f; 253 254 /** Sun's gravity in SI units (m/s^2) */ 255 public static final float GRAVITY_SUN = 275.0f; 256 /** Mercury's gravity in SI units (m/s^2) */ 257 public static final float GRAVITY_MERCURY = 3.70f; 258 /** Venus' gravity in SI units (m/s^2) */ 259 public static final float GRAVITY_VENUS = 8.87f; 260 /** Earth's gravity in SI units (m/s^2) */ 261 public static final float GRAVITY_EARTH = 9.80665f; 262 /** The Moon's gravity in SI units (m/s^2) */ 263 public static final float GRAVITY_MOON = 1.6f; 264 /** Mars' gravity in SI units (m/s^2) */ 265 public static final float GRAVITY_MARS = 3.71f; 266 /** Jupiter's gravity in SI units (m/s^2) */ 267 public static final float GRAVITY_JUPITER = 23.12f; 268 /** Saturn's gravity in SI units (m/s^2) */ 269 public static final float GRAVITY_SATURN = 8.96f; 270 /** Uranus' gravity in SI units (m/s^2) */ 271 public static final float GRAVITY_URANUS = 8.69f; 272 /** Neptune's gravity in SI units (m/s^2) */ 273 public static final float GRAVITY_NEPTUNE = 11.0f; 274 /** Pluto's gravity in SI units (m/s^2) */ 275 public static final float GRAVITY_PLUTO = 0.6f; 276 /** Gravity (estimate) on the first Death Star in Empire units (m/s^2) */ 277 public static final float GRAVITY_DEATH_STAR_I = 0.000000353036145f; 278 /** Gravity on the island */ 279 public static final float GRAVITY_THE_ISLAND = 4.815162342f; 280 281 282 /** Maximum magnetic field on Earth's surface */ 283 public static final float MAGNETIC_FIELD_EARTH_MAX = 60.0f; 284 /** Minimum magnetic field on Earth's surface */ 285 public static final float MAGNETIC_FIELD_EARTH_MIN = 30.0f; 286 287 288 /** Standard atmosphere, or average sea-level pressure in hPa (millibar) */ 289 public static final float PRESSURE_STANDARD_ATMOSPHERE = 1013.25f; 290 291 292 /** Maximum luminance of sunlight in lux */ 293 public static final float LIGHT_SUNLIGHT_MAX = 120000.0f; 294 /** luminance of sunlight in lux */ 295 public static final float LIGHT_SUNLIGHT = 110000.0f; 296 /** luminance in shade in lux */ 297 public static final float LIGHT_SHADE = 20000.0f; 298 /** luminance under an overcast sky in lux */ 299 public static final float LIGHT_OVERCAST = 10000.0f; 300 /** luminance at sunrise in lux */ 301 public static final float LIGHT_SUNRISE = 400.0f; 302 /** luminance under a cloudy sky in lux */ 303 public static final float LIGHT_CLOUDY = 100.0f; 304 /** luminance at night with full moon in lux */ 305 public static final float LIGHT_FULLMOON = 0.25f; 306 /** luminance at night with no moon in lux*/ 307 public static final float LIGHT_NO_MOON = 0.001f; 308 309 310 /** get sensor data as fast as possible */ 311 public static final int SENSOR_DELAY_FASTEST = 0; 312 /** rate suitable for games */ 313 public static final int SENSOR_DELAY_GAME = 1; 314 /** rate suitable for the user interface */ 315 public static final int SENSOR_DELAY_UI = 2; 316 /** rate (default) suitable for screen orientation changes */ 317 public static final int SENSOR_DELAY_NORMAL = 3; 318 319 320 /** 321 * The values returned by this sensor cannot be trusted, calibration is 322 * needed or the environment doesn't allow readings 323 */ 324 public static final int SENSOR_STATUS_UNRELIABLE = 0; 325 326 /** 327 * This sensor is reporting data with low accuracy, calibration with the 328 * environment is needed 329 */ 330 public static final int SENSOR_STATUS_ACCURACY_LOW = 1; 331 332 /** 333 * This sensor is reporting data with an average level of accuracy, 334 * calibration with the environment may improve the readings 335 */ 336 public static final int SENSOR_STATUS_ACCURACY_MEDIUM = 2; 337 338 /** This sensor is reporting data with maximum accuracy */ 339 public static final int SENSOR_STATUS_ACCURACY_HIGH = 3; 340 341 /** see {@link #remapCoordinateSystem} */ 342 public static final int AXIS_X = 1; 343 /** see {@link #remapCoordinateSystem} */ 344 public static final int AXIS_Y = 2; 345 /** see {@link #remapCoordinateSystem} */ 346 public static final int AXIS_Z = 3; 347 /** see {@link #remapCoordinateSystem} */ 348 public static final int AXIS_MINUS_X = AXIS_X | 0x80; 349 /** see {@link #remapCoordinateSystem} */ 350 public static final int AXIS_MINUS_Y = AXIS_Y | 0x80; 351 /** see {@link #remapCoordinateSystem} */ 352 public static final int AXIS_MINUS_Z = AXIS_Z | 0x80; 353 354 /*-----------------------------------------------------------------------*/ 355 356 Looper mMainLooper; 357 @SuppressWarnings("deprecation") 358 private HashMap<SensorListener, LegacyListener> mLegacyListenersMap = 359 new HashMap<SensorListener, LegacyListener>(); 360 361 /*-----------------------------------------------------------------------*/ 362 363 private static final int SENSOR_DISABLE = -1; 364 private static boolean sSensorModuleInitialized = false; 365 private static ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>(); 366 private static SparseArray<List<Sensor>> sSensorListByType = new SparseArray<List<Sensor>>(); 367 private static IWindowManager sWindowManager; 368 private static int sRotation = Surface.ROTATION_0; 369 /* The thread and the sensor list are global to the process 370 * but the actual thread is spawned on demand */ 371 private static SensorThread sSensorThread; 372 private static int sQueue; 373 374 // Used within this module from outside SensorManager, don't make private 375 static SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>(); 376 static final ArrayList<ListenerDelegate> sListeners = 377 new ArrayList<ListenerDelegate>(); 378 379 /*-----------------------------------------------------------------------*/ 380 381 static private class SensorThread { 382 383 Thread mThread; 384 boolean mSensorsReady; 385 386 SensorThread() { 387 } 388 389 @Override 390 protected void finalize() { 391 } 392 393 // must be called with sListeners lock 394 boolean startLocked() { 395 try { 396 if (mThread == null) { 397 mSensorsReady = false; 398 SensorThreadRunnable runnable = new SensorThreadRunnable(); 399 Thread thread = new Thread(runnable, SensorThread.class.getName()); 400 thread.start(); 401 synchronized (runnable) { 402 while (mSensorsReady == false) { 403 runnable.wait(); 404 } 405 } 406 mThread = thread; 407 } 408 } catch (InterruptedException e) { 409 } 410 return mThread == null ? false : true; 411 } 412 413 private class SensorThreadRunnable implements Runnable { 414 SensorThreadRunnable() { 415 } 416 417 private boolean open() { 418 // NOTE: this cannot synchronize on sListeners, since 419 // it's held in the main thread at least until we 420 // return from here. 421 sQueue = sensors_create_queue(); 422 return true; 423 } 424 425 public void run() { 426 //Log.d(TAG, "entering main sensor thread"); 427 final float[] values = new float[3]; 428 final int[] status = new int[1]; 429 final long timestamp[] = new long[1]; 430 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); 431 432 if (!open()) { 433 return; 434 } 435 436 synchronized (this) { 437 // we've open the driver, we're ready to open the sensors 438 mSensorsReady = true; 439 this.notify(); 440 } 441 442 while (true) { 443 // wait for an event 444 final int sensor = sensors_data_poll(sQueue, values, status, timestamp); 445 446 int accuracy = status[0]; 447 synchronized (sListeners) { 448 if (sensor == -1 || sListeners.isEmpty()) { 449 if (sensor == -1) { 450 // we lost the connection to the event stream. this happens 451 // when the last listener is removed. 452 Log.d(TAG, "_sensors_data_poll() failed, we bail out."); 453 } 454 455 // we have no more listeners or polling failed, terminate the thread 456 sensors_destroy_queue(sQueue); 457 sQueue = 0; 458 mThread = null; 459 break; 460 } 461 final Sensor sensorObject = sHandleToSensor.get(sensor); 462 if (sensorObject != null) { 463 // report the sensor event to all listeners that 464 // care about it. 465 final int size = sListeners.size(); 466 for (int i=0 ; i<size ; i++) { 467 ListenerDelegate listener = sListeners.get(i); 468 if (listener.hasSensor(sensorObject)) { 469 // this is asynchronous (okay to call 470 // with sListeners lock held). 471 listener.onSensorChangedLocked(sensorObject, 472 values, timestamp, accuracy); 473 } 474 } 475 } 476 } 477 } 478 //Log.d(TAG, "exiting main sensor thread"); 479 } 480 } 481 } 482 483 /*-----------------------------------------------------------------------*/ 484 485 private class ListenerDelegate { 486 final SensorEventListener mSensorEventListener; 487 private final ArrayList<Sensor> mSensorList = new ArrayList<Sensor>(); 488 private final Handler mHandler; 489 private SensorEvent mValuesPool; 490 public int mSensors; 491 492 ListenerDelegate(SensorEventListener listener, Sensor sensor, Handler handler) { 493 mSensorEventListener = listener; 494 Looper looper = (handler != null) ? handler.getLooper() : mMainLooper; 495 // currently we create one Handler instance per listener, but we could 496 // have one per looper (we'd need to pass the ListenerDelegate 497 // instance to handleMessage and keep track of them separately). 498 mHandler = new Handler(looper) { 499 @Override 500 public void handleMessage(Message msg) { 501 SensorEvent t = (SensorEvent)msg.obj; 502 if (t.accuracy >= 0) { 503 mSensorEventListener.onAccuracyChanged(t.sensor, t.accuracy); 504 } 505 mSensorEventListener.onSensorChanged(t); 506 returnToPool(t); 507 } 508 }; 509 addSensor(sensor); 510 } 511 512 protected SensorEvent createSensorEvent() { 513 // maximal size for all legacy events is 3 514 return new SensorEvent(3); 515 } 516 517 protected SensorEvent getFromPool() { 518 SensorEvent t = null; 519 synchronized (this) { 520 // remove the array from the pool 521 t = mValuesPool; 522 mValuesPool = null; 523 } 524 if (t == null) { 525 // the pool was empty, we need a new one 526 t = createSensorEvent(); 527 } 528 return t; 529 } 530 531 protected void returnToPool(SensorEvent t) { 532 synchronized (this) { 533 // put back the array into the pool 534 if (mValuesPool == null) { 535 mValuesPool = t; 536 } 537 } 538 } 539 540 Object getListener() { 541 return mSensorEventListener; 542 } 543 544 int addSensor(Sensor sensor) { 545 mSensors |= 1<<sensor.getHandle(); 546 mSensorList.add(sensor); 547 return mSensors; 548 } 549 int removeSensor(Sensor sensor) { 550 mSensors &= ~(1<<sensor.getHandle()); 551 mSensorList.remove(sensor); 552 return mSensors; 553 } 554 boolean hasSensor(Sensor sensor) { 555 return ((mSensors & (1<<sensor.getHandle())) != 0); 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 /** 975 * Registers a {@link android.hardware.SensorEventListener 976 * SensorEventListener} for the given sensor. 977 * 978 * @param listener 979 * A {@link android.hardware.SensorEventListener SensorEventListener} 980 * object. 981 * 982 * @param sensor 983 * The {@link android.hardware.Sensor Sensor} to register to. 984 * 985 * @param rate 986 * The rate {@link android.hardware.SensorEvent sensor events} are 987 * delivered at. This is only a hint to the system. Events may be 988 * received faster or slower than the specified rate. Usually events 989 * are received faster. The value must be one of 990 * {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI}, 991 * {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}. 992 * or, the desired delay between events in microsecond. 993 * 994 * @param handler 995 * The {@link android.os.Handler Handler} the 996 * {@link android.hardware.SensorEvent sensor events} will be 997 * delivered to. 998 * 999 * @return true if the sensor is supported and successfully enabled. 1000 * 1001 * @see #registerListener(SensorEventListener, Sensor, int) 1002 * @see #unregisterListener(SensorEventListener) 1003 * @see #unregisterListener(SensorEventListener, Sensor) 1004 * 1005 */ 1006 public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate, 1007 Handler handler) { 1008 if (listener == null || sensor == null) { 1009 return false; 1010 } 1011 boolean result; 1012 int delay = -1; 1013 switch (rate) { 1014 case SENSOR_DELAY_FASTEST: 1015 delay = 0; 1016 break; 1017 case SENSOR_DELAY_GAME: 1018 delay = 20000; 1019 break; 1020 case SENSOR_DELAY_UI: 1021 delay = 60000; 1022 break; 1023 case SENSOR_DELAY_NORMAL: 1024 delay = 200000; 1025 break; 1026 default: 1027 delay = rate; 1028 break; 1029 } 1030 1031 synchronized (sListeners) { 1032 ListenerDelegate l = null; 1033 for (ListenerDelegate i : sListeners) { 1034 if (i.getListener() == listener) { 1035 l = i; 1036 break; 1037 } 1038 } 1039 1040 String name = sensor.getName(); 1041 int handle = sensor.getHandle(); 1042 if (l == null) { 1043 result = false; 1044 l = new ListenerDelegate(listener, sensor, handler); 1045 sListeners.add(l); 1046 if (!sListeners.isEmpty()) { 1047 result = sSensorThread.startLocked(); 1048 if (result) { 1049 result = sensors_enable_sensor(sQueue, name, handle, delay); 1050 if (!result) { 1051 // there was an error, remove the listeners 1052 sListeners.remove(l); 1053 } 1054 } 1055 } 1056 } else { 1057 result = sensors_enable_sensor(sQueue, name, handle, delay); 1058 if (result) { 1059 l.addSensor(sensor); 1060 } 1061 } 1062 } 1063 return result; 1064 } 1065 1066 private void unregisterListener(Object listener, Sensor sensor) { 1067 if (listener == null || sensor == null) { 1068 return; 1069 } 1070 synchronized (sListeners) { 1071 final int size = sListeners.size(); 1072 for (int i=0 ; i<size ; i++) { 1073 ListenerDelegate l = sListeners.get(i); 1074 if (l.getListener() == listener) { 1075 // disable these sensors 1076 String name = sensor.getName(); 1077 int handle = sensor.getHandle(); 1078 sensors_enable_sensor(sQueue, name, handle, SENSOR_DISABLE); 1079 // if we have no more sensors enabled on this listener, 1080 // take it off the list. 1081 if (l.removeSensor(sensor) == 0) { 1082 sListeners.remove(i); 1083 } 1084 break; 1085 } 1086 } 1087 } 1088 } 1089 1090 private void unregisterListener(Object listener) { 1091 if (listener == null) { 1092 return; 1093 } 1094 synchronized (sListeners) { 1095 final int size = sListeners.size(); 1096 for (int i=0 ; i<size ; i++) { 1097 ListenerDelegate l = sListeners.get(i); 1098 if (l.getListener() == listener) { 1099 // disable all sensors for this listener 1100 for (Sensor sensor : l.getSensors()) { 1101 String name = sensor.getName(); 1102 int handle = sensor.getHandle(); 1103 sensors_enable_sensor(sQueue, name, handle, SENSOR_DISABLE); 1104 } 1105 sListeners.remove(i); 1106 break; 1107 } 1108 } 1109 } 1110 } 1111 1112 /** 1113 * <p> 1114 * Computes the inclination matrix <b>I</b> as well as the rotation matrix 1115 * <b>R</b> transforming a vector from the device coordinate system to the 1116 * world's coordinate system which is defined as a direct orthonormal basis, 1117 * where: 1118 * </p> 1119 * 1120 * <ul> 1121 * <li>X is defined as the vector product <b>Y.Z</b> (It is tangential to 1122 * the ground at the device's current location and roughly points East).</li> 1123 * <li>Y is tangential to the ground at the device's current location and 1124 * points towards the magnetic North Pole.</li> 1125 * <li>Z points towards the sky and is perpendicular to the ground.</li> 1126 * </ul> 1127 * 1128 * <p> 1129 * <center><img src="../../../images/axis_globe.png" 1130 * alt="Sensors coordinate-system diagram." border="0" /></center> 1131 * </p> 1132 * 1133 * <p> 1134 * <hr> 1135 * <p> 1136 * By definition: 1137 * <p> 1138 * [0 0 g] = <b>R</b> * <b>gravity</b> (g = magnitude of gravity) 1139 * <p> 1140 * [0 m 0] = <b>I</b> * <b>R</b> * <b>geomagnetic</b> (m = magnitude of 1141 * geomagnetic field) 1142 * <p> 1143 * <b>R</b> is the identity matrix when the device is aligned with the 1144 * world's coordinate system, that is, when the device's X axis points 1145 * toward East, the Y axis points to the North Pole and the device is facing 1146 * the sky. 1147 * 1148 * <p> 1149 * <b>I</b> is a rotation matrix transforming the geomagnetic vector into 1150 * the same coordinate space as gravity (the world's coordinate space). 1151 * <b>I</b> is a simple rotation around the X axis. The inclination angle in 1152 * radians can be computed with {@link #getInclination}. 1153 * <hr> 1154 * 1155 * <p> 1156 * Each matrix is returned either as a 3x3 or 4x4 row-major matrix depending 1157 * on the length of the passed array: 1158 * <p> 1159 * <u>If the array length is 16:</u> 1160 * 1161 * <pre> 1162 * / M[ 0] M[ 1] M[ 2] M[ 3] \ 1163 * | M[ 4] M[ 5] M[ 6] M[ 7] | 1164 * | M[ 8] M[ 9] M[10] M[11] | 1165 * \ M[12] M[13] M[14] M[15] / 1166 *</pre> 1167 * 1168 * This matrix is ready to be used by OpenGL ES's 1169 * {@link javax.microedition.khronos.opengles.GL10#glLoadMatrixf(float[], int) 1170 * glLoadMatrixf(float[], int)}. 1171 * <p> 1172 * Note that because OpenGL matrices are column-major matrices you must 1173 * transpose the matrix before using it. However, since the matrix is a 1174 * rotation matrix, its transpose is also its inverse, conveniently, it is 1175 * often the inverse of the rotation that is needed for rendering; it can 1176 * therefore be used with OpenGL ES directly. 1177 * <p> 1178 * Also note that the returned matrices always have this form: 1179 * 1180 * <pre> 1181 * / M[ 0] M[ 1] M[ 2] 0 \ 1182 * | M[ 4] M[ 5] M[ 6] 0 | 1183 * | M[ 8] M[ 9] M[10] 0 | 1184 * \ 0 0 0 1 / 1185 *</pre> 1186 * 1187 * <p> 1188 * <u>If the array length is 9:</u> 1189 * 1190 * <pre> 1191 * / M[ 0] M[ 1] M[ 2] \ 1192 * | M[ 3] M[ 4] M[ 5] | 1193 * \ M[ 6] M[ 7] M[ 8] / 1194 *</pre> 1195 * 1196 * <hr> 1197 * <p> 1198 * The inverse of each matrix can be computed easily by taking its 1199 * transpose. 1200 * 1201 * <p> 1202 * The matrices returned by this function are meaningful only when the 1203 * device is not free-falling and it is not close to the magnetic north. If 1204 * the device is accelerating, or placed into a strong magnetic field, the 1205 * returned matrices may be inaccurate. 1206 * 1207 * @param R 1208 * is an array of 9 floats holding the rotation matrix <b>R</b> when 1209 * this function returns. R can be null. 1210 * <p> 1211 * 1212 * @param I 1213 * is an array of 9 floats holding the rotation matrix <b>I</b> when 1214 * this function returns. I can be null. 1215 * <p> 1216 * 1217 * @param gravity 1218 * is an array of 3 floats containing the gravity vector expressed in 1219 * the device's coordinate. You can simply use the 1220 * {@link android.hardware.SensorEvent#values values} returned by a 1221 * {@link android.hardware.SensorEvent SensorEvent} of a 1222 * {@link android.hardware.Sensor Sensor} of type 1223 * {@link android.hardware.Sensor#TYPE_ACCELEROMETER 1224 * TYPE_ACCELEROMETER}. 1225 * <p> 1226 * 1227 * @param geomagnetic 1228 * is an array of 3 floats containing the geomagnetic vector 1229 * expressed in the device's coordinate. You can simply use the 1230 * {@link android.hardware.SensorEvent#values values} returned by a 1231 * {@link android.hardware.SensorEvent SensorEvent} of a 1232 * {@link android.hardware.Sensor Sensor} of type 1233 * {@link android.hardware.Sensor#TYPE_MAGNETIC_FIELD 1234 * TYPE_MAGNETIC_FIELD}. 1235 * 1236 * @return <code>true</code> on success, <code>false</code> on failure (for 1237 * instance, if the device is in free fall). On failure the output 1238 * matrices are not modified. 1239 * 1240 * @see #getInclination(float[]) 1241 * @see #getOrientation(float[], float[]) 1242 * @see #remapCoordinateSystem(float[], int, int, float[]) 1243 */ 1244 1245 public static boolean getRotationMatrix(float[] R, float[] I, 1246 float[] gravity, float[] geomagnetic) { 1247 // TODO: move this to native code for efficiency 1248 float Ax = gravity[0]; 1249 float Ay = gravity[1]; 1250 float Az = gravity[2]; 1251 final float Ex = geomagnetic[0]; 1252 final float Ey = geomagnetic[1]; 1253 final float Ez = geomagnetic[2]; 1254 float Hx = Ey*Az - Ez*Ay; 1255 float Hy = Ez*Ax - Ex*Az; 1256 float Hz = Ex*Ay - Ey*Ax; 1257 final float normH = (float)Math.sqrt(Hx*Hx + Hy*Hy + Hz*Hz); 1258 if (normH < 0.1f) { 1259 // device is close to free fall (or in space?), or close to 1260 // magnetic north pole. Typical values are > 100. 1261 return false; 1262 } 1263 final float invH = 1.0f / normH; 1264 Hx *= invH; 1265 Hy *= invH; 1266 Hz *= invH; 1267 final float invA = 1.0f / (float)Math.sqrt(Ax*Ax + Ay*Ay + Az*Az); 1268 Ax *= invA; 1269 Ay *= invA; 1270 Az *= invA; 1271 final float Mx = Ay*Hz - Az*Hy; 1272 final float My = Az*Hx - Ax*Hz; 1273 final float Mz = Ax*Hy - Ay*Hx; 1274 if (R != null) { 1275 if (R.length == 9) { 1276 R[0] = Hx; R[1] = Hy; R[2] = Hz; 1277 R[3] = Mx; R[4] = My; R[5] = Mz; 1278 R[6] = Ax; R[7] = Ay; R[8] = Az; 1279 } else if (R.length == 16) { 1280 R[0] = Hx; R[1] = Hy; R[2] = Hz; R[3] = 0; 1281 R[4] = Mx; R[5] = My; R[6] = Mz; R[7] = 0; 1282 R[8] = Ax; R[9] = Ay; R[10] = Az; R[11] = 0; 1283 R[12] = 0; R[13] = 0; R[14] = 0; R[15] = 1; 1284 } 1285 } 1286 if (I != null) { 1287 // compute the inclination matrix by projecting the geomagnetic 1288 // vector onto the Z (gravity) and X (horizontal component 1289 // of geomagnetic vector) axes. 1290 final float invE = 1.0f / (float)Math.sqrt(Ex*Ex + Ey*Ey + Ez*Ez); 1291 final float c = (Ex*Mx + Ey*My + Ez*Mz) * invE; 1292 final float s = (Ex*Ax + Ey*Ay + Ez*Az) * invE; 1293 if (I.length == 9) { 1294 I[0] = 1; I[1] = 0; I[2] = 0; 1295 I[3] = 0; I[4] = c; I[5] = s; 1296 I[6] = 0; I[7] =-s; I[8] = c; 1297 } else if (I.length == 16) { 1298 I[0] = 1; I[1] = 0; I[2] = 0; 1299 I[4] = 0; I[5] = c; I[6] = s; 1300 I[8] = 0; I[9] =-s; I[10]= c; 1301 I[3] = I[7] = I[11] = I[12] = I[13] = I[14] = 0; 1302 I[15] = 1; 1303 } 1304 } 1305 return true; 1306 } 1307 1308 /** 1309 * Computes the geomagnetic inclination angle in radians from the 1310 * inclination matrix <b>I</b> returned by {@link #getRotationMatrix}. 1311 * 1312 * @param I 1313 * inclination matrix see {@link #getRotationMatrix}. 1314 * 1315 * @return The geomagnetic inclination angle in radians. 1316 * 1317 * @see #getRotationMatrix(float[], float[], float[], float[]) 1318 * @see #getOrientation(float[], float[]) 1319 * @see GeomagneticField 1320 * 1321 */ 1322 public static float getInclination(float[] I) { 1323 if (I.length == 9) { 1324 return (float)Math.atan2(I[5], I[4]); 1325 } else { 1326 return (float)Math.atan2(I[6], I[5]); 1327 } 1328 } 1329 1330 /** 1331 * <p> 1332 * Rotates the supplied rotation matrix so it is expressed in a different 1333 * coordinate system. This is typically used when an application needs to 1334 * compute the three orientation angles of the device (see 1335 * {@link #getOrientation}) in a different coordinate system. 1336 * </p> 1337 * 1338 * <p> 1339 * When the rotation matrix is used for drawing (for instance with OpenGL 1340 * ES), it usually <b>doesn't need</b> to be transformed by this function, 1341 * unless the screen is physically rotated, in which case you can use 1342 * {@link android.view.Display#getRotation() Display.getRotation()} to 1343 * retrieve the current rotation of the screen. Note that because the user 1344 * is generally free to rotate their screen, you often should consider the 1345 * rotation in deciding the parameters to use here. 1346 * </p> 1347 * 1348 * <p> 1349 * <u>Examples:</u> 1350 * <p> 1351 * 1352 * <ul> 1353 * <li>Using the camera (Y axis along the camera's axis) for an augmented 1354 * reality application where the rotation angles are needed:</li> 1355 * 1356 * <p> 1357 * <ul> 1358 * <code>remapCoordinateSystem(inR, AXIS_X, AXIS_Z, outR);</code> 1359 * </ul> 1360 * </p> 1361 * 1362 * <li>Using the device as a mechanical compass when rotation is 1363 * {@link android.view.Surface#ROTATION_90 Surface.ROTATION_90}:</li> 1364 * 1365 * <p> 1366 * <ul> 1367 * <code>remapCoordinateSystem(inR, AXIS_Y, AXIS_MINUS_X, outR);</code> 1368 * </ul> 1369 * </p> 1370 * 1371 * Beware of the above example. This call is needed only to account for a 1372 * rotation from its natural orientation when calculating the rotation 1373 * angles (see {@link #getOrientation}). If the rotation matrix is also used 1374 * for rendering, it may not need to be transformed, for instance if your 1375 * {@link android.app.Activity Activity} is running in landscape mode. 1376 * </ul> 1377 * 1378 * <p> 1379 * Since the resulting coordinate system is orthonormal, only two axes need 1380 * to be specified. 1381 * 1382 * @param inR 1383 * the rotation matrix to be transformed. Usually it is the matrix 1384 * returned by {@link #getRotationMatrix}. 1385 * 1386 * @param X 1387 * defines on which world axis and direction the X axis of the device 1388 * is mapped. 1389 * 1390 * @param Y 1391 * defines on which world axis and direction the Y axis of the device 1392 * is mapped. 1393 * 1394 * @param outR 1395 * the transformed rotation matrix. inR and outR can be the same 1396 * array, but it is not recommended for performance reason. 1397 * 1398 * @return <code>true</code> on success. <code>false</code> if the input 1399 * parameters are incorrect, for instance if X and Y define the same 1400 * axis. Or if inR and outR don't have the same length. 1401 * 1402 * @see #getRotationMatrix(float[], float[], float[], float[]) 1403 */ 1404 1405 public static boolean remapCoordinateSystem(float[] inR, int X, int Y, 1406 float[] outR) 1407 { 1408 if (inR == outR) { 1409 final float[] temp = mTempMatrix; 1410 synchronized(temp) { 1411 // we don't expect to have a lot of contention 1412 if (remapCoordinateSystemImpl(inR, X, Y, temp)) { 1413 final int size = outR.length; 1414 for (int i=0 ; i<size ; i++) 1415 outR[i] = temp[i]; 1416 return true; 1417 } 1418 } 1419 } 1420 return remapCoordinateSystemImpl(inR, X, Y, outR); 1421 } 1422 1423 private static boolean remapCoordinateSystemImpl(float[] inR, int X, int Y, 1424 float[] outR) 1425 { 1426 /* 1427 * X and Y define a rotation matrix 'r': 1428 * 1429 * (X==1)?((X&0x80)?-1:1):0 (X==2)?((X&0x80)?-1:1):0 (X==3)?((X&0x80)?-1:1):0 1430 * (Y==1)?((Y&0x80)?-1:1):0 (Y==2)?((Y&0x80)?-1:1):0 (Y==3)?((X&0x80)?-1:1):0 1431 * r[0] ^ r[1] 1432 * 1433 * where the 3rd line is the vector product of the first 2 lines 1434 * 1435 */ 1436 1437 final int length = outR.length; 1438 if (inR.length != length) 1439 return false; // invalid parameter 1440 if ((X & 0x7C)!=0 || (Y & 0x7C)!=0) 1441 return false; // invalid parameter 1442 if (((X & 0x3)==0) || ((Y & 0x3)==0)) 1443 return false; // no axis specified 1444 if ((X & 0x3) == (Y & 0x3)) 1445 return false; // same axis specified 1446 1447 // Z is "the other" axis, its sign is either +/- sign(X)*sign(Y) 1448 // this can be calculated by exclusive-or'ing X and Y; except for 1449 // the sign inversion (+/-) which is calculated below. 1450 int Z = X ^ Y; 1451 1452 // extract the axis (remove the sign), offset in the range 0 to 2. 1453 final int x = (X & 0x3)-1; 1454 final int y = (Y & 0x3)-1; 1455 final int z = (Z & 0x3)-1; 1456 1457 // compute the sign of Z (whether it needs to be inverted) 1458 final int axis_y = (z+1)%3; 1459 final int axis_z = (z+2)%3; 1460 if (((x^axis_y)|(y^axis_z)) != 0) 1461 Z ^= 0x80; 1462 1463 final boolean sx = (X>=0x80); 1464 final boolean sy = (Y>=0x80); 1465 final boolean sz = (Z>=0x80); 1466 1467 // Perform R * r, in avoiding actual muls and adds. 1468 final int rowLength = ((length==16)?4:3); 1469 for (int j=0 ; j<3 ; j++) { 1470 final int offset = j*rowLength; 1471 for (int i=0 ; i<3 ; i++) { 1472 if (x==i) outR[offset+i] = sx ? -inR[offset+0] : inR[offset+0]; 1473 if (y==i) outR[offset+i] = sy ? -inR[offset+1] : inR[offset+1]; 1474 if (z==i) outR[offset+i] = sz ? -inR[offset+2] : inR[offset+2]; 1475 } 1476 } 1477 if (length == 16) { 1478 outR[3] = outR[7] = outR[11] = outR[12] = outR[13] = outR[14] = 0; 1479 outR[15] = 1; 1480 } 1481 return true; 1482 } 1483 1484 /** 1485 * Computes the device's orientation based on the rotation matrix. 1486 * <p> 1487 * When it returns, the array values is filled with the result: 1488 * <ul> 1489 * <li>values[0]: <i>azimuth</i>, rotation around the Z axis.</li> 1490 * <li>values[1]: <i>pitch</i>, rotation around the X axis.</li> 1491 * <li>values[2]: <i>roll</i>, rotation around the Y axis.</li> 1492 * </ul> 1493 * <p> 1494 * <center><img src="../../../images/axis_device.png" 1495 * alt="Sensors coordinate-system diagram." border="0" /></center> 1496 * </p> 1497 * <p> 1498 * All three angles above are in <b>radians</b> and <b>positive</b> in the 1499 * <b>counter-clockwise</b> direction. 1500 * 1501 * @param R 1502 * rotation matrix see {@link #getRotationMatrix}. 1503 * 1504 * @param values 1505 * an array of 3 floats to hold the result. 1506 * 1507 * @return The array values passed as argument. 1508 * 1509 * @see #getRotationMatrix(float[], float[], float[], float[]) 1510 * @see GeomagneticField 1511 */ 1512 public static float[] getOrientation(float[] R, float values[]) { 1513 /* 1514 * 4x4 (length=16) case: 1515 * / R[ 0] R[ 1] R[ 2] 0 \ 1516 * | R[ 4] R[ 5] R[ 6] 0 | 1517 * | R[ 8] R[ 9] R[10] 0 | 1518 * \ 0 0 0 1 / 1519 * 1520 * 3x3 (length=9) case: 1521 * / R[ 0] R[ 1] R[ 2] \ 1522 * | R[ 3] R[ 4] R[ 5] | 1523 * \ R[ 6] R[ 7] R[ 8] / 1524 * 1525 */ 1526 if (R.length == 9) { 1527 values[0] = (float)Math.atan2(R[1], R[4]); 1528 values[1] = (float)Math.asin(-R[7]); 1529 values[2] = (float)Math.atan2(-R[6], R[8]); 1530 } else { 1531 values[0] = (float)Math.atan2(R[1], R[5]); 1532 values[1] = (float)Math.asin(-R[9]); 1533 values[2] = (float)Math.atan2(-R[8], R[10]); 1534 } 1535 return values; 1536 } 1537 1538 /** 1539 * Computes the Altitude in meters from the atmospheric pressure and the 1540 * pressure at sea level. 1541 * <p> 1542 * Typically the atmospheric pressure is read from a 1543 * {@link Sensor#TYPE_PRESSURE} sensor. The pressure at sea level must be 1544 * known, usually it can be retrieved from airport databases in the 1545 * vicinity. If unknown, you can use {@link #PRESSURE_STANDARD_ATMOSPHERE} 1546 * as an approximation, but absolute altitudes won't be accurate. 1547 * </p> 1548 * <p> 1549 * To calculate altitude differences, you must calculate the difference 1550 * between the altitudes at both points. If you don't know the altitude 1551 * as sea level, you can use {@link #PRESSURE_STANDARD_ATMOSPHERE} instead, 1552 * which will give good results considering the range of pressure typically 1553 * involved. 1554 * </p> 1555 * <p> 1556 * <code><ul> 1557 * float altitude_difference = 1558 * getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, pressure_at_point2) 1559 * - getAltitude(SensorManager.PRESSURE_STANDARD_ATMOSPHERE, pressure_at_point1); 1560 * </ul></code> 1561 * </p> 1562 * 1563 * @param p0 pressure at sea level 1564 * @param p atmospheric pressure 1565 * @return Altitude in meters 1566 */ 1567 public static float getAltitude(float p0, float p) { 1568 final float coef = 1.0f / 5.255f; 1569 return 44330.0f * (1.0f - (float)Math.pow(p/p0, coef)); 1570 } 1571 1572 1573 /** 1574 * {@hide} 1575 */ 1576 public void onRotationChanged(int rotation) { 1577 synchronized(sListeners) { 1578 sRotation = rotation; 1579 } 1580 } 1581 1582 static int getRotation() { 1583 synchronized(sListeners) { 1584 return sRotation; 1585 } 1586 } 1587 1588 private class LegacyListener implements SensorEventListener { 1589 private float mValues[] = new float[6]; 1590 @SuppressWarnings("deprecation") 1591 private SensorListener mTarget; 1592 private int mSensors; 1593 private final LmsFilter mYawfilter = new LmsFilter(); 1594 1595 @SuppressWarnings("deprecation") 1596 LegacyListener(SensorListener target) { 1597 mTarget = target; 1598 mSensors = 0; 1599 } 1600 1601 void registerSensor(int legacyType) { 1602 mSensors |= legacyType; 1603 } 1604 1605 boolean unregisterSensor(int legacyType) { 1606 mSensors &= ~legacyType; 1607 int mask = SENSOR_ORIENTATION|SENSOR_ORIENTATION_RAW; 1608 if (((legacyType&mask)!=0) && ((mSensors&mask)!=0)) { 1609 return false; 1610 } 1611 return true; 1612 } 1613 1614 @SuppressWarnings("deprecation") 1615 public void onAccuracyChanged(Sensor sensor, int accuracy) { 1616 try { 1617 mTarget.onAccuracyChanged(sensor.getLegacyType(), accuracy); 1618 } catch (AbstractMethodError e) { 1619 // old app that doesn't implement this method 1620 // just ignore it. 1621 } 1622 } 1623 1624 @SuppressWarnings("deprecation") 1625 public void onSensorChanged(SensorEvent event) { 1626 final float v[] = mValues; 1627 v[0] = event.values[0]; 1628 v[1] = event.values[1]; 1629 v[2] = event.values[2]; 1630 int legacyType = event.sensor.getLegacyType(); 1631 mapSensorDataToWindow(legacyType, v, SensorManager.getRotation()); 1632 if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) { 1633 if ((mSensors & SENSOR_ORIENTATION_RAW)!=0) { 1634 mTarget.onSensorChanged(SENSOR_ORIENTATION_RAW, v); 1635 } 1636 if ((mSensors & SENSOR_ORIENTATION)!=0) { 1637 v[0] = mYawfilter.filter(event.timestamp, v[0]); 1638 mTarget.onSensorChanged(SENSOR_ORIENTATION, v); 1639 } 1640 } else { 1641 mTarget.onSensorChanged(legacyType, v); 1642 } 1643 } 1644 1645 /* 1646 * Helper function to convert the specified sensor's data to the windows's 1647 * coordinate space from the device's coordinate space. 1648 * 1649 * output: 3,4,5: values in the old API format 1650 * 0,1,2: transformed values in the old API format 1651 * 1652 */ 1653 private void mapSensorDataToWindow(int sensor, 1654 float[] values, int orientation) { 1655 float x = values[0]; 1656 float y = values[1]; 1657 float z = values[2]; 1658 1659 switch (sensor) { 1660 case SensorManager.SENSOR_ORIENTATION: 1661 case SensorManager.SENSOR_ORIENTATION_RAW: 1662 z = -z; 1663 break; 1664 case SensorManager.SENSOR_ACCELEROMETER: 1665 x = -x; 1666 y = -y; 1667 z = -z; 1668 break; 1669 case SensorManager.SENSOR_MAGNETIC_FIELD: 1670 x = -x; 1671 y = -y; 1672 break; 1673 } 1674 values[0] = x; 1675 values[1] = y; 1676 values[2] = z; 1677 values[3] = x; 1678 values[4] = y; 1679 values[5] = z; 1680 1681 if ((orientation & Surface.ROTATION_90) != 0) { 1682 // handles 90 and 270 rotation 1683 switch (sensor) { 1684 case SENSOR_ACCELEROMETER: 1685 case SENSOR_MAGNETIC_FIELD: 1686 values[0] =-y; 1687 values[1] = x; 1688 values[2] = z; 1689 break; 1690 case SENSOR_ORIENTATION: 1691 case SENSOR_ORIENTATION_RAW: 1692 values[0] = x + ((x < 270) ? 90 : -270); 1693 values[1] = z; 1694 values[2] = y; 1695 break; 1696 } 1697 } 1698 if ((orientation & Surface.ROTATION_180) != 0) { 1699 x = values[0]; 1700 y = values[1]; 1701 z = values[2]; 1702 // handles 180 (flip) and 270 (flip + 90) rotation 1703 switch (sensor) { 1704 case SENSOR_ACCELEROMETER: 1705 case SENSOR_MAGNETIC_FIELD: 1706 values[0] =-x; 1707 values[1] =-y; 1708 values[2] = z; 1709 break; 1710 case SENSOR_ORIENTATION: 1711 case SENSOR_ORIENTATION_RAW: 1712 values[0] = (x >= 180) ? (x - 180) : (x + 180); 1713 values[1] =-y; 1714 values[2] =-z; 1715 break; 1716 } 1717 } 1718 } 1719 } 1720 1721 class LmsFilter { 1722 private static final int SENSORS_RATE_MS = 20; 1723 private static final int COUNT = 12; 1724 private static final float PREDICTION_RATIO = 1.0f/3.0f; 1725 private static final float PREDICTION_TIME = (SENSORS_RATE_MS*COUNT/1000.0f)*PREDICTION_RATIO; 1726 private float mV[] = new float[COUNT*2]; 1727 private float mT[] = new float[COUNT*2]; 1728 private int mIndex; 1729 1730 public LmsFilter() { 1731 mIndex = COUNT; 1732 } 1733 1734 public float filter(long time, float in) { 1735 float v = in; 1736 final float ns = 1.0f / 1000000000.0f; 1737 final float t = time*ns; 1738 float v1 = mV[mIndex]; 1739 if ((v-v1) > 180) { 1740 v -= 360; 1741 } else if ((v1-v) > 180) { 1742 v += 360; 1743 } 1744 /* Manage the circular buffer, we write the data twice spaced 1745 * by COUNT values, so that we don't have to copy the array 1746 * when it's full 1747 */ 1748 mIndex++; 1749 if (mIndex >= COUNT*2) 1750 mIndex = COUNT; 1751 mV[mIndex] = v; 1752 mT[mIndex] = t; 1753 mV[mIndex-COUNT] = v; 1754 mT[mIndex-COUNT] = t; 1755 1756 float A, B, C, D, E; 1757 float a, b; 1758 int i; 1759 1760 A = B = C = D = E = 0; 1761 for (i=0 ; i<COUNT-1 ; i++) { 1762 final int j = mIndex - 1 - i; 1763 final float Z = mV[j]; 1764 final float T = 0.5f*(mT[j] + mT[j+1]) - t; 1765 float dT = mT[j] - mT[j+1]; 1766 dT *= dT; 1767 A += Z*dT; 1768 B += T*(T*dT); 1769 C += (T*dT); 1770 D += Z*(T*dT); 1771 E += dT; 1772 } 1773 b = (A*B + C*D) / (E*B + C*C); 1774 a = (E*b - A) / C; 1775 float f = b + PREDICTION_TIME*a; 1776 1777 // Normalize 1778 f *= (1.0f / 360.0f); 1779 if (((f>=0)?f:-f) >= 0.5f) 1780 f = f - (float)Math.ceil(f + 0.5f) + 1.0f; 1781 if (f < 0) 1782 f += 1.0f; 1783 f *= 360.0f; 1784 return f; 1785 } 1786 } 1787 1788 1789 /** Helper function to compute the angle change between two rotation matrices. 1790 * Given a current rotation matrix (R) and a previous rotation matrix 1791 * (prevR) computes the rotation around the x,y, and z axes which 1792 * transforms prevR to R. 1793 * outputs a 3 element vector containing the x,y, and z angle 1794 * change at indexes 0, 1, and 2 respectively. 1795 * <p> Each input matrix is either as a 3x3 or 4x4 row-major matrix 1796 * depending on the length of the passed array: 1797 * <p>If the array length is 9, then the array elements represent this matrix 1798 * <pre> 1799 * / R[ 0] R[ 1] R[ 2] \ 1800 * | R[ 3] R[ 4] R[ 5] | 1801 * \ R[ 6] R[ 7] R[ 8] / 1802 *</pre> 1803 * <p>If the array length is 16, then the array elements represent this matrix 1804 * <pre> 1805 * / R[ 0] R[ 1] R[ 2] R[ 3] \ 1806 * | R[ 4] R[ 5] R[ 6] R[ 7] | 1807 * | R[ 8] R[ 9] R[10] R[11] | 1808 * \ R[12] R[13] R[14] R[15] / 1809 *</pre> 1810 * @param R current rotation matrix 1811 * @param prevR previous rotation matrix 1812 * @param angleChange an array of floats in which the angle change is stored 1813 */ 1814 1815 public static void getAngleChange( float[] angleChange, float[] R, float[] prevR) { 1816 float rd1=0,rd4=0, rd6=0,rd7=0, rd8=0; 1817 float ri0=0,ri1=0,ri2=0,ri3=0,ri4=0,ri5=0,ri6=0,ri7=0,ri8=0; 1818 float pri0=0, pri1=0, pri2=0, pri3=0, pri4=0, pri5=0, pri6=0, pri7=0, pri8=0; 1819 int i, j, k; 1820 1821 if(R.length == 9) { 1822 ri0 = R[0]; 1823 ri1 = R[1]; 1824 ri2 = R[2]; 1825 ri3 = R[3]; 1826 ri4 = R[4]; 1827 ri5 = R[5]; 1828 ri6 = R[6]; 1829 ri7 = R[7]; 1830 ri8 = R[8]; 1831 } else if(R.length == 16) { 1832 ri0 = R[0]; 1833 ri1 = R[1]; 1834 ri2 = R[2]; 1835 ri3 = R[4]; 1836 ri4 = R[5]; 1837 ri5 = R[6]; 1838 ri6 = R[8]; 1839 ri7 = R[9]; 1840 ri8 = R[10]; 1841 } 1842 1843 if(prevR.length == 9) { 1844 pri0 = R[0]; 1845 pri1 = R[1]; 1846 pri2 = R[2]; 1847 pri3 = R[3]; 1848 pri4 = R[4]; 1849 pri5 = R[5]; 1850 pri6 = R[6]; 1851 pri7 = R[7]; 1852 pri8 = R[8]; 1853 } else if(prevR.length == 16) { 1854 pri0 = R[0]; 1855 pri1 = R[1]; 1856 pri2 = R[2]; 1857 pri3 = R[4]; 1858 pri4 = R[5]; 1859 pri5 = R[6]; 1860 pri6 = R[8]; 1861 pri7 = R[9]; 1862 pri8 = R[10]; 1863 } 1864 1865 // calculate the parts of the rotation difference matrix we need 1866 // rd[i][j] = pri[0][i] * ri[0][j] + pri[1][i] * ri[1][j] + pri[2][i] * ri[2][j]; 1867 1868 rd1 = pri0 * ri1 + pri3 * ri4 + pri6 * ri7; //rd[0][1] 1869 rd4 = pri1 * ri1 + pri4 * ri4 + pri7 * ri7; //rd[1][1] 1870 rd6 = pri2 * ri0 + pri5 * ri3 + pri8 * ri6; //rd[2][0] 1871 rd7 = pri2 * ri1 + pri5 * ri4 + pri8 * ri7; //rd[2][1] 1872 rd8 = pri2 * ri2 + pri5 * ri5 + pri8 * ri8; //rd[2][2] 1873 1874 angleChange[0] = (float)Math.atan2(rd1, rd4); 1875 angleChange[1] = (float)Math.asin(-rd7); 1876 angleChange[2] = (float)Math.atan2(-rd6, rd8); 1877 1878 } 1879 1880 /** Helper function to convert a rotation vector to a rotation matrix. 1881 * Given a rotation vector (presumably from a ROTATION_VECTOR sensor), returns a 1882 * 9 or 16 element rotation matrix in the array R. R must have length 9 or 16. 1883 * If R.length == 9, the following matrix is returned: 1884 * <pre> 1885 * / R[ 0] R[ 1] R[ 2] \ 1886 * | R[ 3] R[ 4] R[ 5] | 1887 * \ R[ 6] R[ 7] R[ 8] / 1888 *</pre> 1889 * If R.length == 16, the following matrix is returned: 1890 * <pre> 1891 * / R[ 0] R[ 1] R[ 2] 0 \ 1892 * | R[ 4] R[ 5] R[ 6] 0 | 1893 * | R[ 8] R[ 9] R[10] 0 | 1894 * \ 0 0 0 1 / 1895 *</pre> 1896 * @param rotationVector the rotation vector to convert 1897 * @param R an array of floats in which to store the rotation matrix 1898 */ 1899 public static void getRotationMatrixFromVector(float[] R, float[] rotationVector) { 1900 float q0 = (float)Math.sqrt(1 - rotationVector[0]*rotationVector[0] - 1901 rotationVector[1]*rotationVector[1] - 1902 rotationVector[2]*rotationVector[2]); 1903 float q1 = rotationVector[0]; 1904 float q2 = rotationVector[1]; 1905 float q3 = rotationVector[2]; 1906 1907 float sq_q1 = 2 * q1 * q1; 1908 float sq_q2 = 2 * q2 * q2; 1909 float sq_q3 = 2 * q3 * q3; 1910 float q1_q2 = 2 * q1 * q2; 1911 float q3_q0 = 2 * q3 * q0; 1912 float q1_q3 = 2 * q1 * q3; 1913 float q2_q0 = 2 * q2 * q0; 1914 float q2_q3 = 2 * q2 * q3; 1915 float q1_q0 = 2 * q1 * q0; 1916 1917 if(R.length == 9) { 1918 R[0] = 1 - sq_q2 - sq_q3; 1919 R[1] = q1_q2 - q3_q0; 1920 R[2] = q1_q3 + q2_q0; 1921 1922 R[3] = q1_q2 + q3_q0; 1923 R[4] = 1 - sq_q1 - sq_q3; 1924 R[5] = q2_q3 - q1_q0; 1925 1926 R[6] = q1_q3 - q2_q0; 1927 R[7] = q2_q3 + q1_q0; 1928 R[8] = 1 - sq_q1 - sq_q2; 1929 } else if (R.length == 16) { 1930 R[0] = 1 - sq_q2 - sq_q3; 1931 R[1] = q1_q2 - q3_q0; 1932 R[2] = q1_q3 + q2_q0; 1933 R[3] = 0.0f; 1934 1935 R[4] = q1_q2 + q3_q0; 1936 R[5] = 1 - sq_q1 - sq_q3; 1937 R[6] = q2_q3 - q1_q0; 1938 R[7] = 0.0f; 1939 1940 R[8] = q1_q3 - q2_q0; 1941 R[9] = q2_q3 + q1_q0; 1942 R[10] = 1 - sq_q1 - sq_q2; 1943 R[11] = 0.0f; 1944 1945 R[12] = R[13] = R[14] = 0.0f; 1946 R[15] = 1.0f; 1947 } 1948 } 1949 1950 /** Helper function to convert a rotation vector to a normalized quaternion. 1951 * Given a rotation vector (presumably from a ROTATION_VECTOR sensor), returns a normalized 1952 * quaternion in the array Q. The quaternion is stored as [w, x, y, z] 1953 * @param rv the rotation vector to convert 1954 * @param Q an array of floats in which to store the computed quaternion 1955 */ 1956 public static void getQuaternionFromVector(float[] Q, float[] rv) { 1957 float w = (float)Math.sqrt(1 - rv[0]*rv[0] - rv[1]*rv[1] - rv[2]*rv[2]); 1958 //In this case, the w component of the quaternion is known to be a positive number 1959 1960 Q[0] = w; 1961 Q[1] = rv[0]; 1962 Q[2] = rv[1]; 1963 Q[3] = rv[2]; 1964 } 1965 1966 private static native void nativeClassInit(); 1967 1968 private static native int sensors_module_init(); 1969 private static native int sensors_module_get_next_sensor(Sensor sensor, int next); 1970 1971 // Used within this module from outside SensorManager, don't make private 1972 static native int sensors_create_queue(); 1973 static native void sensors_destroy_queue(int queue); 1974 static native boolean sensors_enable_sensor(int queue, String name, int sensor, int enable); 1975 static native int sensors_data_poll(int queue, float[] values, int[] status, long[] timestamp); 1976} 1977