-
-
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 :)