January 20th, 2022

Jetpack Compose WindowState preview

Kristen Halper
SW/FW Engineer

Hello Jetpack Compose developers!

This week, we’d like to announce the release of WindowState, a new utility library that’s part of our Compose SDK. Our goal was to provide easy access to all the window information provided by the Jetpack Window Manager library and to simplify the logic required to enhance your apps for large screens and foldables.

Library overview

The main features of the library are the WindowState data class, which contains three categories of information, and the rememberWindowState() helper function.

data class WindowState(
   val hasFold: Boolean = false,
   val isFoldHorizontal: Boolean = false,
   val foldBounds: Rect = Rect(),
   val foldState: FoldState = FoldState.FLAT,
   val foldSeparates: Boolean = false,
   val foldOccludes: Boolean = false,
   val windowWidth: Dp = 0.dp,
   val windowHeight: Dp = 0.dp,
)
@Composable
fun Activity.rememberWindowState(): WindowState

Figure 1. Constructor for the WindowState data class and function signature for rememberWindowState().

Fold properties

The WindowState class encapsulates all of the fold data that can be extracted from Jetpack Window Manager’s WindowLayoutInfo and FoldingFeature classes. As shown above, the properties passed into the WindowState constructor are all publicly accessible values, and we also added a few other properties that might be helpful in your app’s logic:

val foldablePaneWidth: Int

The foldablePaneWidth property returns the width (in pixels) of a single pane of a dual-screen or foldable device when the device is in dual-screen mode. If the device is in single-screen mode, or the device is a regular single-screen device, the return value will be 0. (Note: the return value is based on the assumption that the developer wants two panes of equal width)

val foldSize: Int

The foldSize property returns the width (in pixels) of the hinge of dual-screen device or the folding line of foldable device when the device is in dual-screen mode. If the device is in single-screen mode, or the device is a regular single-screen device, the return value will be 0.

Window size

The WindowState class also contains properties related to large screens. As you can see in constructor, the class accepts the height and width of the current window, then uses this information to calculate the corresponding WindowSizeClass for both window dimensions. Our implementation follows the official Android guidance for how to partition windows into the three size classes.

The window dimensions passed into the constructor are public, so these can be accessed at any time. In addition, the calculated size classes for the window can be accessed via the following getters:

fun widthSizeClass(): WindowSizeClass
fun heightSizeClass(): WindowSizeClass

Figure 2. Getter methods for window width and height size classes

Window mode

Lastly, WindowState makes it simple to calculate the current window mode, which is helpful when making decisions about your app’s layout. We’ve provided several properties and getters that help you determine which of the four window modes is currently in use:

val windowMode: WindowMode
fun isDualScreen(): Boolean
fun isDualPortrait(): Boolean
fun isDualLandscape(): Boolean
fun isSinglePortrait(): Boolean
fun isSingleLandscape(): Boolean

Figure 3. Public properties and getter methods for window mode information

To make the library as flexible as possible, we’ve given you the option to access the windowMode directly, which is useful for choosing between different layouts in a when block, or to simply ask whether the current window is in a specific mode, which is useful as a state to pass to composables.

Get started

Add to your project

To start using the WindowState library, follow these steps:

  1. Add the following dependency to your build.gradle file:

    implementation "com.microsoft.device.dualscreen:windowstate:1.0.0-alpha1"
  2. Call the rememberWindowState() function from your MainActivity and pass the result into your top-level composable

    class MainActivity : ComponentActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            
            setContent {
                ExampleAppTheme {
                    ExampleApp(rememberWindowState())
                }
            }
        }
    }
  3. Access the WindowState properties within your composables and use them to make layout decisions

    fun ExampleApp(windowState: WindowState) {
        if (windowState.isDualScreen())
            DualScreenAppContent(windowState.foldSize)
        else
            SingleScreenAppContent()
    }

For more detailed instructions and API reference information, please refer to the WindowState README.

Example usage

To see some of examples of how to use the library, you can check out a few different samples.

In the SDK repo, we created a small sample to showcase all of the properties that can be accessed via WindowState.

Figure 4. Screenshots of the library sample in single portrait mode and dual landscape mode on the Surface Duo emulator.

WindowState sample output on three different sized device emulators

Figure 5. Screenshots of the library sample on other large screen and foldable emulators (clockwise from the top: 6.7 Horizontal Fold-in, 7.6 Fold-in with outer display, Pixel C).

We’ve also updated each of our Compose samples to use WindowState. For an example of how foldable properties can be used, check out the updated TwoPage sample. To see how you can use windowMode inside a when block, check out the updated CompanionPane sample. If you would prefer to check whether the window is in a specific mode, you can refer to the ListDetail sample to see how isDualPortrait() is used.

In our samples, we definitely noticed that using WindowState helped simplify our app logic, and we hope it does the same for you! Since this is the first version of the library, please don’t hesitate to send us feedback on how you think future versions could be improved 😊

Resources and Feedback

Check out the Surface Duo Jetpack Compose developer documentation and past blog posts for links and details on all our samples. You can find our Jetpack Compose samples on GitHub.

If you have any questions, or would like to tell us about your apps, use the feedback forum or message us on Twitter @surfaceduodev.

Finally, join us live on Twitch at 11am PST to discuss the WindowState library, Jetpack Window Manager, and any other Surface Duo developer questions you might have.

Author

Kristen Halper
SW/FW Engineer

Works in the Surface Duo Developer Experience team to help with all aspects of dual-screen SDK development and customer engagement.

0 comments

Discussion are closed.