Documentation

$window, $display and $metrics

The app's own window, as state: its color mode, its blur and dim, its refresh rate, and how its frames are doing.

Why these exist

A Compose screen has no way to reach its own Window. Anything that wants to set a color mode, ask for a refresh rate or blur what is behind a dialog has to find the Activity, keep a reference to it, and drop that reference before it leaks. Every app that does this invents the same plumbing. These three objects are that plumbing, generated once per app and attached to the Activity for you.

They are objects, not calls. $display and $window are substituted wherever they appear, so they work in a click handler and a function body as well as in markup.

$display

val mode = $display

mode.current      // "default" | "wide" | "hdr" | "hdr10"
mode.available    // can this display report an HDR/SDR ratio?
mode.hdrSdrRatio  // 1.0 outside the HDR modes
mode.headroom     // what the window asks for, as a multiple of SDR white (API 34)
mode.set("hdr")

current, available and hdrSdrRatio are state. set asks the window for a mode; what you get is what current reports afterwards, which on a panel without HDR is nothing. Hide the control behind available rather than disabling it: on such a display an HDR button does not fail, it succeeds and changes nothing.

$display is Android's window color mode and HDR headroom. It is not the web's dynamic-range media query, which only reads the capability; this one sets it.

$window

$window.dim = 0.2f            // dim what is behind the window, 0..1
$window.blurBehind = 10       // blur it, in dp; $window.blurSupported says whether it will
$window.backgroundBlur = 20   // blur the window's own background
$window.frameRate = 1f        // ask for a refresh rate; 0 means no preference
$window.displayRefreshRate    // what the display is actually doing, as state

The writes go to the Activity's window at the moment they run. The reads are state, so a <Text> showing displayRefreshRate follows the panel as it switches between 60 and 120.

$metrics

val fx = $metrics

fx.frameTimeMs    // average over the last sixty frames
fx.gpuTimeMs
fx.worstFrameMs
fx.dropped        // frames that missed the budget, in the window
fx.jankPercent
fx.totalFrames
fx.budgetMs       // 16.67 at 60 Hz, 8.33 at 120

Every field is state, so an overlay that shows them redraws as the numbers move. whitehall bench measures the same thing from outside, as a gate; this is the app showing it to itself.

Try it

Window.wh
import $lib.components.ui.Button

val mode = $display

<Column class="gap-8">
  <Text>{mode.current}</Text>
  <Row class="gap-4">
    <Button onClick={() => mode.set("default")}>sRGB</Button>
    <Button onClick={() => mode.set("wide")}>P3</Button>
    <Button onClick={() => mode.set("hdr")} disabled={!mode.available}>HDR</Button>
  </Row>
</Column>
Kotlin waiting
Scroll into view to compile.

$display is the window's color mode as state. Reading current or available in markup subscribes to it; set() asks the window for a mode.

See Also