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