Jetpack Window Manager for foldable devices

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.

Jetpack Window Manager (currently in alpha) provides a standard API for working with all foldable devices. It contains two main APIs:

  • DisplayFeature - Identifies disruptions in the continuous flat screen surface such as hinges or folds.
  • DeviceState - Provides the current posture of the device from a list of defined postures (e.g. CLOSED, OPENED, HALF_OPENED, etc.).

Read more about developing for foldables in the Android docs.

Tip

The controls and helper classes in the Surface Duo dual-screen library work with Window Manager. Follow the instructions to add the correct packages to your app project.

To use the Window Manager directly in your code, follow the instructions below:

Add dependency

To add the Jetpack Window Manager library, update your build.gradle file to include this dependency:

dependencies {
    implementation "androidx.window:window:1.0.0-alpha01"
}

Note

The library name includes "alpha" - the Window Manager APIs are currently still in preview and could change prior to becoming stable.

Use Window Manager in your code

  1. In the MainActivity class, declare a variable for the window manager:

    class MainActivity : AppCompatActivity() {
       private lateinit var wm: WindowManager
    

    Ensure that the correct import androidx.window.WindowManager is added to the top of the file.

  2. Initialize the window manager in your activity's OnCreate:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        wm = WindowManager(this, null)
    
  3. Now create function that extends from Executor so we provide it to the callback as the first parameter and it will be invoked using it. We are going to create one that runs on the UI thread, you can create a different one that doesn’t run on the UI thread if required.

    private fun runOnUiThreadExecutor(): Executor {
       val handler = Handler(Looper.getMainLooper())
       return Executor() {
           handler.post(it)
       }
    }
    
  4. Use the Window Manager instance to register for device state changes (registerDeviceStateChangeCallback) in OnCreate. The activity should have a TextView called device_state_change_text:

    wm.registerDeviceStateChangeCallback(
        runOnUiThreadExecutor(),
        { deviceState ->
            device_state_change_text.text = "Posture: ${deviceState.toString()}"
        })
    
  5. In an OnAttachedToWindow override, register the registerLayoutChangeCallback handler. The activity should have a TextView called layout_change_text:

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        wm.registerLayoutChangeCallback(
               runOnUiThreadExecutor(),
           { windowLayoutInfo ->
               layout_change_text.text = windowLayoutInfo.toString()
           })
        }
    

    This cannot be called in OnCreate as the the activity won't be attached to the window yet, and will crash.

  6. When this code is run, the activity will update with the current device posture and display features (if spanned across the fold or hinge).

Resources