Image by Gus Winkelman

Support new form factors with the new Jetpack WindowManager library

Kenneth Ford
Android Developers

--

Posted by Kenneth Ford and Andrii Kulian

WindowManager is a recent addition to Android Jetpack that aims to help application developers support new device form factors and provide a common API surface for different Window Manager features on both old and new platform versions. The initial release is aimed at foldable devices, and future versions will be extended to support more display types and window features.

Why would I need it?

New foldable devices are appearing on the market that provide a set of unique hardware features. Optimizing your app for these new devices and form-factors allow you to bring a differentiating experience and allow your users to take full advantage of whatever device they are on.

For example, the Samsung Galaxy Z Flip is a clamshell type of device which supports both folded and partially folded states (referred to by Samsung as Flex mode).The app can optimize its layout when the device is in the partially folded state and separate its controls on the bottom from the rest of the content on the top.

Example of how a camera or photo viewer app may adjust (image copyright by Samsung)

Users can set the phone somewhere flat, like on a table, and use the bottom half of the screen to navigate and interact with the app.

Google Duo and Youtube screenshots shown during Samsung Galaxy Unpacked 2020
Google Duo and Youtube screenshots shown during Samsung Galaxy Unpacked 2020

The goal of the Jetpack WindowManager library is to provide a single API surface for different types of foldable devices coming to the market, so that application developers could target entire categories of devices instead of a single model.

In version 1.0.0, the library provides information about two physical properties of foldable devices — display features and device state.

Display features

A single display panel or a multi-display configuration may have different features that create disruptions in the continuous screen surface. Examples of these can be folds, hinges, curved areas, or cutouts. If there are such disruptions within the application window, the layout and placement of the content in the window can be adapted to avoid such areas, or to take advantage of them and use it as a natural separator.

Each display feature area can be characterized by its bounding rectangle in the window coordinate space and its type. The rectangle will indicate the physical bounds of the feature. The type of the feature will help to define how to treat it. For example, some features can create physical separations and/or non-interactive areas (e.g. hinge between two display panels, display cutout), while others can serve as logical separators (e.g. fold).

The first version of the support library includes only two types of features: TYPE_FOLD and TYPE_HINGE.

For TYPE_FOLD specifically the bounding rectangle is expected to be zero-high (0, y, width, y) or zero-wide (x, 0, x, height). This indicates that there is no inaccessible region, but it still reports the position on screen.

Device states

Depending on the hinge hardware design different foldable devices can have several intermediate states: closed, partially opened, fully opened (flat surface), or flipped. Using the library, apps can provide different functions depending on these device states. These states are defined as different postures:

Each device can report any subset of the postures defined above depending on their hardware and desired UX

How do I use it?

To add a dependency on Window Manager, you must add the Google Maven repository to your project.

Add the dependencies for the artifacts you need in the build.gradle file for your app or module:

Google Duo on the Samsung Galaxy Z Flip in both the flat and half-opened state.
Google Duo on the Samsung Galaxy Z Flip

Let’s say you’d like to split the UI of your app like Google Duo on foldable devices. Generally, it would make sense to do so in cases when the physical configuration and state of the device creates a logical separation for the user. For example, the Galaxy Z Flip creates such logical separation when it is in “Flex” or “half-folded” mode. Therefore, you need to know the position of the fold within the app window and the state of the device.

First, obtain an instance of androidx.window.WindowManager from an Activity.

Notice the parameters here.

First, the context is used to initialize and connect the instance of WindowManager to a visual entity on the screen. So it must be a visual Context, which means either Activity or a ContextWrapper around one.

Second, the window backend is the provider of the information for the support library. Passing null here would mean that the default device information would be used, and the library would report no display features and unknown device state when the app runs on a regular phone. However, you can also pass a custom implementation of androidx.window.WindowBackend to emulate any kind of foldable device out there without access to the physical hardware. We show an example of this in our sample application.

Since it only makes sense to separate the UI when there is a logical hardware separation, there are two cases to do so:

  1. Either the type of the display feature is TYPE_HINGE and there is always a physical separation within the activity window.
  2. Or the type of the display feature is Type_Fold, and the state of the screen is not flat (e.g. not POSTURE_OPENED). For the Galaxy Z Flip specifically, we’ll be interested in POSTURE_HALF_OPENED.

For the case of the fold we’ll need to learn about the device posture changes, so we’ll need to register a DeviceState change listener:

In the callback you can change the device state and update the UI if needed.

Lastly, we’ll need to get the actual display features that are located within the activity window.

Depending on how your activity handles (or doesn’t handle) configuration changes, you may need to ask it at different points of the Activity lifecycle. Asking for it on the layout for the window decor view will make sure that it’s always up to date after activity state changes:

Note that the positions of display features are calculated relative to the activity window coordinate space. Therefore, it can only be provided after the activity is attached to the window. Requesting the information before that will throw an Exception.

We strongly suggest exploring the demo application for the library. It also contains examples of computing the position of display features in the view hierarchy, and an example of a layout that automatically splits the content if a dividing display feature is found.

--

--