У меня есть проблема, с которой я боролся уже несколько недель.
У меня есть приложение, которое использует датчик TYPE_ROTATION_VECTOR. Когда я дома, он всегда работает, но когда я нахожусь на улице, датчик перестает работать. Я по-прежнему получаю вызовы onSensorChanged, но значения остаются прежними, даже когда устройство перемещается или поворачивается.
На данный момент мое решение состоит в том, чтобы определить, остаются ли значения неизменными в течение некоторого времени, и если они остаются, я отменяю регистрацию и перерегистрирую SensorEventListener. Потом снова работает.
Но почему это может происходить и только снаружи? Проблема возникает как на Galaxy S3 Mini (с Android 4.1), так и на Nexus 10 (с Android 4.4).
Ниже приведен код моего класса RotationSensor. Объект RotationSensor является членом Fragment с setRetainInstance(true);. Но ошибка возникает только с датчиком TYPE_ROTATION_VECTOR, поэтому я предполагаю, что ошибка должна быть в приведенном ниже коде.
public class RotationSensor extends OrientationSensor { //The super class is just an abstract class which doesn't do anything
private int screen_rotation=0;
private SensorManager mSensorManager;
private Sensor mSensor, magSensor;
private float[] values = null;
private Activity activity=null;
private SensorListener listener;
private float magField=0;
private float[] orientationValsFlat = new float[3];
private float[] orientationValsOpp = new float[3];
private float[] mRotationMatrix = new float[9];
private float[] matrixI=null;
private float[] m_NormMagFieldValues = null;
//This method is called from a Fragment's onResume method.
@Override
public void register(Activity activity, SensorListener otherListener,int sensorSpeed) {
this.activity=activity;
listener=otherListener;
mSensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
if (mSensor==null){
mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
matrixI= new float[9];
}
magSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
mSensorManager.registerListener(this, mSensor, sensorSpeed);
mSensorManager.registerListener(this, magSensor, sensorSpeed);
}
//Called from onPause in a Fragment
@Override
public void unregister() {
activity=null;
listener=null;
mSensorManager.unregisterListener (this, mSensor);
mSensorManager.unregisterListener (this, magSensor);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
if (activity==null) return;
if (listener!=null) listener.onAccuracyChanged(sensor, accuracy);
}
@Override
public void onSensorChanged(SensorEvent event) {
if (activity==null) return;
if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR)
{
values= event.values.clone();
SensorManager.getRotationMatrixFromVector(mRotationMatrix, values);
float[] remapMatrix = new float[9];
SensorManager.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_X, SensorManager.AXIS_Z, remapMatrix);
SensorManager.getOrientation(remapMatrix, orientationValsOpp);
SensorManager.getOrientation(mRotationMatrix, orientationValsFlat);
screen_rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
float screen_adjustment = 0;
switch(screen_rotation) {
case Surface.ROTATION_0: screen_adjustment = 0; break;
case Surface.ROTATION_90: screen_adjustment = (float)Math.PI/2; break;
case Surface.ROTATION_180: screen_adjustment = (float)Math.PI; break;
case Surface.ROTATION_270: screen_adjustment = 3*(float)Math.PI/2; break;
}
if (screen_rotation==Surface.ROTATION_90 || screen_rotation==Surface.ROTATION_270) arrayswap (orientationValsFlat,1,2);
orientationValsFlat[0]+=screen_adjustment;
orientationValsOpp[0]+=screen_adjustment;
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
if (m_NormMagFieldValues == null) m_NormMagFieldValues = new float[3];
m_NormMagFieldValues=event.values.clone();
magField = (float)Math.sqrt(m_NormMagFieldValues[0]*m_NormMagFieldValues[0] + m_NormMagFieldValues[1]*m_NormMagFieldValues[1] + m_NormMagFieldValues[2]*m_NormMagFieldValues[2]);
}
if (event.sensor.getType()==Sensor.TYPE_ACCELEROMETER){
values = event.values.clone();
if (m_NormMagFieldValues!=null && SensorManager.getRotationMatrix(mRotationMatrix, matrixI, values, m_NormMagFieldValues)){
SensorManager.getOrientation(mRotationMatrix, orientationValsFlat);
orientationValsOpp=orientationValsFlat;
screen_rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
float screen_adjustment = 0;
switch(screen_rotation) {
case Surface.ROTATION_0: screen_adjustment = 0; break;
case Surface.ROTATION_90: screen_adjustment = (float)Math.PI/(4); break;
case Surface.ROTATION_180: screen_adjustment = (float)Math.PI/(-2); break;
case Surface.ROTATION_270: screen_adjustment = 3*(float)Math.PI/4; break;
}
if (screen_rotation==Surface.ROTATION_90 || screen_rotation==Surface.ROTATION_270) arrayswap (orientationValsFlat,1,2);
orientationValsFlat[0]+=screen_adjustment; orientationValsOpp[0]+=screen_adjustment;
}
}
if (listener!=null) listener.onSensorChanged(this,event);
}
@Override
public int getField(){
return (int)magField;
}
@Override
public double getAzimuth() {
boolean opp =(screen_rotation==Surface.ROTATION_0 && Math.toDegrees(getPitch())<-50);
if (opp)
return orientationValsOpp[0];
else
return orientationValsFlat[0];
}
@Override
public double getPitch() {
return orientationValsFlat[1];
}
@Override
public double getRoll() {
return orientationValsFlat[2];
}
private void arrayswap (float[] array, int index1, int index2){
float temp= array[index1];
array[index1]=array[index2];
array[index2]=temp;
}
}
public interface SensorListener {
public void onSensorChanged(OrientationSensor os, SensorEvent event);
public void onAccuracyChanged(Sensor sensor, int accuracy);
}