Exploring Jetpack WindowManager for Foldable Devices
Over the last decade, the evolution of mobile devices has rapidly expanded the ecosystem of device form factors. Foldable devices are one of the more recent additions that has pushed the boundaries of what we thought was possible, offering different displays — or even a combination of displays — depending on a device’s folding state.
Of this new generation of foldable devices, dual-screen devices, which provide symmetrical screens that work together in unique ways, are particularly interesting. But, they also present unique challenges.
A key feature of these foldable, responsive UIs is that screen sizes can change in runtime. This means that applications should recognize screen changes in runtime, which could be a challenging feature for developers to implement who need to focus on business code.
To get around this challenge, Google suggested a new solution: the Jetpack WindowManager. Now that the library is in RC release, Google is encouraging all developers to adopt Jetpack WindowManager with its device-agnostic APIs, testing APIs, and WindowMetrics so you can respond easily to screen changes.
In this post, you’ll learn how to set up the foldable device emulator and how to use the Jetpack WindowManager library to build responsive UIs for Android.
For additional help, check out the links below:
Set Up the Foldable Emulator
To get started, you need to install a foldable emulator. In this tutorial, you will use Microsoft’s Surface Duo 2 emulator to run the demo project. To run the emulator, you will learn how to install and run the foldable emulator on Android Studio.
To get started, you can follow instructions in the resources below:
Note: If you build with other foldable emulators, this project may not work properly on your emulator.
Download the Surface Duo Emulator
You can download the Surface Duo emulator image by following the steps below:
- Go to Microsoft Download Center.
- Click the Download button on the page.
- Choose a download option as in the figure below. You should select the option that matches your PC environment.
- Click the Next button and start downloading the emulator file.
Install the SDK and Emulator
After downloading the emulator, follow the instructions below to install it on your PC:
👉 Instructions for Mac:
- Open the SurfaceDuoEmulator.dmg file.
- Copy the .jar file and the contents of the emulator folder to a new location on your local hard drive. (The emulator folder name cannot contain periods.)
- Navigate to the SurfaceDuoEmulator folder where you copied the emulator files.
- Run the ./run.sh by double-clicking (or type it on the terminal) to start the installation process. This can take some time - but at the end of the process, you will see the emulator launch.
👉 Window Instructions:
- Unzip the downloaded file.
- Launch the installer.
- After completing the SDK setup, launch the Surface Duo Emulator via the start menu link.
Note: If the emulator does not start, you might need to update the pointer to your Android SDK installation.
Run the Surface Duo 2 Emulator on Android Studio
After running the Surface Duo 2 Emulator, you’ll see the result below on your PC:
The Surface Duo 2 emulator will automatically appear in the Android Studio available devices list like the figure below. Then, you can run this demo project on your Duo 2 emulator:
After running this demo project, you’ll see the result below:
Now, you can control the folding state and degree of the device on the Virtual sensors tab on the emulator controller:
Congratulations! 🎉 Now you can build projects for responsive UIs on the Surface Duo 2 emulator. Now let’s deep dive into the Jetpack WindowManager to see how the responsible application works.
The Jetpack WindowManager library makes it possible for application developers to support new device form factors and implement responsive UIs. If you want to use this library in your project, add the following dependency in the build.gradle file for your app:
The Jetpack WindowManager version 1.0.0 contains the following key features:
WindowMetricsCalculator: Interface to calculate the WindowMetrics for an Activity. It computes the size and position of the area the window would occupy with MATCH_PARENT width and height.
WindowInfoTracker: Provides the
WindowLayoutInfo, which contains display features of a window as an observable type such as Flow or RxJava.
WindowLayoutInfo: Contains the display features of a window to distinguish whether the window encompasses a fold or hinge.
FoldingFeature: Enables you to monitor the folded state of a foldable device to determine device postures.
This article will walk you through the key features of the Jetpack WIndowManager.
Set Up the Example UI
Before deep-diving into the WindowManager API, you need to set up an example layout on your Activity to observe the folded states and display configurations.
First, open the
activity_main.xml file and copy-paste the following code:
Next, enables the view binding in the build.gradle file with the following code:
Last, after clicking the sync button on Android Studio, initialize layouts with view binding with the following example:
Calculating the Screen Size with WindowMetricsCalculator
Now, let’s get the window size with the
WindowMetricsCalculator finds the maximum dimensions and position of an area for the window by calculating MATCH_PARENT width and height and any flags that allow the window to extend behind cutout areas.
First, you create an instance of the
WindowMetricsCaculator by using the
getOrCreate() static method:
Next, you can get the
WindowMetrics, which contains the size information of the
After building, you’ll get the following result:
Tracking Window With WindowInfoTracker
The WindowManager API provides tracking interfaces of the
WindowLayoutInfo, which contains the list of DisplayFeatures located within the window. We can observe the window layout changes by using the
windowLayoutInfo(activity) method, which provides the Flow of
WindowLayoutInfo across Activity recreations with the code below:
windowLayoutInfo(activity) method returns
Flow<WindowLayoutInfo>. We can observe the
WindowLayoutInfo in our Activity with the code below:
Building a Responsive Screen With FoldingFeature
The WindowManager API provides you with
FoldingFeature, which describes folds and hinges in the display. Its API provides access to important informatio related to the device methods below:
state(): Represents the current posture state of the foldable device such as STATE_FLAT and STATE_HALF_OPENED.
isSeparating(): Determines if a
FoldingFeatureshould split the window into multiple physical areas that users will view as logically separate.
FoldingFeature.Orientation.HORIZONTALif the FoldingFeature width is greater than the height, or
FoldingFeature provides two folding states: FLAT and HALF_OPENED.
FLAT means the posture state should be opened entirely flat, and
HALF_OPENDED means two logical screen areas should be folded in between 30 and 150 degrees as seen in the figure below:
FoldingFeature includes information like hinge orientation and the posture state which you’ve handled above, so we can use these values to check if the device is in tabletop mode or in book mode.
You can check if the device is in tabletop mode (half open with the hinge horizontal) with the code below:
You can check if the device is in book mode (half open with the hinge vertical) with the code below:
👉 You can find the full sample code in this post on GitHub.
For more information, you can also check out the references below:
- Support foldable and dual-screen devices with Jetpack WindowManager
- Unbundling the WindowManager
- Migrate your UI to responsive layouts
Using Jetpack WindowManager in Your App
Let’s take a look at how you can use these APIs in our next application. In the screenshot below, you’ll see the the real-world example of the responsive UI with Jetpack WindowManager:
Foldable devices can have flexible screen sizes depending on folded states, so we can build responsive layouts based on specific breakpoints following the different screens. Google's Material Design suggests some breakpoint guidelines about how content reflows on different screens.
Following the Material Design guidance, we can calculate the screen sizes and define breakpoints of the folding states with the code below:
If you're using Jetpack Compose to build UIs on your app, you can observe the screen size with the following example:
rememberWindowSizeClass() stores the
WindowSize object in the Composition, and it will be updated if screen size changes. So you can build the responsive UIs with the example below:
👉 You can find the full sample codes in this post on GitHub. This real-world example was built with Stream's Jetpack Compose API, so check it out if you have further interest.
In this article, you learned how to set up the foldable emulator and the Jetpack WindowManager to build responsive UIs. Foldable devices provide a larger screen, which provides a more immersive user experience that improves productivity. So you can provide better user experiences by supporting responsive UIs for your Android application.
Again, you can find the full sample codes with examples in this article on GitHub.
To learn more about the foldable devices and how to use them, take a look at this Learn about foldables piece.
In case you have any feedback on this article, reach the team on Twitter @getstream_io or the author
And as always, happy coding!
- Building a Video Chat App: WebRTC in Jetpack Compose (Part2)
- 6 Jetpack Compose Guidelines to Optimize Your App Performance
- Exploring Google’s Now in Android Open-Source Project
- Building a Video Chat App: WebRTC on Android (Part1)
- Setting Background Modes and Device Capability Privacies in iOS Apps
- Linting Documentation with Vale to Increase Quality & Consistency