blob: 62c194f0005d6f85b175805a98715d764a231335 [file] [log] [blame]
Jeff Brown4481d9c2012-04-16 16:14:44 -07001/*
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 float mT[] = new float[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 final float t = time*ns;
385 float v1 = mV[mIndex];
386 if ((v-v1) > 180) {
387 v -= 360;
388 } else if ((v1-v) > 180) {
389 v += 360;
390 }
391 /* Manage the circular buffer, we write the data twice spaced
392 * by COUNT values, so that we don't have to copy the array
393 * when it's full
394 */
395 mIndex++;
396 if (mIndex >= COUNT*2)
397 mIndex = COUNT;
398 mV[mIndex] = v;
399 mT[mIndex] = t;
400 mV[mIndex-COUNT] = v;
401 mT[mIndex-COUNT] = t;
402
403 float A, B, C, D, E;
404 float a, b;
405 int i;
406
407 A = B = C = D = E = 0;
408 for (i=0 ; i<COUNT-1 ; i++) {
409 final int j = mIndex - 1 - i;
410 final float Z = mV[j];
411 final float T = 0.5f*(mT[j] + mT[j+1]) - t;
412 float dT = mT[j] - mT[j+1];
413 dT *= dT;
414 A += Z*dT;
415 B += T*(T*dT);
416 C += (T*dT);
417 D += Z*(T*dT);
418 E += dT;
419 }
420 b = (A*B + C*D) / (E*B + C*C);
421 a = (E*b - A) / C;
422 float f = b + PREDICTION_TIME*a;
423
424 // Normalize
425 f *= (1.0f / 360.0f);
426 if (((f>=0)?f:-f) >= 0.5f)
427 f = f - (float)Math.ceil(f + 0.5f) + 1.0f;
428 if (f < 0)
429 f += 1.0f;
430 f *= 360.0f;
431 return f;
432 }
433 }
434}