Mastering Device Orientation Detection in Jetpack Compose

Anand Jeyapal
3 min readMay 22, 2024

Let’s assume you fixed the screen’s orientation to portrait or landscapelike below,

activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT

Then this solution will not work and LocalConfiguration.current.orientation will always return Configuration.ORIENTATION_PORTRAIT even the user rotated the device horizontally.

Because the screen orientation is fixed to portrait, not the device orientation.

In this blog post, we’ll delve into how to detect device orientation in Android using the OrientationListener.

What is OrientationListener?

OrientationListener is a class provided by the Android framework that allows developers to monitor changes in device orientation. By registering an OrientationListener with the system, your app can receive updates whenever the device orientation changes, such as when the user rotates their device from portrait to landscape or vice versa.

Implementing Orientation Detection

Let’s start by creating a composable that sets up an OrientationEventListener and displays different content based on the orientation.

Step 1: Create the OrientationListener

First, we need to create an OrientationEventListener through a DisposableEffect that will notify us when the device's orientation changes.

@Composable
fun DeviceOrientationListener(applicationContext: Context, onOrientationChange: (DeviceOrientation) -> Unit) {

DisposableEffect(Unit) {

val orientationEventListener = object : OrientationEventListener(applicationContext) {
override fun onOrientationChanged(orientation: Int) {
if (orientation >= 350 || orientation < 10) {
onOrientationChange(DeviceOrientation.DEVICE_ORIENTATION_PORTRAIT)
} else if (orientation in 80..159) {
onOrientationChange(DeviceOrientation.DEVICE_ORIENTATION_REVERSE_LANDSCAPE)
} else if (orientation in 200..289) {
onOrientationChange(DeviceOrientation.DEVICE_ORIENTATION_LANDSCAPE)
}
}
}
orientationEventListener.enable()

// Disable the event onDispose
onDispose {
orientationEventListener.disable()
}

}
}

Step 2: Create the Composable Function

Next, we’ll create a composable function that sets up the OrientationEventListener and reacts to orientation changes.

import android.content.Context
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp

@Composable
fun OrientationAwareContent() {
val context = LocalContext.current
var orientation by remember { mutableStateOf(DeviceOrientation.DEVICE_ORIENTATION_PORTRAIT) }

val applicationContext = LocalContext.current.applicationContext
DeviceOrientationListener(applicationContext) { orientation = it }

if (orientation == DeviceOrientation.DEVICE_ORIENTATION_LANDSCAPE) {
// Content to show in landscape mode
LandscapeContent()
} else {
// Content to show in portrait mode
PortraitContent()
}
}

@Composable
fun PortraitContent() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(text = "Portrait Mode", style = MaterialTheme.typography.h4)
}
}
@Composable
fun LandscapeContent() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(text = "Landscape Mode", style = MaterialTheme.typography.h4)
}
}

Step 3: Handling Orientation Changes

In our OrientationAwareContent composable, we initialize the DeviceOrientationListener and enable it when the composable enters the composition. We disable the listener when the composable leaves the composition to avoid memory leaks. (That’s the beauty of DisposableEffect)

We use the orientation state to keep track of the current orientation and display different content based on whether the device is in portrait or landscape mode.

Step 4: Creating the Main Activity

Finally, we set up our MainActivity to display the OrientationAwareContent composable.

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.example.orientationlistener.ui.theme.OrientationListenerTheme

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
OrientationListenerTheme {
OrientationAwareContent()
}
}
}
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
OrientationListenerTheme {
OrientationAwareContent()
}
}

Conclusion

Detecting and handling device orientation changes in Jetpack Compose is straightforward with the OrientationEventListener. By setting up an OrientationEventListener within a composable and responding to orientation changes, we can create responsive and adaptive UI layouts that enhance the user experience.

This approach ensures that our app reacts dynamically to orientation changes, providing a seamless and engaging user experience. Try integrating this into your Jetpack Compose project and see how it improves your app’s responsiveness.

--

--