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