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 
LegacySensorManager(SensorManager sensorManager)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 
getSensors()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 
registerListener(SensorListener listener, int sensors, int rate)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 
registerLegacyListener(int legacyType, int type, SensorListener listener, int sensors, int rate)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 
unregisterListener(SensorListener listener, int sensors)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 
unregisterLegacyListener(int legacyType, int type, SensorListener listener, int sensors)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 
onRotationChanged(int rotation)194     static void onRotationChanged(int rotation) {
195         synchronized (SensorManager.class) {
196             sRotation  = rotation;
197         }
198     }
199 
getRotation()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 
LegacyListener(SensorListener target)212         LegacyListener(SensorListener target) {
213             mTarget = target;
214             mSensors = 0;
215         }
216 
registerSensor(int legacyType)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 
unregisterSensor(int legacyType)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 
hasSensors()240         boolean hasSensors() {
241             return mSensors != 0;
242         }
243 
hasOrientationSensor(int sensors)244         private static boolean hasOrientationSensor(int sensors) {
245             return (sensors & (SensorManager.SENSOR_ORIENTATION
246                     | SensorManager.SENSOR_ORIENTATION_RAW)) != 0;
247         }
248 
onAccuracyChanged(Sensor sensor, int accuracy)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 
onSensorChanged(SensorEvent event)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          */
mapSensorDataToWindow(int sensor, float[] values, int orientation)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 
getLegacySensorType(int type)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 
LmsFilter()379         public LmsFilter() {
380             mIndex = COUNT;
381         }
382 
filter(long time, float in)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