3

I want to achieve the way youtube handles its video orientation.

There are a few things to have in mind before just saying that I have to use onConfigurationChanged.


THINGS TO CONSIDER

  1. The phone orientation. This means the way you hold de phone. It could be PORTRAIT or LANDSCAPE

  2. The screen orientation. This means the way the view is displayed. It could be PORTRAIT or LANDSCAPE regardless of the orientation of the phone


HOW YOUTUBE ROTATION WORKS?

  1. If the phone is in PORTRAIT mode (using OS quick settings)
  • The screen will keep in PORTRAIT. It doesn't matter if you rotate the phone
  • The only way to rotate de screen is by pressing the rotate button.
  • The screen will keep in the last orientation chooses, and it will not change even if you rotate the phone. PORTRAIT will remain PORTRAIT, and LANDSCAPE will remain LANDSCAPE.
  1. If the phone is in AUTO-ROTATE mode
  • if you rotate the phone, then the screen rotation follows it. I mean, if the phone is in PORTRAIT, the screen will be PORTRAIT. And the same happens with LANDSCAPE.

  • if the rotate button is pressed, the screen orientation will change regardless of the phone orientation. In this case, the only way to listen to the sensor orientation is to rotate the phone to the same side of the screen rotation and go back. This is to let the phone sensor have control of the orientation again.


WHAT I HAVE?

With onConfigurationChanged I could know when I rotate the phone (if AUTO-ROTATE is enabled) and define the layout:

override fun onConfigurationChanged(newConfig: Configuration) {
     when (newConfig.orientation) {
         Configuration.ORIENTATION_PORTRAIT -> buildPortrait()
         Configuration.ORIENTATION_LANDSCAPE -> buildLandscape()
     }

     super.onConfigurationChanged(newConfig)
}

With the rotation button, I can handle screen orientation (when the phone is in PORTRAIT BLOCKED from OS)

fun rotate() {
        val orientation = requireActivity().requestedOrientation
        val isRotationOn = Settings.System.getInt(requireActivity().contentResolver,
                Settings.System.ACCELEROMETER_ROTATION, 0) == 1

        requireActivity().requestedOrientation = if (isRotationOn) {
            // AUTO-ROTATE enabled
           TODO()
        } else 
            // PORTRAIT BLOCKED
            if (orientation == PORTRAIT) {
                buildLandscape()
            LANDSCAPE
        } else {
                buildPortrait()
            PORTRAIT
        }
    }

WHAT I CAN'T ACHIEVE? I don't know how to handle screen rotation when I have the AUTO-ROTATE enabled that handles the rotation by the sensor, and at the same time, there is a rotate button that does a rotation regardless of the AUTO-ROTATE.


IMPORTANT: I can't find any example with the solution anywhere.

Deneb Chorny
  • 391
  • 3
  • 19

1 Answers1

0

You need to use OrientationEventListener to listen to orientation change and set requestedOrientation back to ActivityInfo.SCREEN_ORIENTATION_USER when orientation changed. The orientation value passed in onOrientationChanged is from 0 to 359 and -1 means flat. You need to map it into 4 directions according to the following code.

orientationEventListener = object: OrientationEventListener(this) {
    override fun onOrientationChanged(orientation: Int) {
        val newOrientation = when (orientation) {
            in 0 .. 44 -> 0
            in 45 .. 134 -> 1
            in 135 .. 224 -> 2
            in 225 .. 314 -> 3
            in 315 .. 359 -> 0
            else -> ORIENTATION_UNKNOWN
        }
        if (newOrientation != previousOrientation) {
            requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER
        }
        previousOrientation = newOrientation
    }
}

And remember to only enable the above listener if auto-rotate setting is on

val autoRotationOn = Settings.System.getInt(contentResolver,
    Settings.System.ACCELEROMETER_ROTATION, 0) == 1
if (autoRotationOn) {
    orientationEventListener.enable()
} else {
    orientationEventListener.disable()
}

As the auto-rotate setting could be changed within the lifecycle of current activity, you have to listen to the value change and enable/disable the orientationEventListener.

private val contentObserver = object:ContentObserver(handler) {
    override fun onChange(selfChange: Boolean) {
        super.onChange(selfChange)
        setupOrientationEventListener()
    }
}


val settingUri = Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION)
contentResolver.registerContentObserver(settingUri, false, contentObserver)
Xiaoxi Zhang
  • 670
  • 1
  • 5
  • 7