WindowState

Important

This article describes functionality and guidance that is in public preview and may be substantially modified before it's generally available. Microsoft makes no warranties, express or implied, with respect to the information provided here.

WindowState is a utility library for Jetpack Compose that helps you easily get details about the window state of dual-screen, foldable and large screen devices. This information is collected using Google's Jetpack Window Manager library.

The WindowState class provides information as a Compose state, and it includes properties like folding feature position/orientation, window size class, and window mode. The height and width window size classes are measured based on the official Android guidelines, and the current window mode is determined by folding feature and device orientation. As a reminder, window modes are display postures that take advantage of dual-screen and foldable form factors. There are four possible modes: Dual Portrait, Dual Landscape, Single Portrait, and Single Landscape.

Graphic of the four window modes/display postures

Add dependency

  1. Make sure you have mavenCentral() repository in your top level build.gradle file:

    allprojects {
        repositories {
            google()
            mavenCentral()
         }
    }
    
  2. Add the following dependency to the module-level build.gradle file (current version may be different from what's shown here):

    implementation "com.microsoft.device.dualscreen:windowstate:1.0.0-alpha07"
    
  3. Also ensure the compileSdkVersion is set to API 33 and the targetSdkVersion is set to API 32 or newer in the module-level build.gradle file.

    android { 
        compileSdkVersion 33
    
        defaultConfig { 
            targetSdkVersion 32
        } 
        ... 
    }
    

Use WindowState in your project

To use the library in a Compose project, call the rememberWindowState() function from your MainActivity. This method returns a WindowState object that you can pass into your top-level composable as a state.

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        setContent {
            ExampleAppTheme {
                ExampleApp(rememberWindowState())
            }
        }
    }
}

Inside your composables, you can then access the different properties of the WindowState object to make choices about your app's layout. In the example below, the isDualScreen() method is used to choose between two different layouts, one for single screen devices and one for dual-screen devices.

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

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

Calculate pane sizes

Besides exposing Jetpack Window Manager and window size class information, the WindowState class also calculates pane sizes for two pane layouts. If the TwoPaneLayout component isn't suitable for your project, then you can use the largeScreenPane1Weight, pane1SizeDp, and pane2SizeDp properties to set up your own custom layouts:

fun ExampleApp(windowState: WindowState) {
    windowState.largeScreenPane1Weight = 0.3f
    
    CustomListDetailLayout(
        pane1Width = windowState.pane1SizeDp.width,
        pane2Width = windowState.pane2SizeDp.width,
        list = { ListContent() },
        detail = { DetailContent() }
    )
}

Pane sizes are calculated based on the following logic:

  • If a window contains a separating folding feature:
    • Calculate pane size based on the boundaries of the folding feature
  • If a window is considered large (EXPANDED width and at least MEDIUM height size classes):
    • Calculate pane size based on the largeScreenPane1Weight property, window size, and device orientation
  • If not foldable or large screen:
    • Only one pane should be shown, so return pane size 0

Note that these logic checks are performed in order, so it's possible for a large foldable device to be considered a large screen if its folding feature is not separating, meaning the device does not have a hinge and is flat.

Important

The largeScreenPane1Weight property must be set before calling pane1SizeDp or pane2SizeDp for the weight to be used in the calculations.

We recommend using the properties described above to provide support for both large screens and foldables. However, if you only need to use pane sizes when a separating folding feature is present, then you can use the foldablePane1SizeDp and foldablePane2SizeDp properties instead:

fun ExampleApp(windowState: WindowState) {
    CustomCompanionPaneLayout(
        pane1Size = windowState.foldablePane1SizeDp,
        pane2Size = windowState.foldablePane2SizeDp,
        game = { GameScreen() },
        controls = { ControlPanel() }
    )
}

Samples

To see more examples of how to use WindowState, check out the library sample and our Compose samples.