diff --git a/catroid/src/org/catrobat/catroid/formulaeditor/SensorHandler.java b/catroid/src/org/catrobat/catroid/formulaeditor/SensorHandler.java index 53f7d540a59..c7c8f7b47db 100644 --- a/catroid/src/org/catrobat/catroid/formulaeditor/SensorHandler.java +++ b/catroid/src/org/catrobat/catroid/formulaeditor/SensorHandler.java @@ -37,32 +37,55 @@ import org.catrobat.catroid.facedetection.FaceDetectionHandler; public final class SensorHandler implements SensorEventListener, SensorCustomEventListener { + public static final float RADIAN_TO_DEGREE_CONST = 180f / (float) Math.PI; private static final String TAG = SensorHandler.class.getSimpleName(); private static SensorHandler instance = null; + private static BluetoothDeviceService btService = ServiceProvider.getService(CatroidService.BLUETOOTH_DEVICE_SERVICE); private SensorManagerInterface sensorManager = null; + private Sensor linearAccelerationSensor = null; private Sensor accelerometerSensor = null; + private Sensor magneticFieldSensor = null; private Sensor rotationVectorSensor = null; private float[] rotationMatrix = new float[16]; private float[] rotationVector = new float[3]; - public static final float RADIAN_TO_DEGREE_CONST = 180f / (float) Math.PI; - - private float linearAcceleartionX = 0f; - private float linearAcceleartionY = 0f; - private float linearAcceleartionZ = 0f; - + private float[] accelerationXYZ = new float[3]; + private float signAccelerationZ = 0f; + private float[] gravity = new float[] { 0f, 0f, 0f }; + private boolean useLinearAccelerationFallback = false; + private boolean useRotationVectorFallback = false; + private float linearAccelerationX = 0f; + private float linearAccelerationY = 0f; + private float linearAccelerationZ = 0f; private float loudness = 0f; private float faceDetected = 0f; private float faceSize = 0f; private float facePositionX = 0f; private float facePositionY = 0f; - private static BluetoothDeviceService btService = ServiceProvider.getService(CatroidService.BLUETOOTH_DEVICE_SERVICE); - private SensorHandler(Context context) { sensorManager = new SensorManager( (android.hardware.SensorManager) context.getSystemService(Context.SENSOR_SERVICE)); - accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION); + linearAccelerationSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION); + if (linearAccelerationSensor == null) { + useLinearAccelerationFallback = true; + } + rotationVectorSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); + if (rotationVectorSensor == null) { + useRotationVectorFallback = true; + } + + if (useRotationVectorFallback) { + accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + magneticFieldSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); + } else if (useLinearAccelerationFallback) { + accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + } + + Log.d(TAG, "*** LINEAR_ACCELERATION SENSOR: " + linearAccelerationSensor); + Log.d(TAG, "*** ACCELEROMETER SENSOR: " + accelerometerSensor); + Log.d(TAG, "*** ROTATION_VECTOR SENSOR: " + rotationVectorSensor); + Log.d(TAG, "*** MAGNETIC_FIELD SENSOR: " + magneticFieldSensor); } public static void startSensorListener(Context context) { @@ -72,10 +95,9 @@ public static void startSensorListener(Context context) { } instance.sensorManager.unregisterListener((SensorEventListener) instance); instance.sensorManager.unregisterListener((SensorCustomEventListener) instance); - instance.sensorManager.registerListener(instance, instance.accelerometerSensor, - android.hardware.SensorManager.SENSOR_DELAY_NORMAL); - instance.sensorManager.registerListener(instance, instance.rotationVectorSensor, - android.hardware.SensorManager.SENSOR_DELAY_NORMAL); + + instance.registerListener(instance); + instance.sensorManager.registerListener(instance, Sensors.LOUDNESS); FaceDetectionHandler.registerOnFaceDetectedListener(instance); FaceDetectionHandler.registerOnFaceDetectionStatusListener(instance); @@ -85,10 +107,26 @@ public static void registerListener(SensorEventListener listener) { if (instance == null) { return; } - instance.sensorManager.registerListener(listener, instance.accelerometerSensor, - android.hardware.SensorManager.SENSOR_DELAY_NORMAL); - instance.sensorManager.registerListener(listener, instance.rotationVectorSensor, - android.hardware.SensorManager.SENSOR_DELAY_NORMAL); + + if (!instance.useLinearAccelerationFallback) { + instance.sensorManager.registerListener(listener, instance.linearAccelerationSensor, + android.hardware.SensorManager.SENSOR_DELAY_GAME); + } + + if (!instance.useRotationVectorFallback) { + instance.sensorManager.registerListener(listener, instance.rotationVectorSensor, + android.hardware.SensorManager.SENSOR_DELAY_GAME); + } + + if (instance.useLinearAccelerationFallback || instance.useRotationVectorFallback) { + instance.sensorManager.registerListener(listener, instance.accelerometerSensor, + android.hardware.SensorManager.SENSOR_DELAY_GAME); + } + + if (instance.useRotationVectorFallback && instance.magneticFieldSensor != null) { + instance.sensorManager.registerListener(listener, instance.magneticFieldSensor, + android.hardware.SensorManager.SENSOR_DELAY_GAME); + } } public static void unregisterListener(SensorEventListener listener) { @@ -117,50 +155,89 @@ public static Double getSensorValue(Sensors sensor) { switch (sensor) { case X_ACCELERATION: - return (double) instance.linearAcceleartionX; + return (double) instance.linearAccelerationX; case Y_ACCELERATION: - return (double) instance.linearAcceleartionY; + return (double) instance.linearAccelerationY; case Z_ACCELERATION: - return (double) instance.linearAcceleartionZ; + return (double) instance.linearAccelerationZ; case COMPASS_DIRECTION: float[] orientations = new float[3]; - android.hardware.SensorManager.getRotationMatrixFromVector(instance.rotationMatrix, - instance.rotationVector); + if (!instance.useRotationVectorFallback) { + android.hardware.SensorManager.getRotationMatrixFromVector(instance.rotationMatrix, + instance.rotationVector); + } android.hardware.SensorManager.getOrientation(instance.rotationMatrix, orientations); sensorValue = (double) orientations[0]; return sensorValue * RADIAN_TO_DEGREE_CONST * -1f; case X_INCLINATION: - - orientations = new float[3]; - android.hardware.SensorManager.getRotationMatrixFromVector(instance.rotationMatrix, - instance.rotationVector); - android.hardware.SensorManager.getOrientation(instance.rotationMatrix, orientations); - sensorValue = (double) orientations[2]; - return sensorValue * RADIAN_TO_DEGREE_CONST * -1f; - + if (instance.useRotationVectorFallback) { + float rawInclinationX = RADIAN_TO_DEGREE_CONST * (float) (Math.acos(instance.accelerationXYZ[0])); + float correctedInclinationX = 0; + + if (rawInclinationX >= 90 && rawInclinationX <= 180) { + if (instance.signAccelerationZ > 0) { + correctedInclinationX = -(rawInclinationX - 90); + } else { + correctedInclinationX = -(180 + (90 - rawInclinationX)); + } + } else if (rawInclinationX >= 0 && rawInclinationX < 90) { + if (instance.signAccelerationZ > 0) { + correctedInclinationX = (90 - rawInclinationX); + } else { + correctedInclinationX = (90 + rawInclinationX); + } + } + return (double) correctedInclinationX; + } else { + orientations = new float[3]; + android.hardware.SensorManager.getRotationMatrixFromVector(instance.rotationMatrix, + instance.rotationVector); + android.hardware.SensorManager.getOrientation(instance.rotationMatrix, orientations); + sensorValue = (double) orientations[2]; + return sensorValue * RADIAN_TO_DEGREE_CONST * -1f; + } case Y_INCLINATION: - orientations = new float[3]; - android.hardware.SensorManager.getRotationMatrixFromVector(instance.rotationMatrix, - instance.rotationVector); - android.hardware.SensorManager.getOrientation(instance.rotationMatrix, orientations); - - float xInclinationUsedToExtendRangeOfRoll = orientations[2] * RADIAN_TO_DEGREE_CONST * -1f; + if (instance.useRotationVectorFallback) { + float rawInclinationY = RADIAN_TO_DEGREE_CONST * (float) (Math.acos(instance.accelerationXYZ[1])); + float correctedInclinationY = 0; + if (rawInclinationY >= 90 && rawInclinationY <= 180) { + if (instance.signAccelerationZ > 0) { + correctedInclinationY = -(rawInclinationY - 90); + } else { + correctedInclinationY = -(180 + (90 - rawInclinationY)); + } + } else if (rawInclinationY >= 0 && rawInclinationY < 90) { + if (instance.signAccelerationZ > 0) { + correctedInclinationY = (90 - rawInclinationY); + } else { + correctedInclinationY = (90 + rawInclinationY); + } + } + return (double) correctedInclinationY; + } else { + orientations = new float[3]; + android.hardware.SensorManager.getRotationMatrixFromVector(instance.rotationMatrix, + instance.rotationVector); + android.hardware.SensorManager.getOrientation(instance.rotationMatrix, orientations); - sensorValue = (double) orientations[1]; + float xInclinationUsedToExtendRangeOfRoll = orientations[2] * RADIAN_TO_DEGREE_CONST * -1f; - if (Math.abs(xInclinationUsedToExtendRangeOfRoll) <= 90f) { - return sensorValue * RADIAN_TO_DEGREE_CONST * -1f; - } else { - float uncorrectedYInclination = sensorValue.floatValue() * RADIAN_TO_DEGREE_CONST * -1f; + sensorValue = (double) orientations[1]; - if (uncorrectedYInclination > 0f) { - return (double) 180f - uncorrectedYInclination; + if (Math.abs(xInclinationUsedToExtendRangeOfRoll) <= 90f) { + return sensorValue * RADIAN_TO_DEGREE_CONST * -1f; } else { - return (double) -180f - uncorrectedYInclination; + float uncorrectedYInclination = sensorValue.floatValue() * RADIAN_TO_DEGREE_CONST * -1f; + + if (uncorrectedYInclination > 0f) { + return (double) 180f - uncorrectedYInclination; + } else { + return (double) -180f - uncorrectedYInclination; + } } } case FACE_DETECTED: @@ -201,6 +278,15 @@ public static Double getSensorValue(Sensors sensor) { return 0d; } + public static void clearFaceDetectionValues() { + if (instance != null) { + instance.faceDetected = 0f; + instance.faceSize = 0f; + instance.facePositionX = 0f; + instance.facePositionY = 0f; + } + } + @Override public void onAccuracyChanged(Sensor arg0, int arg1) { } @@ -208,10 +294,29 @@ public void onAccuracyChanged(Sensor arg0, int arg1) { @Override public void onSensorChanged(SensorEvent event) { switch (event.sensor.getType()) { + case Sensor.TYPE_MAGNETIC_FIELD: + float[] tempMagneticFieldXYZ = event.values.clone(); + float[] tempInclinationMatrix = new float[9]; + android.hardware.SensorManager.getRotationMatrix(rotationMatrix, tempInclinationMatrix, accelerationXYZ, + tempMagneticFieldXYZ); //http://goo.gl/wo6QK5 + break; + case Sensor.TYPE_ACCELEROMETER: + accelerationXYZ = event.values.clone(); + if (useLinearAccelerationFallback) { + determinePseudoLinearAcceleration(accelerationXYZ.clone()); + } + double normOfG = Math.sqrt(accelerationXYZ[0] * accelerationXYZ[0] + + accelerationXYZ[1] * accelerationXYZ[1] + + accelerationXYZ[2] * accelerationXYZ[2]); + accelerationXYZ[0] = (float) (accelerationXYZ[0] / normOfG); + accelerationXYZ[1] = (float) (accelerationXYZ[1] / normOfG); + accelerationXYZ[2] = (float) (accelerationXYZ[2] / normOfG); + signAccelerationZ = Math.signum(event.values[2]); + break; case Sensor.TYPE_LINEAR_ACCELERATION: - linearAcceleartionX = event.values[0]; - linearAcceleartionY = event.values[1]; - linearAcceleartionZ = event.values[2]; + linearAccelerationX = event.values[0]; + linearAccelerationY = event.values[1]; + linearAccelerationZ = event.values[2]; break; case Sensor.TYPE_ROTATION_VECTOR: rotationVector[0] = event.values[0]; @@ -223,6 +328,18 @@ public void onSensorChanged(SensorEvent event) { } } + private void determinePseudoLinearAcceleration(float[] input) { + float alpha = 0.8f; + + gravity[0] = alpha * gravity[0] + ((1 - alpha) * input[0]); + gravity[1] = alpha * gravity[1] + ((1 - alpha) * input[1]); + gravity[2] = alpha * gravity[2] + ((1 - alpha) * input[2]); + + linearAccelerationX = -1f * (input[0] - gravity[0]); + linearAccelerationY = -1f * (input[1] - gravity[1]); + linearAccelerationZ = -1f * (input[2] - gravity[2]); + } + @Override public void onCustomSensorChanged(SensorCustomEvent event) { switch (event.sensor) { @@ -245,13 +362,4 @@ public void onCustomSensorChanged(SensorCustomEvent event) { Log.v(TAG, "Unhandled sensor: " + event.sensor); } } - - public static void clearFaceDetectionValues() { - if (instance != null) { - instance.faceDetected = 0f; - instance.faceSize = 0f; - instance.facePositionX = 0f; - instance.facePositionY = 0f; - } - } } diff --git a/catroid/src/org/catrobat/catroid/ui/dialogs/FormulaEditorComputeDialog.java b/catroid/src/org/catrobat/catroid/ui/dialogs/FormulaEditorComputeDialog.java index edfcaa3a03d..82bb3ecf1dd 100644 --- a/catroid/src/org/catrobat/catroid/ui/dialogs/FormulaEditorComputeDialog.java +++ b/catroid/src/org/catrobat/catroid/ui/dialogs/FormulaEditorComputeDialog.java @@ -110,14 +110,7 @@ public void onAccuracyChanged(Sensor sensor, int accuracy) { @Override public void onSensorChanged(SensorEvent event) { - switch (event.sensor.getType()) { - case Sensor.TYPE_LINEAR_ACCELERATION: - showFormulaResult(); - break; - case Sensor.TYPE_ROTATION_VECTOR: - showFormulaResult(); - break; - } + showFormulaResult(); } private void setDialogTextView(final String newString) { diff --git a/catroidTest/src/org/catrobat/catroid/test/formulaeditor/ParserTestSensors.java b/catroidTest/src/org/catrobat/catroid/test/formulaeditor/ParserTestSensors.java index 4c33a0a64fb..85b4d850be5 100644 --- a/catroidTest/src/org/catrobat/catroid/test/formulaeditor/ParserTestSensors.java +++ b/catroidTest/src/org/catrobat/catroid/test/formulaeditor/ParserTestSensors.java @@ -202,7 +202,8 @@ public void testSensors() throws SecurityException, IllegalArgumentException, No SimulatedSensorManager simulatedSensorManager = new SimulatedSensorManager(); Reflection.setPrivateField(sensorHandler, "sensorManager", simulatedSensorManager); - Sensor accelerometerSensor = (Sensor) Reflection.getPrivateField(sensorHandler, "accelerometerSensor"); + Sensor accelerometerSensor = (Sensor) Reflection.getPrivateField(sensorHandler, + "linearAccelerationSensor"); Sensor rotationVectorSensor = (Sensor) Reflection.getPrivateField(sensorHandler, "rotationVectorSensor"); SensorHandler.startSensorListener(getInstrumentation().getTargetContext()); @@ -222,9 +223,9 @@ public void testSensors() throws SecurityException, IllegalArgumentException, No float expectedLoudness = (Float) Reflection.getPrivateField(sensorHandler, "loudness"); - float expectedXAcceleration = (Float) Reflection.getPrivateField(sensorHandler, "linearAcceleartionX"); - float expectedYAcceleration = (Float) Reflection.getPrivateField(sensorHandler, "linearAcceleartionY"); - float expectedZAcceleration = (Float) Reflection.getPrivateField(sensorHandler, "linearAcceleartionZ"); + float expectedXAcceleration = (Float) Reflection.getPrivateField(sensorHandler, "linearAccelerationX"); + float expectedYAcceleration = (Float) Reflection.getPrivateField(sensorHandler, "linearAccelerationY"); + float expectedZAcceleration = (Float) Reflection.getPrivateField(sensorHandler, "linearAccelerationZ"); float[] rotationMatrix = new float[16]; float[] rotationVector = (float[]) Reflection.getPrivateField(sensorHandler, "rotationVector");