439 lines
17 KiB
Java
439 lines
17 KiB
Java
![]() |
/*
|
||
|
* Copyright (C) 2012 The Android Open Source Project
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package android.hardware;
|
||
|
|
||
|
import static android.view.Display.DEFAULT_DISPLAY;
|
||
|
|
||
|
import android.os.RemoteException;
|
||
|
import android.os.ServiceManager;
|
||
|
import android.view.IRotationWatcher;
|
||
|
import android.view.IWindowManager;
|
||
|
import android.view.Surface;
|
||
|
|
||
|
import java.util.HashMap;
|
||
|
import java.util.List;
|
||
|
|
||
|
/**
|
||
|
* Helper class for implementing the legacy sensor manager API.
|
||
|
* @hide
|
||
|
*/
|
||
|
@SuppressWarnings("deprecation")
|
||
|
final class LegacySensorManager {
|
||
|
private static boolean sInitialized;
|
||
|
private static IWindowManager sWindowManager;
|
||
|
private static int sRotation = Surface.ROTATION_0;
|
||
|
|
||
|
private final SensorManager mSensorManager;
|
||
|
|
||
|
// List of legacy listeners. Guarded by mLegacyListenersMap.
|
||
|
private final HashMap<SensorListener, LegacyListener> mLegacyListenersMap =
|
||
|
new HashMap<SensorListener, LegacyListener>();
|
||
|
|
||
|
public LegacySensorManager(SensorManager sensorManager) {
|
||
|
mSensorManager = sensorManager;
|
||
|
|
||
|
synchronized (SensorManager.class) {
|
||
|
if (!sInitialized) {
|
||
|
sWindowManager = IWindowManager.Stub.asInterface(
|
||
|
ServiceManager.getService("window"));
|
||
|
if (sWindowManager != null) {
|
||
|
// if it's null we're running in the system process
|
||
|
// which won't get the rotated values
|
||
|
try {
|
||
|
sRotation = sWindowManager.watchRotation(
|
||
|
new IRotationWatcher.Stub() {
|
||
|
public void onRotationChanged(int rotation) {
|
||
|
LegacySensorManager.onRotationChanged(rotation);
|
||
|
}
|
||
|
}, DEFAULT_DISPLAY);
|
||
|
} catch (RemoteException e) {
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public int getSensors() {
|
||
|
int result = 0;
|
||
|
final List<Sensor> fullList = mSensorManager.getFullSensorList();
|
||
|
for (Sensor i : fullList) {
|
||
|
switch (i.getType()) {
|
||
|
case Sensor.TYPE_ACCELEROMETER:
|
||
|
result |= SensorManager.SENSOR_ACCELEROMETER;
|
||
|
break;
|
||
|
case Sensor.TYPE_MAGNETIC_FIELD:
|
||
|
result |= SensorManager.SENSOR_MAGNETIC_FIELD;
|
||
|
break;
|
||
|
case Sensor.TYPE_ORIENTATION:
|
||
|
result |= SensorManager.SENSOR_ORIENTATION
|
||
|
| SensorManager.SENSOR_ORIENTATION_RAW;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
public boolean registerListener(SensorListener listener, int sensors, int rate) {
|
||
|
if (listener == null) {
|
||
|
return false;
|
||
|
}
|
||
|
boolean result = false;
|
||
|
result = registerLegacyListener(SensorManager.SENSOR_ACCELEROMETER,
|
||
|
Sensor.TYPE_ACCELEROMETER, listener, sensors, rate) || result;
|
||
|
result = registerLegacyListener(SensorManager.SENSOR_MAGNETIC_FIELD,
|
||
|
Sensor.TYPE_MAGNETIC_FIELD, listener, sensors, rate) || result;
|
||
|
result = registerLegacyListener(SensorManager.SENSOR_ORIENTATION_RAW,
|
||
|
Sensor.TYPE_ORIENTATION, listener, sensors, rate) || result;
|
||
|
result = registerLegacyListener(SensorManager.SENSOR_ORIENTATION,
|
||
|
Sensor.TYPE_ORIENTATION, listener, sensors, rate) || result;
|
||
|
result = registerLegacyListener(SensorManager.SENSOR_TEMPERATURE,
|
||
|
Sensor.TYPE_TEMPERATURE, listener, sensors, rate) || result;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
private boolean registerLegacyListener(int legacyType, int type,
|
||
|
SensorListener listener, int sensors, int rate) {
|
||
|
boolean result = false;
|
||
|
// Are we activating this legacy sensor?
|
||
|
if ((sensors & legacyType) != 0) {
|
||
|
// if so, find a suitable Sensor
|
||
|
Sensor sensor = mSensorManager.getDefaultSensor(type);
|
||
|
if (sensor != null) {
|
||
|
// We do all of this work holding the legacy listener lock to ensure
|
||
|
// that the invariants around listeners are maintained. This is safe
|
||
|
// because neither registerLegacyListener nor unregisterLegacyListener
|
||
|
// are called reentrantly while sensors are being registered or unregistered.
|
||
|
synchronized (mLegacyListenersMap) {
|
||
|
// If we don't already have one, create a LegacyListener
|
||
|
// to wrap this listener and process the events as
|
||
|
// they are expected by legacy apps.
|
||
|
LegacyListener legacyListener = mLegacyListenersMap.get(listener);
|
||
|
if (legacyListener == null) {
|
||
|
// we didn't find a LegacyListener for this client,
|
||
|
// create one, and put it in our list.
|
||
|
legacyListener = new LegacyListener(listener);
|
||
|
mLegacyListenersMap.put(listener, legacyListener);
|
||
|
}
|
||
|
|
||
|
// register this legacy sensor with this legacy listener
|
||
|
if (legacyListener.registerSensor(legacyType)) {
|
||
|
// and finally, register the legacy listener with the new apis
|
||
|
result = mSensorManager.registerListener(legacyListener, sensor, rate);
|
||
|
} else {
|
||
|
result = true; // sensor already enabled
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
public void unregisterListener(SensorListener listener, int sensors) {
|
||
|
if (listener == null) {
|
||
|
return;
|
||
|
}
|
||
|
unregisterLegacyListener(SensorManager.SENSOR_ACCELEROMETER, Sensor.TYPE_ACCELEROMETER,
|
||
|
listener, sensors);
|
||
|
unregisterLegacyListener(SensorManager.SENSOR_MAGNETIC_FIELD, Sensor.TYPE_MAGNETIC_FIELD,
|
||
|
listener, sensors);
|
||
|
unregisterLegacyListener(SensorManager.SENSOR_ORIENTATION_RAW, Sensor.TYPE_ORIENTATION,
|
||
|
listener, sensors);
|
||
|
unregisterLegacyListener(SensorManager.SENSOR_ORIENTATION, Sensor.TYPE_ORIENTATION,
|
||
|
listener, sensors);
|
||
|
unregisterLegacyListener(SensorManager.SENSOR_TEMPERATURE, Sensor.TYPE_TEMPERATURE,
|
||
|
listener, sensors);
|
||
|
}
|
||
|
|
||
|
private void unregisterLegacyListener(int legacyType, int type,
|
||
|
SensorListener listener, int sensors) {
|
||
|
// Are we deactivating this legacy sensor?
|
||
|
if ((sensors & legacyType) != 0) {
|
||
|
// if so, find the corresponding Sensor
|
||
|
Sensor sensor = mSensorManager.getDefaultSensor(type);
|
||
|
if (sensor != null) {
|
||
|
// We do all of this work holding the legacy listener lock to ensure
|
||
|
// that the invariants around listeners are maintained. This is safe
|
||
|
// because neither registerLegacyListener nor unregisterLegacyListener
|
||
|
// are called re-entrantly while sensors are being registered or unregistered.
|
||
|
synchronized (mLegacyListenersMap) {
|
||
|
// do we know about this listener?
|
||
|
LegacyListener legacyListener = mLegacyListenersMap.get(listener);
|
||
|
if (legacyListener != null) {
|
||
|
// unregister this legacy sensor and if we don't
|
||
|
// need the corresponding Sensor, unregister it too
|
||
|
if (legacyListener.unregisterSensor(legacyType)) {
|
||
|
// corresponding sensor not needed, unregister
|
||
|
mSensorManager.unregisterListener(legacyListener, sensor);
|
||
|
|
||
|
// finally check if we still need the legacyListener
|
||
|
// in our mapping, if not, get rid of it too.
|
||
|
if (!legacyListener.hasSensors()) {
|
||
|
mLegacyListenersMap.remove(listener);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void onRotationChanged(int rotation) {
|
||
|
synchronized (SensorManager.class) {
|
||
|
sRotation = rotation;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int getRotation() {
|
||
|
synchronized (SensorManager.class) {
|
||
|
return sRotation;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static final class LegacyListener implements SensorEventListener {
|
||
|
private float[] mValues = new float[6];
|
||
|
private SensorListener mTarget;
|
||
|
private int mSensors;
|
||
|
private final LmsFilter mYawfilter = new LmsFilter();
|
||
|
|
||
|
LegacyListener(SensorListener target) {
|
||
|
mTarget = target;
|
||
|
mSensors = 0;
|
||
|
}
|
||
|
|
||
|
boolean registerSensor(int legacyType) {
|
||
|
if ((mSensors & legacyType) != 0) {
|
||
|
return false;
|
||
|
}
|
||
|
boolean alreadyHasOrientationSensor = hasOrientationSensor(mSensors);
|
||
|
mSensors |= legacyType;
|
||
|
if (alreadyHasOrientationSensor && hasOrientationSensor(legacyType)) {
|
||
|
return false; // don't need to re-register the orientation sensor
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
boolean unregisterSensor(int legacyType) {
|
||
|
if ((mSensors & legacyType) == 0) {
|
||
|
return false;
|
||
|
}
|
||
|
mSensors &= ~legacyType;
|
||
|
if (hasOrientationSensor(legacyType) && hasOrientationSensor(mSensors)) {
|
||
|
return false; // can't unregister the orientation sensor just yet
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
boolean hasSensors() {
|
||
|
return mSensors != 0;
|
||
|
}
|
||
|
|
||
|
private static boolean hasOrientationSensor(int sensors) {
|
||
|
return (sensors & (SensorManager.SENSOR_ORIENTATION
|
||
|
| SensorManager.SENSOR_ORIENTATION_RAW)) != 0;
|
||
|
}
|
||
|
|
||
|
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||
|
try {
|
||
|
mTarget.onAccuracyChanged(getLegacySensorType(sensor.getType()), accuracy);
|
||
|
} catch (AbstractMethodError e) {
|
||
|
// old app that doesn't implement this method
|
||
|
// just ignore it.
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void onSensorChanged(SensorEvent event) {
|
||
|
final float[] v = mValues;
|
||
|
v[0] = event.values[0];
|
||
|
v[1] = event.values[1];
|
||
|
v[2] = event.values[2];
|
||
|
int type = event.sensor.getType();
|
||
|
int legacyType = getLegacySensorType(type);
|
||
|
mapSensorDataToWindow(legacyType, v, LegacySensorManager.getRotation());
|
||
|
if (type == Sensor.TYPE_ORIENTATION) {
|
||
|
if ((mSensors & SensorManager.SENSOR_ORIENTATION_RAW) != 0) {
|
||
|
mTarget.onSensorChanged(SensorManager.SENSOR_ORIENTATION_RAW, v);
|
||
|
}
|
||
|
if ((mSensors & SensorManager.SENSOR_ORIENTATION) != 0) {
|
||
|
v[0] = mYawfilter.filter(event.timestamp, v[0]);
|
||
|
mTarget.onSensorChanged(SensorManager.SENSOR_ORIENTATION, v);
|
||
|
}
|
||
|
} else {
|
||
|
mTarget.onSensorChanged(legacyType, v);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Helper function to convert the specified sensor's data to the windows's
|
||
|
* coordinate space from the device's coordinate space.
|
||
|
*
|
||
|
* output: 3,4,5: values in the old API format
|
||
|
* 0,1,2: transformed values in the old API format
|
||
|
*
|
||
|
*/
|
||
|
private void mapSensorDataToWindow(int sensor,
|
||
|
float[] values, int orientation) {
|
||
|
float x = values[0];
|
||
|
float y = values[1];
|
||
|
float z = values[2];
|
||
|
|
||
|
switch (sensor) {
|
||
|
case SensorManager.SENSOR_ORIENTATION:
|
||
|
case SensorManager.SENSOR_ORIENTATION_RAW:
|
||
|
z = -z;
|
||
|
break;
|
||
|
case SensorManager.SENSOR_ACCELEROMETER:
|
||
|
x = -x;
|
||
|
y = -y;
|
||
|
z = -z;
|
||
|
break;
|
||
|
case SensorManager.SENSOR_MAGNETIC_FIELD:
|
||
|
x = -x;
|
||
|
y = -y;
|
||
|
break;
|
||
|
}
|
||
|
values[0] = x;
|
||
|
values[1] = y;
|
||
|
values[2] = z;
|
||
|
values[3] = x;
|
||
|
values[4] = y;
|
||
|
values[5] = z;
|
||
|
|
||
|
if ((orientation & Surface.ROTATION_90) != 0) {
|
||
|
// handles 90 and 270 rotation
|
||
|
switch (sensor) {
|
||
|
case SensorManager.SENSOR_ACCELEROMETER:
|
||
|
case SensorManager.SENSOR_MAGNETIC_FIELD:
|
||
|
values[0] = -y;
|
||
|
values[1] = x;
|
||
|
values[2] = z;
|
||
|
break;
|
||
|
case SensorManager.SENSOR_ORIENTATION:
|
||
|
case SensorManager.SENSOR_ORIENTATION_RAW:
|
||
|
values[0] = x + ((x < 270) ? 90 : -270);
|
||
|
values[1] = z;
|
||
|
values[2] = y;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if ((orientation & Surface.ROTATION_180) != 0) {
|
||
|
x = values[0];
|
||
|
y = values[1];
|
||
|
z = values[2];
|
||
|
// handles 180 (flip) and 270 (flip + 90) rotation
|
||
|
switch (sensor) {
|
||
|
case SensorManager.SENSOR_ACCELEROMETER:
|
||
|
case SensorManager.SENSOR_MAGNETIC_FIELD:
|
||
|
values[0] = -x;
|
||
|
values[1] = -y;
|
||
|
values[2] = z;
|
||
|
break;
|
||
|
case SensorManager.SENSOR_ORIENTATION:
|
||
|
case SensorManager.SENSOR_ORIENTATION_RAW:
|
||
|
values[0] = (x >= 180) ? (x - 180) : (x + 180);
|
||
|
values[1] = -y;
|
||
|
values[2] = -z;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static int getLegacySensorType(int type) {
|
||
|
switch (type) {
|
||
|
case Sensor.TYPE_ACCELEROMETER:
|
||
|
return SensorManager.SENSOR_ACCELEROMETER;
|
||
|
case Sensor.TYPE_MAGNETIC_FIELD:
|
||
|
return SensorManager.SENSOR_MAGNETIC_FIELD;
|
||
|
case Sensor.TYPE_ORIENTATION:
|
||
|
return SensorManager.SENSOR_ORIENTATION_RAW;
|
||
|
case Sensor.TYPE_TEMPERATURE:
|
||
|
return SensorManager.SENSOR_TEMPERATURE;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static final class LmsFilter {
|
||
|
private static final int SENSORS_RATE_MS = 20;
|
||
|
private static final int COUNT = 12;
|
||
|
private static final float PREDICTION_RATIO = 1.0f / 3.0f;
|
||
|
private static final float PREDICTION_TIME =
|
||
|
(SENSORS_RATE_MS * COUNT / 1000.0f) * PREDICTION_RATIO;
|
||
|
private float[] mV = new float[COUNT * 2];
|
||
|
private long[] mT = new long[COUNT * 2];
|
||
|
private int mIndex;
|
||
|
|
||
|
public LmsFilter() {
|
||
|
mIndex = COUNT;
|
||
|
}
|
||
|
|
||
|
public float filter(long time, float in) {
|
||
|
float v = in;
|
||
|
final float ns = 1.0f / 1000000000.0f;
|
||
|
float v1 = mV[mIndex];
|
||
|
if ((v - v1) > 180) {
|
||
|
v -= 360;
|
||
|
} else if ((v1 - v) > 180) {
|
||
|
v += 360;
|
||
|
}
|
||
|
/* Manage the circular buffer, we write the data twice spaced
|
||
|
* by COUNT values, so that we don't have to copy the array
|
||
|
* when it's full
|
||
|
*/
|
||
|
mIndex++;
|
||
|
if (mIndex >= COUNT * 2) {
|
||
|
mIndex = COUNT;
|
||
|
}
|
||
|
mV[mIndex] = v;
|
||
|
mT[mIndex] = time;
|
||
|
mV[mIndex - COUNT] = v;
|
||
|
mT[mIndex - COUNT] = time;
|
||
|
|
||
|
float A, B, C, D, E;
|
||
|
float a, b;
|
||
|
int i;
|
||
|
|
||
|
A = B = C = D = E = 0;
|
||
|
for (i = 0; i < COUNT - 1; i++) {
|
||
|
final int j = mIndex - 1 - i;
|
||
|
final float Z = mV[j];
|
||
|
final float T = (mT[j] / 2 + mT[j + 1] / 2 - time) * ns;
|
||
|
float dT = (mT[j] - mT[j + 1]) * ns;
|
||
|
dT *= dT;
|
||
|
A += Z * dT;
|
||
|
B += T * (T * dT);
|
||
|
C += (T * dT);
|
||
|
D += Z * (T * dT);
|
||
|
E += dT;
|
||
|
}
|
||
|
b = (A * B + C * D) / (E * B + C * C);
|
||
|
a = (E * b - A) / C;
|
||
|
float f = b + PREDICTION_TIME * a;
|
||
|
|
||
|
// Normalize
|
||
|
f *= (1.0f / 360.0f);
|
||
|
if (((f >= 0) ? f : -f) >= 0.5f) {
|
||
|
f = f - (float) Math.ceil(f + 0.5f) + 1.0f;
|
||
|
}
|
||
|
if (f < 0) {
|
||
|
f += 1.0f;
|
||
|
}
|
||
|
f *= 360.0f;
|
||
|
return f;
|
||
|
}
|
||
|
}
|
||
|
}
|