Hi, How can I handle auto-rotate in Compose for a ...
# compose
a
Hi, How can I handle auto-rotate in Compose for a player when we already have a button to set fullscreen? I'm using
OrientationChangeListener
, but when the orientation changes from
SCREEN_ORIENTATION_LANDSCAPE
to
SCREEN_ORIENTATION_REVERSE_PORTRAIT
, the screen transitions as follows:
SCREEN_ORIENTATION_LANDSCAPE -> SCREEN_ORIENTATION_PORTRAIT -> SCREEN_ORIENTATION_REVERSE_PORTRAIT
. I don't like this intermediate transition to
SCREEN_ORIENTATION_PORTRAIT
, as it's unnecessary. I also have another solution using
BroadcastReceiver
. It works fine without the button, but when I try to change to fullscreen using the button, the listener doesn't work. Code in thread How can improve auto-rotate.
Copy code
class OrientationChangeListener(private val context: Context) : OrientationEventListener(context) {
  private var lastOrientation: Int = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
  private var lastChangeTime: Long = 0
  private val debounceTime: Long = 500

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

    if (!isAutoRotateEnabled(context)) return

    val currentTime = System.currentTimeMillis()
    if (currentTime - lastChangeTime < debounceTime) return
    val newOrientation = when {
      orientation in 60..120 -> {
        ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
      }
      orientation in 240..300 -> {
        ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
      }
      orientation in 150..210 -> {
        ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
      }
      orientation in 330..360 || orientation in 0..30 -> {
        ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
      }
      else -> {
        lastOrientation
      }
    }
    if (newOrientation != lastOrientation) {
      lastOrientation = newOrientation
      lastChangeTime = currentTime
      onScreenOrientationChanged(newOrientation)
    }
  }
  
  var onScreenOrientationChanged: (Int) -> Unit = {}

  private fun isAutoRotateEnabled(context: Context): Boolean {
    return Settings.System.getInt(
      context.contentResolver,
      Settings.System.ACCELEROMETER_ROTATION,
      0
    ) == 1
  }
}
Copy code
val orientationChangeListener = remember {
  OrientationChangeListener(context).apply {
    onScreenOrientationChanged = { orientation ->
      viewModel.setOrientation(orientation)
      when (orientation) {
        ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE,
        ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE -> viewModel.setPlayerFullScreenState(
          true)

        ActivityInfo.SCREEN_ORIENTATION_PORTRAIT,
        ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT -> viewModel.setPlayerFullScreenState(
          false)
      }
    }
  }
}

DisposableEffect(Unit) {
  orientationChangeListener.enable()

  onDispose {
    orientationChangeListener.disable()
  }
}
Copy code
//  DisposableEffect(context) {
//    val receiver = object : BroadcastReceiver() {
//      override fun onReceive(context: Context?, intent: Intent?) {
//        val orientation = context?.resources?.configuration?.orientation
//        val isLandscape = orientation == ORIENTATION_LANDSCAPE
//        Log.w("SAJAAA",
//          "DisposableEffect isLandscape $isLandscape $orientation ${viewModel.vodFullScreenState.value}")
//        viewModel.updateFullscreenStateFromAutoRotate(isLandscape)
//        viewModel.resetUserToggle()
//      }
//    }
//    context.registerReceiver(receiver, IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED))
//
//    onDispose {
//      context.unregisterReceiver(receiver)
//    }
//  }
Copy code
@Composable
fun LockScreenOrientation(orientation: Int) {
  val context = LocalContext.current
  DisposableEffect(Unit) {
    val activity = context.findActivity() ?: return@DisposableEffect onDispose {}
    val originalOrientation = activity.requestedOrientation

    // Use the orientation passed in the argument (which could be reversed or normal)
    if (orientation != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
      activity.requestedOrientation = orientation
    }

    // Hide/show system UI based on orientation
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
      activity.window.insetsController?.let { insetsController ->
        if (orientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
          orientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
        ) {
          insetsController.hide(WindowInsets.Type.systemBars())
        } else {
          insetsController.show(WindowInsets.Type.systemBars())
        }
      }
    } else {
      if (orientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE ||
        orientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
      ) {
        activity.window.setFlags(
          WindowManager.LayoutParams.FLAG_FULLSCREEN,
          WindowManager.LayoutParams.FLAG_FULLSCREEN
        )
      } else {
        activity.window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
      }
    }
    onDispose {
      // restore original orientation when view disappears
      activity.requestedOrientation = originalOrientation
    }
  }
}