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?
This guide is a temporary measure until you can improve your app to provide full support for all device configurations.
Manage app orientation
To enable landscape orientation on large screens, set your app manifest to handle orientation changes by default. At runtime, determine the app window size. If the app window is small, restrict the app's orientation by overriding the manifest orientation setting.
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 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 screenOrientation
.
2. Determine screen size
With the manifest set to support all user‑permitted orientations, you can specify app orientation programmatically based on screen size.
Add the Jetpack WindowManager libraries to the module's build.gradle
or
build.gradle.kts
file:
Kotlin
implementation("androidx.window:window:version
") implementation("androidx.window:window-core:version
")
Groovy
implementation 'androidx.window:window:version
' implementation 'androidx.window:window-core:version
'
Use the Jetpack WindowManager
WindowMetricsCalculator#computeMaximumWindowMetrics()
method to obtain the
device screen size as a WindowMetrics
object. The window metrics can be
compared to window size classes to decide when to restrict orientation.
Windows size classes provide the breakpoints between small and large screens.
Use the WindowWidthSizeClass#COMPACT
and
WindowHeightSizeClass#COMPACT
breakpoints to determine the screen size:
Kotlin
/** Determines whether the device has a compact screen. **/ fun compactScreen() : Boolean { val metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this) val width = metrics.bounds.width() val height = metrics.bounds.height() val density = resources.displayMetrics.density val windowSizeClass = WindowSizeClass.compute(width/density, height/density) return windowSizeClass.windowWidthSizeClass == WindowWidthSizeClass.COMPACT || windowSizeClass.windowHeightSizeClass == WindowHeightSizeClass.COMPACT }
Java
/** Determines whether the device has a compact screen. **/ private boolean compactScreen() { WindowMetrics metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this); int width = metrics.getBounds().width(); int height = metrics.getBounds().height(); float density = getResources().getDisplayMetrics().density; WindowSizeClass windowSizeClass = WindowSizeClass.compute(width/density, height/density); return windowSizeClass.getWindowWidthSizeClass() == WindowWidthSizeClass.COMPACT || windowSizeClass.getWindowHeightSizeClass() == WindowHeightSizeClass.COMPACT; }
- Note:
- The examples are implemented as methods of an activity; and so, the activity is dereferenced as
this
in the argument ofcomputeMaximumWindowMetrics()
. - The
computeMaximumWindowMetrics()
method is used instead ofcomputeCurrentWindowMetrics()
because the app can be launched in multi‑window mode, which ignores the screen orientation setting. There's no point in determining the app window size and overriding the orientation setting unless the app window is the entire device screen.
See WindowManager for instructions about declaring dependencies to make the
computeMaximumWindowMetrics()
method available in your app.
3. Override app manifest setting
When you've determined that the device has compact screen size, you can call
Activity#setRequestedOrientation()
to override the manifest's
screenOrientation
setting:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) requestedOrientation = if (compactScreen()) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_FULL_USER ... // Replace with a known container that you can safely add a // view to where the view won't affect the layout and the view // won't be replaced. val container: ViewGroup = binding.container // Add a utility view to the container to hook into // View.onConfigurationChanged. This is required for all // activities, even those that don't handle configuration // changes. You can't use Activity.onConfigurationChanged, // since there are situations where that won't be called when // the configuration changes. View.onConfigurationChanged is // called in those scenarios. container.addView(object : View(this) { override fun onConfigurationChanged(newConfig: Configuration?) { super.onConfigurationChanged(newConfig) requestedOrientation = if (compactScreen()) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_FULL_USER } }) }
Java
@Override protected void onCreate(Bundle savedInstance) { super.onCreate(savedInstanceState); if (compactScreen()) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER); } ... // Replace with a known container that you can safely add a // view to where the view won't affect the layout and the view // won't be replaced. ViewGroup container = binding.container; // Add a utility view to the container to hook into // View.onConfigurationChanged. This is required for all // activities, even those that don't handle configuration // changes. You can't use Activity.onConfigurationChanged, // since there are situations where that won't be called when // the configuration changes. View.onConfigurationChanged is // called in those scenarios. container.addView(new View(this) { @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); if (compactScreen()) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } else { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER); } } }); }
By adding the logic to the onCreate()
and View.onConfigurationChanged()
methods, you're able to obtain the maximum window metrics and override the
orientation setting whenever the activity is resized or moved between displays,
such as after a device rotation 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.
Key points
screenOrientation
: App manifest setting that enables you to specify how your app responds to device orientation changes- Jetpack WindowManager: Set of libraries that enable you to determine the size and aspect ratio of the app window; backward compatible to API level 14
Activity#setRequestedOrientation()
: Method with which you can change the app orientation at runtime
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.
Collections that contain this guide
This guide is part of these curated Quick Guide collections that cover broader Android development goals: