Search code examples
androidandroid-camera

Get phone orientation when locked into one orientation


This could easily be a duplicate of another question, Im just struggling to figure out what to search for.

My camera app is locked in landscape mode (in the manifest) like this:

android:screenOrientation="landscape"

However, I want to still rotate some UI elements when the device is rotated into portrait (although android will still think its in landscape, but thats on purpose).

So I've tried this to check the orientation

int rotation = this.getWindowManager().getDefaultDisplay()
            .getRotation();
    int degrees = 0;
    switch (rotation) {
        case Surface.ROTATION_0:
            Log.d("Rotation", "0");
            break;
        case Surface.ROTATION_90:
            Log.d("Rotation", "90");
            break;
        case Surface.ROTATION_180:
            Log.d("Rotation", "180");
            break;
        case Surface.ROTATION_270:
            Log.d("Rotation", "270");
            break;
    }

And unfortunately it always returns 90, regardless of how I turn the phone. Is there a more robust way to get orientation, regardless of what Android "thinks" the orientation is?


Solution

  • So after I thought about it, I realized I could just implement a similar algorithm as what Android itself uses to figure out the orientation.
    I do it using the onSensorChanged callback

    public static final int UPSIDE_DOWN = 3;
    public static final int LANDSCAPE_RIGHT = 4;
    public static final int PORTRAIT = 1;
    public static final int LANDSCAPE_LEFT = 2;
    public int mOrientationDeg; //last rotation in degrees
    public int mOrientationRounded; //last orientation int from above 
    private static final int _DATA_X = 0;
    private static final int _DATA_Y = 1;
    private static final int _DATA_Z = 2;
    private int ORIENTATION_UNKNOWN = -1;
    @Override
    public void onSensorChanged(SensorEvent event) 
    {
        Log.d(TAG, "Sensor Changed");
        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;
        // Don't trust the angle if the magnitude is small compared to the y value
        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
            while (orientation >= 360) {
                orientation -= 360;
            } 
            while (orientation < 0) {
                orientation += 360;
            }
        }
        //^^ thanks to google for that code
        //now we must figure out which orientation based on the degrees
        Log.d("Oreination", ""+orientation);
        if (orientation != mOrientationDeg) 
        {
            mOrientationDeg = orientation;
            //figure out actual orientation
            if(orientation == -1){//basically flat
                
            }
            else if(orientation <= 45 || orientation > 315){//round to 0
                tempOrientRounded = 1;//portrait
            }
            else if(orientation > 45 && orientation <= 135){//round to 90
                tempOrientRounded = 2; //lsleft
            }
            else if(orientation > 135 && orientation <= 225){//round to 180
                tempOrientRounded = 3; //upside down
            }
            else if(orientation > 225 && orientation <= 315){//round to 270
                tempOrientRounded = 4;//lsright
            }
            
        }
    
        if(mOrientationRounded != tempOrientRounded){
                //Orientation changed, handle the change here
            mOrientationRounded = tempOrientRounded;
            
        }
    }
    

    It looks more complicated than it is, but just know that it works (I'd say equally well as the system one works).
    Don't forget to register your sensor change event listener in onResume and onPause for the accelerometer.