-
-
Save Abdelhady/501f6e48c1f3e32b253a to your computer and use it in GitHub Desktop.
import android.hardware.Sensor; | |
import android.hardware.SensorEvent; | |
import android.hardware.SensorEventListener; | |
import android.hardware.SensorManager; | |
import android.media.ExifInterface; | |
/** | |
* Created by abdelhady on 9/23/14. | |
* | |
* to use this class do the following 3 steps in your activity: | |
* | |
* define 3 sensors as member variables | |
Sensor accelerometer; | |
Sensor magnetometer; | |
Sensor vectorSensor; | |
DeviceOrientation deviceOrientation; | |
* | |
* add this to the activity's onCreate | |
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); | |
accelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); | |
magnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); | |
deviceOrientation = new DeviceOrientation(); | |
* | |
* add this to onResume | |
mSensorManager.registerListener(deviceOrientation.getEventListener(), accelerometer, SensorManager.SENSOR_DELAY_UI); | |
mSensorManager.registerListener(deviceOrientation.getEventListener(), magnetometer, SensorManager.SENSOR_DELAY_UI); | |
* | |
* add this to onPause | |
mSensorManager.unregisterListener(deviceOrientation.getEventListener()); | |
* | |
* | |
* then, you can simply call * deviceOrientation.getOrientation() * wherever you want | |
* | |
* | |
* another alternative to this class's approach: | |
* http://stackoverflow.com/questions/11175599/how-to-measure-the-tilt-of-the-phone-in-xy-plane-using-accelerometer-in-android/15149421#15149421 | |
* | |
*/ | |
public class DeviceOrientation { | |
private final int ORIENTATION_PORTRAIT = ExifInterface.ORIENTATION_ROTATE_90; // 6 | |
private final int ORIENTATION_LANDSCAPE_REVERSE = ExifInterface.ORIENTATION_ROTATE_180; // 3 | |
private final int ORIENTATION_LANDSCAPE = ExifInterface.ORIENTATION_NORMAL; // 1 | |
private final int ORIENTATION_PORTRAIT_REVERSE = ExifInterface.ORIENTATION_ROTATE_270; // 8 | |
int smoothness = 1; | |
private float averagePitch = 0; | |
private float averageRoll = 0; | |
private int orientation = ORIENTATION_PORTRAIT; | |
private float[] pitches; | |
private float[] rolls; | |
public DeviceOrientation() { | |
pitches = new float[smoothness]; | |
rolls = new float[smoothness]; | |
} | |
public SensorEventListener getEventListener() { | |
return sensorEventListener; | |
} | |
public int getOrientation() { | |
return orientation; | |
} | |
SensorEventListener sensorEventListener = new SensorEventListener() { | |
float[] mGravity; | |
float[] mGeomagnetic; | |
@Override | |
public void onSensorChanged(SensorEvent event) { | |
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) | |
mGravity = event.values; | |
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) | |
mGeomagnetic = event.values; | |
if (mGravity != null && mGeomagnetic != null) { | |
float R[] = new float[9]; | |
float I[] = new float[9]; | |
boolean success = SensorManager.getRotationMatrix(R, I, mGravity, mGeomagnetic); | |
if (success) { | |
float orientationData[] = new float[3]; | |
SensorManager.getOrientation(R, orientationData); | |
averagePitch = addValue(orientationData[1], pitches); | |
averageRoll = addValue(orientationData[2], rolls); | |
orientation = calculateOrientation(); | |
} | |
} | |
} | |
@Override | |
public void onAccuracyChanged(Sensor sensor, int accuracy) { | |
// TODO Auto-generated method stub | |
} | |
}; | |
private float addValue(float value, float[] values) { | |
value = (float) Math.round((Math.toDegrees(value))); | |
float average = 0; | |
for (int i = 1; i < smoothness; i++) { | |
values[i - 1] = values[i]; | |
average += values[i]; | |
} | |
values[smoothness - 1] = value; | |
average = (average + value) / smoothness; | |
return average; | |
} | |
private int calculateOrientation() { | |
// finding local orientation dip | |
if (((orientation == ORIENTATION_PORTRAIT || orientation == ORIENTATION_PORTRAIT_REVERSE) | |
&& (averageRoll > -30 && averageRoll < 30))) { | |
if (averagePitch > 0) | |
return ORIENTATION_PORTRAIT_REVERSE; | |
else | |
return ORIENTATION_PORTRAIT; | |
} else { | |
// divides between all orientations | |
if (Math.abs(averagePitch) >= 30) { | |
if (averagePitch > 0) | |
return ORIENTATION_PORTRAIT_REVERSE; | |
else | |
return ORIENTATION_PORTRAIT; | |
} else { | |
if (averageRoll > 0) { | |
return ORIENTATION_LANDSCAPE_REVERSE; | |
} else { | |
return ORIENTATION_LANDSCAPE; | |
} | |
} | |
} | |
} | |
} |
What is the for loop inside addValue for? the smoothness is always equal to 1 then that for never run.
Super working.. 👍
I thought it would be nice to share the logic behind the calculation,
when in portrait (my apps default orientation), users could roll the device a little right or left, but if they rolled it too much (more than 30 degrees) then we need to recalculate the new situation.
See this image for a better understanding of roll and pitch
The for loop inside addvalue
is never executing. What is its purpose?
@anuj-github, I don't fully remember now, but I guess it was basically for getting smoother results, but then I figured that using the smothering constant of 1 is already enough, but probably I left the smothering logic anyways for anyone who might wanna try a different value
Superb :)