0

I have fixed my screen orientation in an activity with

     android:screenOrientation="portrait"

Still, I want to find the angle at which the user is currently holding the screen, i.e, 0, 90 or 270. Accordingly I have to perform some actions.

 getWindowManager().getDefaultDisplay()
        .getRotation()

The above code will always return 0 since I have fixed the orientation of the screen. Can someone please suggest how do I determine the screen orientation in this situation.

Prateek
  • 1,062
  • 1
  • 10
  • 27
  • I would check out the links in this answer. They have some good examples of getting values from the gyroscope. I believe this is what you'd be looking to implement. http://stackoverflow.com/questions/12080170/get-android-rotation-angle-in-x-axis Android SDK Reference: http://developer.android.com/reference/android/hardware/SensorEvent.html – RoraΖ Jul 08 '14 at 18:07

1 Answers1

0

Your activity should implement the SensorEventListener and the onSensorChanged() method:

protected void onCreate(Bundle savedInstanceState) {
    ...         
    sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    orientationSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    ...
}

@Override
public void onSensorChanged(SensorEvent event) {

    int ORIENTATION_UNKNOWN = -1;
    int _DATA_X = 0;
    int _DATA_Y = 1;
    int _DATA_Z = 2;

    if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
        float[] values = event.values;
        int orientation = ORIENTATION_UNKNOWN;
        float X = -values[_DATA_X];
        float Y = -values[_DATA_Y];
        float Z = -values[_DATA_Z];        
        float magnitude = X*X + Y*Y;
        if (magnitude * 4 >= Z*Z) {
            float OneEightyOverPi = 57.29577957855f;
            float angle = (float)Math.atan2(-Y, X) * OneEightyOverPi;
            orientation = 90 - (int)Math.round(angle);
            // normalize to 0 - 359 range
            orientation = compensateOrientation(orientation);
            while (orientation >= 360) {
                orientation -= 360;
            } 
            while (orientation < 0) {
                orientation += 360;
            }
        }

        if (orientation != lastOrientation) {
            lastOrientation = orientation;
            int generalOrientation = getGeneralOrientation(orientation);
            if(generalOrientation != GENERAL_ORIENTATION_UNCHANGED && generalOrientation != lastGeneralOrientation){ 
                lastGeneralOrientation = generalOrientation;
                onOrientationChanged(generalOrientation);
            }
        }
    }
}

/**
 * Only returns 4 orientations and gives some buffer zones where the orientation is not affected
 * 
 * @param degrees
 * @return
 */
private static int getGeneralOrientation(int degrees){
    if(degrees >= 330 || degrees <= 30 ) return 0;
    if(degrees <= 300 && degrees >= 240) return 270;
    if(degrees <= 210 && degrees >= 160) return 180;
    if(degrees <= 120 && degrees >= 60) return 90;
    return GENERAL_ORIENTATION_UNCHANGED;
}

You can also use this method to compensate for the device-specific orientation. Some devices report portrait as 0 degress, while other may report it as 270 degrees. This takes care of all the combinations:

/**
 * 
 * Compensate orientation based on the default rotation degrees for the device.
 * Some devices 0 degrees is landscape while on other 0 degrees is portrait
 * 
 * @param degrees
 * @return
 */
private int compensateOrientation(int degrees){
    Display display = getWindowManager().getDefaultDisplay();
    switch(display.getRotation()){
    case(Surface.ROTATION_270):
        return degrees + 270;
    case(Surface.ROTATION_180):
        return degrees + 180;
    case(Surface.ROTATION_90):
        return degrees + 90;
    default:
        return degrees;
    }
}

Also register the sensor listener and unregister it like this:

@Override
protected void onPause() {
    super.onPause();
    if(sensorManager != null) sensorManager.unregisterListener(this);
}

@Override
protected void onResume(){
    super.onResume();

    if(sensorManager != null) sensorManager.registerListener(this, orientationSensor, SensorManager.SENSOR_DELAY_NORMAL);

}
swbandit
  • 1,986
  • 1
  • 26
  • 37
  • Thanks for the reply Mike, but for some reason my OnSensorChanged is not getting called on rotating the screen in various directions, any particular reason for that? – Prateek Jul 09 '14 at 07:20
  • Sorry, forgot to include the register/unregister for the sensor listener. I updated my answer accordingly. Also added the sensorManager in the onCreate() method. – swbandit Jul 09 '14 at 13:46