Home | History | Annotate | Download | only in hardware
      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