Edge-to-Edge for Fullscreen PWAs on Android

โšก Chromium ๐Ÿ”ง C++ / Java / Android ๐Ÿ‘ค Helmut Januschka

Getting installed fullscreen PWAs to actually reach into the notch

Status: ๐ŸŽ‰ Landed

Update 15.7.2026: โœ… The final CL of the stack landed - fullscreen PWAs going edge-to-edge is now available in Chrome Canary for Android behind chrome://flags/#web-app-short-edges-cutout-mode.

The Problem

Install a PWA that asks for the whole screen and it still does not get the whole screen.

The canonical repro is the interop viewport demo. It is a PWA with:

Install it, launch it, and on Android it stops short of the status-bar / camera-notch region instead of drawing under it. A regular web page that calls document.documentElement.requestFullscreen() goes truly edge-to-edge, but the installed PWA does not.

This had been reported by authors repeatedly - the expectation is simple: a fullscreen PWA with viewport-fit=cover should cover the cutout area just like native fullscreen does.

Bug: 407420295

The Investigation

Android exposes LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES to let a window lay out into the display cutout on the short edges of the screen. Native fullscreen paths use it; the web app / activity flow did not opt in, so the PWA window was laid out with the default cutout mode and stayed below the notch.

Getting from "default" to "short edges" was not a one-line change. The edge-to-edge state on Android is plumbed through several layers - an edge-to-edge manager, a display cutout controller, and the token bookkeeping that decides when the decor fits system windows. The cutout mode had to be threaded through all of them, gated behind a flag, without disturbing the existing edge-to-edge behavior that other surfaces rely on.

The Fix

The change landed as a stack so each layer could be reviewed and de-risked on its own:

The controller-side CL adds support for LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES behind a delegate bit that defaults to false - a no-op on its own. The webapp/activity-flow CL is the one that actually flips fullscreen PWAs into short-edges mode. The rename CL is mechanical cleanup, moving callers off the deprecated releaseSetDecorFitsSystemWindowToken shim to the canonical releaseEdgeToEdgeToken.

The Reland Saga

The controller-side plumbing CL earned itself a small reland history. The code was fine; the tests were the problem. Android form factors are messier than they look:

With the plumbing finally stable, the last CL flipped the actual behavior on for webapp and activity flows - and that is the piece that just landed.

Trying It in Canary

On Chrome Canary for Android:

  1. Open chrome://flags/#web-app-short-edges-cutout-mode and enable it
  2. Install a PWA with display: fullscreen (or display_override: ["cover-display-cutout"]) and viewport-fit=cover - e.g. one of the sampler demos
  3. Launch it from the home screen - it now draws into the notch, with env(safe-area-inset-top) reporting the cutout height

Before and After

Captured on-device from the APK sampler. Unpatched stops below the cutout, patched draws under it.

Standalone PWA - Before
Standalone PWA unpatched
Standalone PWA - After
Standalone PWA patched

The demo page self-reports its verdict: it reads display-mode, innerHeight vs screen.height, and env(safe-area-inset-top) and prints PASS (edge-to-edge active) only when the window really extends under the cutout. In the "after" shot, safe-area-inset-top reports the actual 48px cutout height instead of 0.

The sampler covers the other flows too (fullscreen display mode, backswipe, and the requestFullscreen() control case that already worked), plus a no-notch gallery proving the change is a no-op on devices without a cutout, and downloadable APKs for each case.

Thanks

Big thanks to reviewers Dan Murphy and Charles Hager for the patient back-and-forth across the stack - the layered, flag-gated approach is a direct result of their guidance on keeping a shared Android codepath safe.