windowinsets.info

Developer guide

Foldables: detecting the fold

How Android reports a fold

A Galaxy Z Fold or Flip reports its hinge as a FoldingFeature, one of the display features in WindowLayoutInfo from Jetpack WindowManager. It is not a window inset: the fold never changes systemBars or displayCutout, so pad for insets and lay out around the fold separately. Each feature has:

  • state: FLAT (fully open) or HALF_OPENED (partly folded).
  • orientation: VERTICAL for a book fold such as Galaxy Z Fold, HORIZONTAL for a clamshell such as Galaxy Z Flip.
  • isSeparating: whether the fold splits the window into two logical areas. It is always true while HALF_OPENED.
  • occlusionType: NONE or FULL, whether the fold hides part of the display.
  • bounds: the fold's rectangle in window coordinates (px).

A closed device reports no folding feature. The app then runs on the cover display, which is a separate screen with its own insets. On this site, choose Cover or Main on a foldable's page to see each one.

The recordings below show what each posture reports as the hinge moves through 0°, the partly open range and 180°:

Galaxy Z Fold8 · 0°ClosedThe app runs on the cover screen, which has no FoldingFeature.
Galaxy Z Flip8 · 0°ClosedThe app runs on the cover screen, which has no FoldingFeature.

Recorded from this site's 3D renderer with the measured cover and inner displays. The angle where the animation turns from the cover to the inner display is illustrative; real devices switch displays at their own angle.

Jetpack Compose

Compose Material 3 Adaptive (androidx.compose.material3.adaptive:adaptive) provides collectFoldingFeaturesAsState(), which recomposes whenever the fold changes. The posture checks below follow Android's Make your app fold aware guide.

Kotlin
@Composable
fun FoldAwareScreen() {
  val foldingFeatures by collectFoldingFeaturesAsState()
  val fold = foldingFeatures.firstOrNull()

  val isTabletop = fold?.state == FoldingFeature.State.HALF_OPENED &&
    fold.orientation == FoldingFeature.Orientation.HORIZONTAL
  val isBook = fold?.state == FoldingFeature.State.HALF_OPENED &&
    fold.orientation == FoldingFeature.Orientation.VERTICAL

  when {
    isTabletop -> TabletopLayout(foldBounds = fold!!.bounds) // content above, controls below
    isBook -> TwoPaneLayout(foldBounds = fold!!.bounds)      // one pane on each side
    else -> SinglePaneLayout()
  }
}

If you only need the posture, currentWindowAdaptiveInfoV2().windowPosture exposes it directly, for example windowPosture.isTabletop.

Views

With Views, collect WindowInfoTracker (androidx.window:window) while the activity is started:

Kotlin
override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
      WindowInfoTracker.getOrCreate(this@MainActivity)
        .windowLayoutInfo(this@MainActivity)
        .collect { layoutInfo ->
          val fold = layoutInfo.displayFeatures
            .filterIsInstance<FoldingFeature>()
            .firstOrNull()
          updateLayoutForFold(fold) // null when flat without a fold or closed
        }
    }
  }
}

Hinge angle

FoldingFeature does not expose the angle. If you need it, read Sensor.TYPE_HINGE_ANGLE (API 30+) through SensorManager. Reporting ranges and accuracy vary by device, so prefer state and orientation for layout decisions. The hinge slider on this site's foldable pages is a visualization; the measured insets come from captures of the open and closed displays.

For design guidance on cover and inner screens, see Samsung's Designing for foldables, and for app-level patterns, Android's Learn about foldables.

Found an issue or want to contribute?

Open an issue or pull request on GitHub. If you have a device and want to add insets data, use InsetsProbe and share your JSON.