1 /* 2 * Copyright (C) 2012 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 17 package android.hardware; 18 19 import android.os.RemoteException; 20 import android.os.ServiceManager; 21 import android.view.IRotationWatcher; 22 import android.view.IWindowManager; 23 import android.view.Surface; 24 25 import java.util.HashMap; 26 import java.util.List; 27 28 /** 29 * Helper class for implementing the legacy sensor manager API. 30 * @hide 31 */ 32 @SuppressWarnings("deprecation") 33 final class LegacySensorManager { 34 private static boolean sInitialized; 35 private static IWindowManager sWindowManager; 36 private static int sRotation = Surface.ROTATION_0; 37 38 private final SensorManager mSensorManager; 39 40 // List of legacy listeners. Guarded by mLegacyListenersMap. 41 private final HashMap<SensorListener, LegacyListener> mLegacyListenersMap = 42 new HashMap<SensorListener, LegacyListener>(); 43 44 public LegacySensorManager(SensorManager sensorManager) { 45 mSensorManager = sensorManager; 46 47 synchronized (SensorManager.class) { 48 if (!sInitialized) { 49 sWindowManager = IWindowManager.Stub.asInterface( 50 ServiceManager.getService("window")); 51 if (sWindowManager != null) { 52 // if it's null we're running in the system process 53 // which won't get the rotated values 54 try { 55 sRotation = sWindowManager.watchRotation( 56 new IRotationWatcher.Stub() { 57 public void onRotationChanged(int rotation) { 58 LegacySensorManager.onRotationChanged(rotation); 59 } 60 } 61 ); 62 } catch (RemoteException e) { 63 } 64 } 65 } 66 } 67 } 68 69 public int getSensors() { 70 int result = 0; 71 final List<Sensor> fullList = mSensorManager.getFullSensorList(); 72 for (Sensor i : fullList) { 73 switch (i.getType()) { 74 case Sensor.TYPE_ACCELEROMETER: 75 result |= SensorManager.SENSOR_ACCELEROMETER; 76 break; 77 case Sensor.TYPE_MAGNETIC_FIELD: 78 result |= SensorManager.SENSOR_MAGNETIC_FIELD; 79 break; 80 case Sensor.TYPE_ORIENTATION: 81 result |= SensorManager.SENSOR_ORIENTATION 82 | SensorManager.SENSOR_ORIENTATION_RAW; 83 break; 84 } 85 } 86 return result; 87 } 88 89 public boolean registerListener(SensorListener listener, int sensors, int rate) { 90 if (listener == null) { 91 return false; 92 } 93 boolean result = false; 94 result = registerLegacyListener(SensorManager.SENSOR_ACCELEROMETER, 95 Sensor.TYPE_ACCELEROMETER, listener, sensors, rate) || result; 96 result = registerLegacyListener(SensorManager.SENSOR_MAGNETIC_FIELD, 97 Sensor.TYPE_MAGNETIC_FIELD, listener, sensors, rate) || result; 98 result = registerLegacyListener(SensorManager.SENSOR_ORIENTATION_RAW, 99 Sensor.TYPE_ORIENTATION, listener, sensors, rate) || result; 100 result = registerLegacyListener(SensorManager.SENSOR_ORIENTATION, 101 Sensor.TYPE_ORIENTATION, listener, sensors, rate) || result; 102 result = registerLegacyListener(SensorManager.SENSOR_TEMPERATURE, 103 Sensor.TYPE_TEMPERATURE, listener, sensors, rate) || result; 104 return result; 105 } 106 107 private boolean registerLegacyListener(int legacyType, int type, 108 SensorListener listener, int sensors, int rate) { 109 boolean result = false; 110 // Are we activating this legacy sensor? 111 if ((sensors & legacyType) != 0) { 112 // if so, find a suitable Sensor 113 Sensor sensor = mSensorManager.getDefaultSensor(type); 114 if (sensor != null) { 115 // We do all of this work holding the legacy listener lock to ensure 116 // that the invariants around listeners are maintained. This is safe 117 // because neither registerLegacyListener nor unregisterLegacyListener 118 // are called reentrantly while sensors are being registered or unregistered. 119 synchronized (mLegacyListenersMap) { 120 // If we don't already have one, create a LegacyListener 121 // to wrap this listener and process the events as 122 // they are expected by legacy apps. 123 LegacyListener legacyListener = mLegacyListenersMap.get(listener); 124 if (legacyListener == null) { 125 // we didn't find a LegacyListener for this client, 126 // create one, and put it in our list. 127 legacyListener = new LegacyListener(listener); 128 mLegacyListenersMap.put(listener, legacyListener); 129 } 130 131 // register this legacy sensor with this legacy listener 132 if (legacyListener.registerSensor(legacyType)) { 133 // and finally, register the legacy listener with the new apis 134 result = mSensorManager.registerListener(legacyListener, sensor, rate); 135 } else { 136 result = true; // sensor already enabled 137 } 138 } 139 } 140 } 141 return result; 142 } 143 144 public void unregisterListener(SensorListener listener, int sensors) { 145 if (listener == null) { 146 return; 147 } 148 unregisterLegacyListener(SensorManager.SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER, 149 listener, sensors); 150 unregisterLegacyListener(SensorManager.SENSOR_MAGNETIC_FIELD, Sensor.TYPE_MAGNETIC_FIELD, 151 listener, sensors); 152 unregisterLegacyListener(SensorManager.SENSOR_ORIENTATION_RAW, Sensor.TYPE_ORIENTATION, 153 listener, sensors); 154 unregisterLegacyListener(SensorManager.SENSOR_ORIENTATION, Sensor.TYPE_ORIENTATION, 155 listener, sensors); 156 unregisterLegacyListener(SensorManager.SENSOR_TEMPERATURE, Sensor.TYPE_TEMPERATURE, 157 listener, sensors); 158 } 159 160 private void unregisterLegacyListener(int legacyType, int type, 161 SensorListener listener, int sensors) { 162 // Are we deactivating this legacy sensor? 163 if ((sensors & legacyType) != 0) { 164 // if so, find the corresponding Sensor 165 Sensor sensor = mSensorManager.getDefaultSensor(type); 166 if (sensor != null) { 167 // We do all of this work holding the legacy listener lock to ensure 168 // that the invariants around listeners are maintained. This is safe 169 // because neither registerLegacyListener nor unregisterLegacyListener 170 // are called re-entrantly while sensors are being registered or unregistered. 171 synchronized (mLegacyListenersMap) { 172 // do we know about this listener? 173 LegacyListener legacyListener = mLegacyListenersMap.get(listener); 174 if (legacyListener != null) { 175 // unregister this legacy sensor and if we don't 176 // need the corresponding Sensor, unregister it too 177 if (legacyListener.unregisterSensor(legacyType)) { 178 // corresponding sensor not needed, unregister 179 mSensorManager.unregisterListener(legacyListener, sensor); 180 181 // finally check if we still need the legacyListener 182 // in our mapping, if not, get rid of it too. 183 if (!legacyListener.hasSensors()) { 184 mLegacyListenersMap.remove(listener); 185 } 186 } 187 } 188 } 189 } 190 } 191 } 192 193 static void onRotationChanged(int rotation) { 194 synchronized (SensorManager.class) { 195 sRotation = rotation; 196 } 197 } 198 199 static int getRotation() { 200 synchronized (SensorManager.class) { 201 return sRotation; 202 } 203 } 204 205 private static final class LegacyListener implements SensorEventListener { 206 private float mValues[] = new float[6]; 207 private SensorListener mTarget; 208 private int mSensors; 209 private final LmsFilter mYawfilter = new LmsFilter(); 210 211 LegacyListener(SensorListener target) { 212 mTarget = target; 213 mSensors = 0; 214 } 215 216 boolean registerSensor(int legacyType) { 217 if ((mSensors & legacyType) != 0) { 218 return false; 219 } 220 boolean alreadyHasOrientationSensor = hasOrientationSensor(mSensors); 221 mSensors |= legacyType; 222 if (alreadyHasOrientationSensor && hasOrientationSensor(legacyType)) { 223 return false; // don't need to re-register the orientation sensor 224 } 225 return true; 226 } 227 228 boolean unregisterSensor(int legacyType) { 229 if ((mSensors & legacyType) == 0) { 230 return false; 231 } 232 mSensors &= ~legacyType; 233 if (hasOrientationSensor(legacyType) && hasOrientationSensor(mSensors)) { 234 return false; // can't unregister the orientation sensor just yet 235 } 236 return true; 237 } 238 239 boolean hasSensors() { 240 return mSensors != 0; 241 } 242 243 private static boolean hasOrientationSensor(int sensors) { 244 return (sensors & (SensorManager.SENSOR_ORIENTATION 245 | SensorManager.SENSOR_ORIENTATION_RAW)) != 0; 246 } 247 248 public void onAccuracyChanged(Sensor sensor, int accuracy) { 249 try { 250 mTarget.onAccuracyChanged(getLegacySensorType(sensor.getType()), accuracy); 251 } catch (AbstractMethodError e) { 252 // old app that doesn't implement this method 253 // just ignore it. 254 } 255 } 256 257 public void onSensorChanged(SensorEvent event) { 258 final float v[] = mValues; 259 v[0] = event.values[0]; 260 v[1] = event.values[1]; 261 v[2] = event.values[2]; 262 int type = event.sensor.getType(); 263 int legacyType = getLegacySensorType(type); 264 mapSensorDataToWindow(legacyType, v, LegacySensorManager.getRotation()); 265 if (type == Sensor.TYPE_ORIENTATION) { 266 if ((mSensors & SensorManager.SENSOR_ORIENTATION_RAW)!=0) { 267 mTarget.onSensorChanged(SensorManager.SENSOR_ORIENTATION_RAW, v); 268 } 269 if ((mSensors & SensorManager.SENSOR_ORIENTATION)!=0) { 270 v[0] = mYawfilter.filter(event.timestamp, v[0]); 271 mTarget.onSensorChanged(SensorManager.SENSOR_ORIENTATION, v); 272 } 273 } else { 274 mTarget.onSensorChanged(legacyType, v); 275 } 276 } 277 278 /* 279 * Helper function to convert the specified sensor's data to the windows's 280 * coordinate space from the device's coordinate space. 281 * 282 * output: 3,4,5: values in the old API format 283 * 0,1,2: transformed values in the old API format 284 * 285 */ 286 private void mapSensorDataToWindow(int sensor, 287 float[] values, int orientation) { 288 float x = values[0]; 289 float y = values[1]; 290 float z = values[2]; 291 292 switch (sensor) { 293 case SensorManager.SENSOR_ORIENTATION: 294 case SensorManager.SENSOR_ORIENTATION_RAW: 295 z = -z; 296 break; 297 case SensorManager.SENSOR_ACCELEROMETER: 298 x = -x; 299 y = -y; 300 z = -z; 301 break; 302 case SensorManager.SENSOR_MAGNETIC_FIELD: 303 x = -x; 304 y = -y; 305 break; 306 } 307 values[0] = x; 308 values[1] = y; 309 values[2] = z; 310 values[3] = x; 311 values[4] = y; 312 values[5] = z; 313 314 if ((orientation & Surface.ROTATION_90) != 0) { 315 // handles 90 and 270 rotation 316 switch (sensor) { 317 case SensorManager.SENSOR_ACCELEROMETER: 318 case SensorManager.SENSOR_MAGNETIC_FIELD: 319 values[0] =-y; 320 values[1] = x; 321 values[2] = z; 322 break; 323 case SensorManager.SENSOR_ORIENTATION: 324 case SensorManager.SENSOR_ORIENTATION_RAW: 325 values[0] = x + ((x < 270) ? 90 : -270); 326 values[1] = z; 327 values[2] = y; 328 break; 329 } 330 } 331 if ((orientation & Surface.ROTATION_180) != 0) { 332 x = values[0]; 333 y = values[1]; 334 z = values[2]; 335 // handles 180 (flip) and 270 (flip + 90) rotation 336 switch (sensor) { 337 case SensorManager.SENSOR_ACCELEROMETER: 338 case SensorManager.SENSOR_MAGNETIC_FIELD: 339 values[0] =-x; 340 values[1] =-y; 341 values[2] = z; 342 break; 343 case SensorManager.SENSOR_ORIENTATION: 344 case SensorManager.SENSOR_ORIENTATION_RAW: 345 values[0] = (x >= 180) ? (x - 180) : (x + 180); 346 values[1] =-y; 347 values[2] =-z; 348 break; 349 } 350 } 351 } 352 353 private static int getLegacySensorType(int type) { 354 switch (type) { 355 case Sensor.TYPE_ACCELEROMETER: 356 return SensorManager.SENSOR_ACCELEROMETER; 357 case Sensor.TYPE_MAGNETIC_FIELD: 358 return SensorManager.SENSOR_MAGNETIC_FIELD; 359 case Sensor.TYPE_ORIENTATION: 360 return SensorManager.SENSOR_ORIENTATION_RAW; 361 case Sensor.TYPE_TEMPERATURE: 362 return SensorManager.SENSOR_TEMPERATURE; 363 } 364 return 0; 365 } 366 } 367 368 private static final class LmsFilter { 369 private static final int SENSORS_RATE_MS = 20; 370 private static final int COUNT = 12; 371 private static final float PREDICTION_RATIO = 1.0f/3.0f; 372 private static final float PREDICTION_TIME = (SENSORS_RATE_MS*COUNT/1000.0f)*PREDICTION_RATIO; 373 private float mV[] = new float[COUNT*2]; 374 private long mT[] = new long[COUNT*2]; 375 private int mIndex; 376 377 public LmsFilter() { 378 mIndex = COUNT; 379 } 380 381 public float filter(long time, float in) { 382 float v = in; 383 final float ns = 1.0f / 1000000000.0f; 384 float v1 = mV[mIndex]; 385 if ((v-v1) > 180) { 386 v -= 360; 387 } else if ((v1-v) > 180) { 388 v += 360; 389 } 390 /* Manage the circular buffer, we write the data twice spaced 391 * by COUNT values, so that we don't have to copy the array 392 * when it's full 393 */ 394 mIndex++; 395 if (mIndex >= COUNT*2) 396 mIndex = COUNT; 397 mV[mIndex] = v; 398 mT[mIndex] = time; 399 mV[mIndex-COUNT] = v; 400 mT[mIndex-COUNT] = time; 401 402 float A, B, C, D, E; 403 float a, b; 404 int i; 405 406 A = B = C = D = E = 0; 407 for (i=0 ; i<COUNT-1 ; i++) { 408 final int j = mIndex - 1 - i; 409 final float Z = mV[j]; 410 final float T = (mT[j]/2 + mT[j+1]/2 - time)*ns; 411 float dT = (mT[j] - mT[j+1])*ns; 412 dT *= dT; 413 A += Z*dT; 414 B += T*(T*dT); 415 C += (T*dT); 416 D += Z*(T*dT); 417 E += dT; 418 } 419 b = (A*B + C*D) / (E*B + C*C); 420 a = (E*b - A) / C; 421 float f = b + PREDICTION_TIME*a; 422 423 // Normalize 424 f *= (1.0f / 360.0f); 425 if (((f>=0)?f:-f) >= 0.5f) 426 f = f - (float)Math.ceil(f + 0.5f) + 1.0f; 427 if (f < 0) 428 f += 1.0f; 429 f *= 360.0f; 430 return f; 431 } 432 } 433 } 434