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