App orientation restricted on phones but not on large screens

Two star rating icon

Your app works great on phones in portrait orientation, so you've restricted the app to portrait only. But you see an opportunity to do more on large screens in landscape orientation.

How can you have it both ways—restrict the app to portrait orientation on small screens, but enable landscape on large?

Best practices

The best apps respect user preferences such as device orientation.

The Adaptive app quality guidelines recommend that apps support all device configurations, including portrait and landscape orientations, multi-window mode, and folded and unfolded states of foldable devices. Apps should optimize layouts and user interfaces for different configurations, and apps should save and restore state during configuration changes.

This recipe is a temporary measure—a pinch of large screen support. Use the recipe until you can improve your app to provide full support for all device configurations.

Ingredients

  • screenOrientation: App manifest setting that enables you to specify how your app responds to device orientation changes
  • Activity#setRequestedOrientation(): Method with which you can change the app orientation at runtime
  • LocalConfiguration: Composable local provider that exposes the current device Configuration, allowing you to read screen dimensions in DPs.
  • LaunchedEffect: Compose side-effect API that runs a block of code when a key changes (in this case, when the configuration changes).

Steps

Enable the app to handle orientation changes by default in the app manifest. Then, at runtime, use Jetpack Compose to dynamically restrict the orientation to portrait on compact screens (phones) while allowing all orientations on large screens.

1. Specify orientation setting in the app manifest

You can either avoid declaring the screenOrientation element of the app manifest (in which case orientation defaults to unspecified) or set screen orientation to fullUser. If the user has not locked sensor-based rotation, your app will support all device orientations.

<activity
    android:name=".MyActivity"
    android:screenOrientation="fullUser">

The difference between using unspecified and fullUser is subtle but important. If you don't declare a screenOrientation value, the system chooses the orientation, and the policy the system uses to define the orientation might differ from device to device. On the other hand, specifying fullUser matches more closely the behavior the user defined for the device: if the user has locked sensor-based rotation, the app follows the user preference; otherwise, the system allows any of the four possible screen orientations (portrait, landscape, reverse portrait, or reverse landscape). See android:screenOrientation.

2. Dynamically restrict orientation in Compose

In Jetpack Compose, you can read the current screen dimensions in DPs reactively from LocalConfiguration.current and use a LaunchedEffect to update the Activity's orientation whenever the configuration changes.

If either the screen width or height is less than 600dp (corresponding to the compact breakpoint for phones), restrict the orientation to portrait. Otherwise, allow the system to rotate the app based on the user's preference (unspecified or fullUser).

Here is the complete, compilable implementation:

val configuration = LocalConfiguration.current
val context = LocalActivity.current

LaunchedEffect(configuration) {
    val activity = context ?: return@LaunchedEffect
    // Determine if screen is compact (phone-sized) in either width or height
    val isCompact = configuration.screenWidthDp < 600 || configuration.screenHeightDp < 600
    activity.requestedOrientation = if (isCompact) {
        ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
    } else {
        ActivityInfo.SCREEN_ORIENTATION_FULL_USER
    }
}

By adding the logic inside a LaunchedEffect(configuration) block, you're able to reactively override the orientation setting whenever the app configuration changes, such as when the activity is resized, moved between displays, or when a foldable device is folded or unfolded.

For more information about when configuration changes occur and when they cause activity recreation, refer to Handle configuration changes.

Results

Your app should now remain in portrait orientation on small screens regardless of device rotation. On large screens, the app should support landscape and portrait orientations.

Additional resources

For help with upgrading your app to support all device configurations all the time, see the following: