Get phone orientation but fix screen orientation to portrait
Asked Answered
L

7

32

I want to get the phone orientation but keep the screen orientation to portrait. So no matter the user turns the phone to landscape or portrait, the view stays the same, but I can get whether it is turned to landscape or portrait.

Setting the activity to android:screenOrientation="portrait" will fix both but I wouldn't be able to detect the phone orientation via

public void onConfigurationChanged(Configuration newConfig) {
    switch (newConfig.orientation) {
    case Configuration.ORIENTATION_PORTRAIT:
        Toast.makeText(this, "Portrait", Toast.LENGTH_SHORT).show();
        break;
    case Configuration.ORIENTATION_LANDSCAPE:
        Toast.makeText(this, "Landscape", Toast.LENGTH_SHORT).show();
        break;
    default:
        break;
    }
}

Has anyone an idea how to fix that?

Lightfooted answered 26/1, 2012 at 16:50 Comment(1)
Take a look on this : https://mcmap.net/q/454587/-detect-device-orientation-when-activity-orientation-is-locked this solution using SensorManager.Ferrel
B
22

Could you satisfy your requirement with the accelerometer? If so, perhaps something like this (untested) fragment would suit your purposes.

SensorManager sensorManager = (SensorManager) this.getSystemService(Context.SENSOR_SERVICE);
        sensorManager.registerListener(new SensorEventListener() {
            int orientation=-1;;

            @Override
            public void onSensorChanged(SensorEvent event) {
                if (event.values[1]<6.5 && event.values[1]>-6.5) {
                    if (orientation!=1) {
                        Log.d("Sensor", "Landscape");
                    }
                    orientation=1;
                } else {
                    if (orientation!=0) {
                        Log.d("Sensor", "Portrait");
                    }
                    orientation=0;
                }
            }

            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy) {
                // TODO Auto-generated method stub

            }
        }, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_GAME);
Beulahbeuthel answered 26/1, 2012 at 17:23 Comment(4)
Hi Phillip. That's the same solution I implemented myself. In this context there seems to be no other option then to access the sensor in order to get the orientation of the device.Lightfooted
Isn't of much value if the device is laying flat on a table.Bibliology
Anyone knows know how to detect reverse_landscape?Birecree
would this eat too much battery?Convenient
B
36

Here is a multi-purpose class for easily managing screen orientation changes:

public class OrientationManager extends OrientationEventListener {

    public enum ScreenOrientation {
        REVERSED_LANDSCAPE, LANDSCAPE, PORTRAIT, REVERSED_PORTRAIT
    }

    public ScreenOrientation screenOrientation; 
    private OrientationListener listener;

    public OrientationManager(Context context, int rate, OrientationListener listener) {
        super(context, rate);
        setListener(listener);
    }

    public OrientationManager(Context context, int rate) {
        super(context, rate);
    }

    public OrientationManager(Context context) {
        super(context);
    }

    @Override
    public void onOrientationChanged(int orientation) {
        if (orientation == -1){
            return;
        }
        ScreenOrientation newOrientation;
        if (orientation >= 60 && orientation <= 140){
            newOrientation = ScreenOrientation.REVERSED_LANDSCAPE;
        } else if (orientation >= 140 && orientation <= 220) {
            newOrientation = ScreenOrientation.REVERSED_PORTRAIT;
        } else if (orientation >= 220 && orientation <= 300) {
            newOrientation = ScreenOrientation.LANDSCAPE;
        } else {
            newOrientation = ScreenOrientation.PORTRAIT;                    
        }
        if(newOrientation != screenOrientation){
            screenOrientation = newOrientation;
            if(listener != null){
                listener.onOrientationChange(screenOrientation);
            }           
        }
    }

    public void setListener(OrientationListener listener){
        this.listener = listener;
    }

    public ScreenOrientation getScreenOrientation(){
        return screenOrientation;
    }

    public interface OrientationListener {

        public void onOrientationChange(ScreenOrientation screenOrientation);
    }
}

This is way more simple, reusable, and you can also get REVERSE_LANDSCAPE and REVERSE_PORTRAIT orientations.

You must implement OrientationListener in order to get notified only when an orientation change occurs.

Don't forget to call orientationManager.enable() to begin orientation tracking, and then calling orientationManager.disable() (this two methods are inherited from OrientationEventListener class)

UPDATE: use case example

MyFragment extends Fragment implements OrientationListener {

    ...

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        orientationManager = new OrientationManager(getActivity(), SensorManager.SENSOR_DELAY_NORMAL, this);
        orientationManager.enable();        
    }

    @Override
    public void onOrientationChange(ScreenOrientation screenOrientation) {
        switch(screenOrientation){
            case PORTRAIT:
            case REVERSED_PORTRAIT:
                MainActivityBase.getInstance().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
            break;
            case REVERSED_LANDSCAPE:
                MainActivityBase.getInstance().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
            break;
            case LANDSCAPE:
                MainActivityBase.getInstance().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            break;
        }
    }
}
Birecree answered 4/11, 2014 at 12:41 Comment(3)
So nice, thank you so much. Can't belive this answer got only one upvote.Hygro
Great solution, but please be aware that this gives the correct result only on Smartphones which have portrait mode as default mode. On tablets (with landscape as default), orientation will have value 0 in case of landscape orientation, that is, you have to add 270 to the orientation value before applying your logic. For default device orientation, see #4554150Scintillator
And 3 years later I'm finding this and this is such an elegant solution... if I could only give you more than 1 upvote haha.Albertinaalbertine
B
22

Could you satisfy your requirement with the accelerometer? If so, perhaps something like this (untested) fragment would suit your purposes.

SensorManager sensorManager = (SensorManager) this.getSystemService(Context.SENSOR_SERVICE);
        sensorManager.registerListener(new SensorEventListener() {
            int orientation=-1;;

            @Override
            public void onSensorChanged(SensorEvent event) {
                if (event.values[1]<6.5 && event.values[1]>-6.5) {
                    if (orientation!=1) {
                        Log.d("Sensor", "Landscape");
                    }
                    orientation=1;
                } else {
                    if (orientation!=0) {
                        Log.d("Sensor", "Portrait");
                    }
                    orientation=0;
                }
            }

            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy) {
                // TODO Auto-generated method stub

            }
        }, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_GAME);
Beulahbeuthel answered 26/1, 2012 at 17:23 Comment(4)
Hi Phillip. That's the same solution I implemented myself. In this context there seems to be no other option then to access the sensor in order to get the orientation of the device.Lightfooted
Isn't of much value if the device is laying flat on a table.Bibliology
Anyone knows know how to detect reverse_landscape?Birecree
would this eat too much battery?Convenient
H
3

I needed a solution that would give me the orientation only on-demand. This one worked for me:

public class SensorOrientationChecker {

public final String TAG = getClass().getSimpleName();

int mOrientation = 0;
private SensorEventListener mSensorEventListener;
private SensorManager mSensorManager;

private static SensorOrientationChecker mInstance;

public static SensorOrientationChecker getInstance() {
    if (mInstance == null)
        mInstance = new SensorOrientationChecker();

    return mInstance;
}

private SensorOrientationChecker() {
    mSensorEventListener = new Listener();
    Context applicationContext = GlobalData.getInstance().getContext();
    mSensorManager = (SensorManager) applicationContext.getSystemService(Context.SENSOR_SERVICE);

}

/**
 * Call on activity onResume()
 */
public void onResume() {
    mSensorManager.registerListener(mSensorEventListener, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
}

/**
 * Call on activity onPause()
 */
public void onPause() {
    mSensorManager.unregisterListener(mSensorEventListener);
}

private class Listener implements SensorEventListener {

    @Override
    public void onSensorChanged(SensorEvent event) {
        float x = event.values[0];
        float y = event.values[1];

        if (x<5 && x>-5 && y > 5)
            mOrientation = 0;
        else if (x<-5 && y<5 && y>-5)
            mOrientation = 90;
        else if (x<5 && x>-5 && y<-5)
            mOrientation = 180;
        else if (x>5 && y<5 && y>-5)
            mOrientation = 270;

        //Log.e(TAG,"mOrientation="+mOrientation+"   ["+event.values[0]+","+event.values[1]+","+event.values[2]+"]");
                                                                       }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }

}

public int getOrientation(){
    return mOrientation;
    }
}
Helban answered 15/2, 2015 at 14:38 Comment(0)
E
2

If you disable screen orientation change then obviously the onConfigurationChanged will never be called...

I think the only way is to use accelerometer sensor, check this link.

Ensepulcher answered 26/1, 2012 at 17:28 Comment(0)
D
0

To get into that you want to set in manifest file in that activity

android:configChanges="orientation|keyboardHidden"

Then when user rotate phone it will came into public void onConfigurationChanged() method. Also remove

android:screenOrientation="portrait" 

from the same activity.

Deepseated answered 26/1, 2012 at 17:22 Comment(1)
But if onConfigurationChanged() is called the orientation change has already been performed... I need the information before.Lightfooted
H
0

This is way simpler than writing a whole new class:

 final OrientationEventListener orientationEventListener = new OrientationEventListener( getApplicationContext() ) {

  @Override
  public void onOrientationChanged( final int orientation ) {
    Log.i("", "orientation = " + orientation );
  }
};

orientationEventListener.enable();
Higgs answered 27/9, 2020 at 22:20 Comment(0)
P
-3

In case anybody is looking for a Webview/javascript solution to the question, the below can do that.

This will trigger custom 'flip' events on the window, with 'extra parameters' as jquery has them. It also sets window.flip, analogue to window.orientation:

$(window).on('flip',function(ev,angle,orientation) {
    console.log(angle,orientation);
    alert(window.flip);
});

if (window.DeviceOrientationEvent) {
    jQuery.flip = {
        debug       : false,
        interval    : 1000,
        checked     : false,
        betaflat    : 25,
        gammaflat   : 45,
        orientation : 'portrait-primary',
        angles      : {
            'portrait-primary'      : 0,
            'portrait-secondary'    : 0,
            'landscape-primary'     : 90,
            'landscape-secondary'   : -90       
        },
        timer       : null,
        check       : function(ev) {
            if (!this.checked) {
                var trigger=false;
                if (this.debug) console.log([ev.alpha,ev.beta,ev.gamma]);
                if (ev.beta>this.betaflat) {
                    // if beta is big its portrait
                    if (this.debug) console.log('beta portrait pri');
                    if (this.orientation!='portrait-primary') {
                        this.orientation='portrait-primary';
                        trigger=true;
                    }
                } else if (ev.beta<-this.betaflat) {
                    // if beta is big its portrait
                    if (this.debug) console.log('beta portrait sec');
                    if (this.orientation!='portrait-secondary') {
                        this.orientation='portrait-secondary';
                        trigger=true;
                    }
                } else if (ev.gamma>this.gammaflat) {

                    // else if gamma is big its landscape
                    if (this.debug) console.log('gamma landscape pri');
                    if (this.orientation!='landscape-primary') {
                        this.orientation='landscape-primary';
                        trigger=true;
                    }

                } else if (ev.gamma<-this.gammaflat) {

                    // else if gamma is big its landscape
                    if (this.debug) console.log('gamma landscape sec');
                    if (this.orientation!='landscape-secondary') {
                        this.orientation='landscape-secondary';
                        trigger=true;
                    }

                }
                if (trigger) {
                    if (this.debug) console.log('trigger flip');
                    window.flip = this.angles[this.orientation];
                    $(window).trigger('flip',[window.flip,this.orientation]);
                    this.checked=true;
                }
            }
        }
    }
    $(document).ready(function() {
        setInterval(function() {jQuery.flip.checked=false},jQuery.flip.interval);
        $(window).on('deviceorientation',function(ev) { jQuery.flip.check(ev.originalEvent) });
    });
} else {
    if (this.debug) console.log('DeviceOrientationEvent not supported');
}

The jquery is not really needed. I had it required anyway.

Pennant answered 27/11, 2014 at 22:6 Comment(3)
Solving an Android issue with Javascript is not really helpful. It requires to have a WebView or similar to run the script which might not be the case.Lightfooted
oh - good point. living in my own bubble. updating the answer.Pennant
so why the downvote now ? I'm mentioning this is webview/javascript, and the OP doesn't mention what world s/he lives in.Pennant

© 2022 - 2024 — McMap. All rights reserved.