Toggling fullscreen & orientation like YouTube
Asked Answered
T

5

14

I am trying to mimic the behavior of the YouTube Android app when the "fullscreen" button is clicked in the video player:

  • If device is currently in portrait, immediately rotate to landscape (even if user is still holding the device in portrait) and remain in landscape until user rotates device to landscape and then rotates back to portrait
    • If device is currently in landscape, immediately rotate to portrait (Even if user is still holding the device in portrait) and remain in portrait until the user rotates the device to portrait and then rotates back to landscape.
    • At anytime, allow the user to manually rotate their device to the desired orientation.

It seems that if I force the rotation to landscape or portrait using:

getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

or

getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

... I immediately lose the ability to detect sensor orientation changes (i.e. once the user is in landscape, and they want to manually rotate the device back to portrait).

If I change the requested orientation to unspecified or sensor in onConfigurationChanged, the orientation briefly flips to landscape/portrait (whatever I requested from above) and then snaps back to the orientation that matches how the device is held.

Any thoughts on how to achieve my goals above?

Tempt answered 3/4, 2014 at 20:23 Comment(0)
T
27

I had the excact same problem. What I ended up with was using an OrientationListener to detect when the user had actually tilted the phone to landscape and then setting the orientation to SCREEN_ORIENTATION_SENSOR.

OrientationEventListener orientationEventListener = 
new OrientationEventListener(getActivity()) {
    @Override
    public void onOrientationChanged(int orientation) {
        int epsilon = 10;
        int leftLandscape = 90;
        int rightLandscape = 270;
        if(epsilonCheck(orientation, leftLandscape, epsilon) ||
           epsilonCheck(orientation, rightLandscape, epsilon)){
                getMainActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
            }
        }

        private boolean epsilonCheck(int a, int b, int epsilon) {
            return a > b - epsilon && a < b + epsilon;
        }
    };
    orientationEventListener.enable();

Here is the documentation for OrientationEventListener : Documentation

You would also need to add checks for portrait , because you described needing that in your original post.

Triboluminescent answered 6/5, 2014 at 8:7 Comment(2)
This should be the selected answer. Also could do Math.abs(a - b) < epsilon for clarityCadent
Sometimes if we don't rotate phone in a perfect gesture, it behaves like, assume the screen is in landscape and phone is in portrait. when i rotate phone from portrait to landscape, the screen will rotate like, it goes to portrait and switches to landscape immediately. So, the solution would be to make the orientation to sensor only when the phone stays in that particular orientation for around 300msGantt
T
5

Big tnx to havch

It is gold, I was stuck on that for 5 hours. Here is my kotlin piece of code to deal with it.

orientationEventListener = object: OrientationEventListener(this) {
            override fun onOrientationChanged(orientation: Int) {
                val isPortrait = orientation > 300 || orientation < 60 || orientation in 120..240

                if ((requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT && isPortrait) ||
                    (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE && !isPortrait)){
                    requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR
                }
            }
        }
        orientationEventListener.enable()
Thurmond answered 12/11, 2019 at 0:19 Comment(0)
P
2

This modification of Alexander code is working better for me

   object : OrientationEventListener(requireContext()) {
        override fun onOrientationChanged(orientation: Int) {
            val isPortrait = orientation > 345 || orientation < 15 || orientation in 165..195
            val isLandscape = orientation in 255..285 || orientation in 75..105
            if (
                (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT && isPortrait) ||
                (requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE && isLandscape)
            ) {
                lifecycleScope.launch {
                    // adding a delay to avoid orientation change glitch
                    delay(200)
                    activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR
                }
            }
        }
    }
Popgun answered 18/10, 2021 at 11:1 Comment(1)
That glitch you are saying is still happening. Rather we need to program it like, change to Orientation_sensor only if that orientation stays in either portrait or landscape for a 200ms or 300ms. In programmatically, we have to check if the phone is still in that particular orientation when compared to what it was when we called the delay() functionGantt
G
0
/**
     * -1 -> Unknown
     * 1 -> Portrait
     * 0 -> Landscape
     */
    var previousOrientation = -1

    val orientationEventListener: OrientationEventListener =
        object : OrientationEventListener(this) {
            override fun onOrientationChanged(orientation: Int) {

                val isPortrait = (orientation > 340 || orientation < 20 || orientation in 160..200) &&
                        requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
                val isLandscape = (orientation in 250..290 || orientation in 70..110) &&
                        requestedOrientation == ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE

                if (isPortrait || isLandscape) {
                    lifecycleScope.launch {
                        if (previousOrientation == -1) {
                            previousOrientation = if (isPortrait) 1 else 0
                        }
                        delay(700)
                        val currentOrientation = if (isPortrait) 1 else 0
                        if (previousOrientation == currentOrientation) {
                            previousOrientation = -1
                            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR
                        }
                    }
                }
            }
        }
    orientationEventListener.enable()

This one handles the orientation glitch more properly. this code is improved version of what @Buntupana posted

Gantt answered 4/3, 2022 at 9:50 Comment(0)
B
-1

Try to setRequestedOrientation to SCREEN_ORIENTATION_SENSOR when exit from fullscreen ! setting OrientationEventListener may cause some unexpected resources usage.

Benita answered 22/4, 2019 at 14:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.