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