Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setRequestedOrientation, but still change according to sensor

I would like to simulate youtube video-view behaviour in terms of handling screen orientation.

use cases:
p1. when user press maximise -> activity always goes into landscape
p2. when user press minimise -> activity always goes into portrait
p3. when user rotates the device -> screen orientation should change accordingly even if p1 or p2 was applied before.

Currently I use:

 @Override
 public void onClick(View view) {
     if (getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT) {
         setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
     } else {
         setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
     }

However this locks the orientation permanently and fails p3.

like image 951
Yuriy Avatar asked Oct 26 '17 11:10

Yuriy


People also ask

How to handle changes in screen orientation?

If you want to manually handle orientation changes in your app you must declare the "orientation" , "screenSize" , and "screenLayout" values in the android:configChanges attributes. You can declare multiple configuration values in the attribute by separating them with a pipe | character.

What happens when screen orientation changes in Android?

When you rotate your device and the screen changes orientation, Android usually destroys your application's existing Activities and Fragments and recreates them . Android does this so that your application can reload resources based on the new configuration.

How to change screen orientation in Android studio?

In AndroidManifest. xml file add the screenOrientation attribute in activity and provides its orientation. In this example, we provide "portrait" orientation for MainActivity and "landscape" for SecondActivity.


2 Answers

After playing around for a while I have found the right solution. First of all - the problem is that android locks the screen after setRequestedOrientation call, you can't have a mix of both, the only to do it is to do everything manually.

Here is how:

class PlayerOrientationListener extends OrientationEventListener {
    PlayerOrientationListener() {
        super(VideoPlayerActivity.this);
    }

    @Override
    public void onOrientationChanged(int orientation) {
        int threshold = 5;
        if (Math.abs(orientation - 0) < threshold) orientation = 0;
        else if (Math.abs(orientation - 90) < threshold) orientation = 90;
        else if (Math.abs(orientation - 180) < threshold) orientation = 180;
        else if (Math.abs(orientation - 270) < threshold) orientation = 270;

        switch (orientation) {
            case 0:
                if (!orientationLandscapeLocked) {
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
                    orientationPortraitLocked = false;
                }
                break;
            case 90:
                if (!orientationPortraitLocked) {
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
                    orientationLandscapeLocked = false;
                }
                break;
            case 180:
                if (!orientationLandscapeLocked) {
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
                    orientationPortraitLocked = false;
                }
                break;
            case 270:
                if (!orientationPortraitLocked) {
                    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
                    orientationLandscapeLocked = false;
                }
                break;
        }
    }
}

and activity code:

View.OnClickListener onExpandClick = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT) {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
                orientationLandscapeLocked = true;
                orientationPortraitLocked = false;
            } else {
                setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
                orientationPortraitLocked = true;
                orientationLandscapeLocked = false;
            }
        }
    };
btnExpandVideo.setOnClickListener(onExpandClick);

orientationListener = new PlayerOrientationListener();
orientationListener.enable();
like image 66
Yuriy Avatar answered Nov 24 '22 01:11

Yuriy


@Yuriy's answer worked great for me, here it is in Kotlin with some minor modifications so that it can live in a separate file:

class PlayerOrientationListener(val activity: Activity?) : OrientationEventListener(activity) {
    companion object {
        private const val ROT_THRESHOLD = 5

        private const val ROT_0 = 0
        private const val ROT_90 = 90
        private const val ROT_180 = 180
        private const val ROT_270 = 270
    }

    private var orientationLockedPortrait = false
    private var orientationLockedLandscape = false

    fun lockLandscape() {
        activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
        orientationLockedLandscape = true
        orientationLockedPortrait = false
    }

    fun lockPortrait() {
        activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
        orientationLockedPortrait = true
        orientationLockedLandscape = false
    }

    override fun onOrientationChanged(orientation: Int) {
        if (orientation == ORIENTATION_UNKNOWN) {
            return
        }

        val rotation: Int =
                when {
                    Math.abs(orientation - ROT_0) < ROT_THRESHOLD -> ROT_0
                    Math.abs(orientation - ROT_90) < ROT_THRESHOLD -> ROT_90
                    Math.abs(orientation - ROT_180) < ROT_THRESHOLD -> ROT_180
                    Math.abs(orientation - ROT_270) < ROT_THRESHOLD -> ROT_270
                    else -> ORIENTATION_UNKNOWN
                }

        when (rotation) {
            ROT_0 -> if (!orientationLockedLandscape) {
                activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
                orientationLockedPortrait = false
            }
            ROT_90 -> if (!orientationLockedPortrait) {
                activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
                orientationLockedLandscape = false
            }
            ROT_180 -> if (!orientationLockedLandscape) {
                activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
                orientationLockedPortrait = false
            }
            ROT_270 -> if (!orientationLockedPortrait) {
                activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
                orientationLockedLandscape = false
            }
        }
    }
}

Then in your Fragment, something like:

val orientationListener = PlayerOrientationListener(activity)
orientationListener.enable()

menuItemMaximize?.setOnMenuItemClickListener {
    orientationListener.lockLandscape()
    true
}

menuItemMinimize?.setOnMenuItemClickListener {
    orientationListener.lockPortrait()
    true
}
like image 20
skylerb Avatar answered Nov 24 '22 01:11

skylerb