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