Illustration by Ocupop

Unbundling the WindowManager

Pietro Maggi
Aug 19 · 6 min read

Optimize application for foldables and large screen devices

Screen sizes in Android are rapidly changing, and with the rising popularity of tablets and foldable devices, understanding the window size and state of your app is critical to developing a responsive UI. Jetpack WindowManager, now in beta, is a library and API providing capabilities similar to the Android framework WindowManager, including support for responsive UIs, callback adapters for detecting screen changes, and window testing APIs. But Jetpack WindowManager also provides support for new types of devices such as foldables and for windowing environments such as Chrome OS.

New WindowManager APIs include the following:

  • WindowLayoutInfo: contains the display features of a window, such as whether the window encompasses a fold or hinge
  • FoldingFeature: enables you to monitor the folded state of a foldable device to determine device postures
  • WindowMetrics: provides the current window metrics or the overall display metrics

Jetpack WindowManager is unbundled from Android, allowing faster iteration on APIs to quickly support the rapidly evolving device market, and enabling app developers to adopt updates to the library without having to wait for the latest Android versions.

Now that the library is in beta, we encourage all developers to adopt Jetpack WindowManager with its device-agnostic API’s, testing API’s, as well as bringing WindowMetrics to allow you to respond easily to window size changes. Graduating to beta means that you can have confidence in the API’s that you are adopting, allowing you to focus solely on building exciting experiences on these devices. Jetpack WindowManager supports feature detection down to API 14.

The library

Jetpack WindowManager is a modern, Kotlin-first library that supports new device form factors and provides “AppCompat-like” capabilities to build applications with a responsive UI.

Fold states

The most visible feature provided by this library is the support for foldable devices. An application can receive events when there’s a change in the device’s fold state, allowing an update in the UI to support new user interactions.

Google Duo on the Samsung Galaxy Z Fold2

Take a look at this Google Duo case study that presents how to add support for foldable devices.

There are two possible fold states, FLAT and HALF_OPENED. For FLAT you can consider the surface to be opened entirely flat, though in some cases it may be split by a hinge. For HALF_OPENED, the window has at least two logical areas. Below, we have images illustrating possibilities for each state:

Fold state: FLAT and HALF-OPENED

An application can receive information about the changes of the fold state by collecting events from a Kotlin flow while the application is active.

To start and stop the event collection, we can use a life cycle scope as explained in the repeatOnLifeCycle API design story blog post and the following code sample:

The application can then use the information available in the received WindowLayoutInfo object to update its layout while the application is visible to the user.

FoldingFeature includes information like hinge orientation and whether the folding feature creates two logical screen areas (isSeparating property). We can use these values to check if the device is in tabletop mode (half open with the hinge horizontal):

Device in TableTop mode

or in book mode (half open with the hinge vertical):

Device in Book mode

You can see an example on how to do this for a media player application in the Tabletop mode on foldable devices article.

Note: It is important to collect these events on the main/UI thread to avoid synchronization issues between the UI and the handling of these events.

Support for responsive UIs

Since screen size can vary so frequently in Android, it’s important to start designing fully adaptive and responsive UIs. Another feature included in the WindowManager library is the ability to retrieve the current and maximum window metrics information. This is similar to the information provided by the framework WindowMetrics API included in API 30 but it is backward compatible down to API 14.

Jetpack WindowManager offers two ways to retrieve WindowMetrics information, as a stream of flow events or synchronously through the WindowMetricsCalculator class.

Use WindowMetricsCalculator when writing code in a view where the asynchronous API can be too hard to deal with (such as onMeasure):

Another use case can be in tests (see Testing below).

For higher level handling of the application UI, use WindowInfoRepository#currentWindowMetrics to get notified by the library when there’s a window size change, independent of whether this change fires a configuration change.

Here’s an example of how to switch your layout depending on how large your available area is:

Callback adapter

To use this library with the Java programming language or to use a callback interface, include the androidx.window:window-java dependency in your application. The artifact provides the WindowInfoRepositoryCallbackAdapter, which you can use to register (and unregister) a callback to receive updates on device posture and window metrics information.

Testing

We’ve heard from developers that more robust testing APIs are critical for maintaining long-term support. Let’s talk about how you can test foldable postures on normal devices.

We’ve seen so far that the Jetpack WindowManager library notifies your application when there’s a change in the device posture so that you can modify the application’s layout.

The library makes available, in androidx.window:window-testing, WindowLayoutInfoPublisherRule, which enables you to publish a WindowInfoLayout with the support of a testing FoldingFeature:

We can use this to create a fake FoldingFeature to be used in our tests:

And then use the WindowLayoutInfoPublisherRule to publish it:

The final step is to check that the activity’s layout that we are testing behaves as expected using the available Espresso matchers.

Below is an example of a test publishing a FoldingFeature with a HALF_OPENED vertical hinge in the screen’s center:

See it in action: Code sample

An up-to-date sample on GitHub shows how to use the Jetpack WindowManager library to retrieve display posture information, collecting the information from the WindowLayoutInfo flow or registering a callback through the WindowInfoRepositoryCallbackAdapter.

The sample also includes a few tests that can be run on any device or emulator.

Adopt WindowManager in your app

Foldable and dual-screen devices are no longer experimental or futuristic — the large display area and additional postures have user value that’s proven, and more devices are now available to your users. Foldables and dual-screen devices represent the natural evolution of the smartphone. For Android developers, they offer the opportunity to enter a premium market that is growing, thanks also to renewed interest by device manufacturers.

We introduced Jetpack WindowManager alpha01 last year. Since then the library has had a steady evolution with some great improvements to address the early feedback. The library has now embraced Android’s Kotlin-first philosophy, transitioning from a callback-driven model to coroutines and flows. With WindowManager now in beta, the API is stable, and we strongly recommend adoption.

And the updates don’t stop there. We plan to add more functionality to the library and to evolve it in an unbundled AppCompat for system UI, enabling developers to easily implement modern, responsive UIs on all Android devices.

Keep the feedback flowing!

Visit this page if you want to see more resources about optimizing for foldables and other large screen devices.

Android Developers

The official Android Developers publication on Medium