Skip to content

Instantly share code, notes, and snippets.

@Abdelhady
Last active April 29, 2023 05:16
Show Gist options
  • Star 21 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save Abdelhady/501f6e48c1f3e32b253a to your computer and use it in GitHub Desktop.
Save Abdelhady/501f6e48c1f3e32b253a to your computer and use it in GitHub Desktop.
A utility class to help get current device orientation, you will need it if you decided to fix the activity's orientation in the manifest :)
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;
}
}
}
}
}
@surahul
Copy link

surahul commented Mar 8, 2016

Superb :)

@langhoangal
Copy link

What is the for loop inside addValue for? the smoothness is always equal to 1 then that for never run.

@hafsp65
Copy link

hafsp65 commented Jun 3, 2017

Super working.. 👍

@Abdelhady
Copy link
Author

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

Understanding of roll and pitch

@anuj-github
Copy link

The for loop inside addvalue is never executing. What is its purpose?

@Abdelhady
Copy link
Author

@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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment