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
17package android.hardware;
18
19import android.os.RemoteException;
20import android.os.ServiceManager;
21import android.view.IRotationWatcher;
22import android.view.IWindowManager;
23import android.view.Surface;
24
25import java.util.HashMap;
26import java.util.List;
27
28/**
29 * Helper class for implementing the legacy sensor manager API.
30 * @hide
31 */
32@SuppressWarnings("deprecation")
33final 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