Docs

Documentation versions (currently viewingVaadin 25)
Documentation translations (currently viewingEnglish)

Wake Lock

Using the Wake Lock API to keep the device screen on from the server.

The WakeLock API gives server-side Java code access to the browser Screen Wake Lock API. It keeps the screen from dimming or locking while the lock is held — useful for dashboards left on display, kiosks, presentations, navigation, media playback, and similar always-on views. It exposes two static entry points — WakeLock.request() to acquire and WakeLock.release() to release — and a pair of reactive signals for observing state and availability.

Note
The Screen Wake Lock API requires a secure context (HTTPS), except on localhost during development. Safari supports it from version 16.4. The browser may also release the lock at any time — for example, when the tab becomes hidden, on low battery, or under operating-system power-saving rules — and the application has no control over that. Use WakeLock.availabilitySignal() to gate UI controls up front and WakeLock.activeSignal() to react to spontaneous releases.

Acquiring a Wake Lock

Use WakeLock.request() to ask the browser to keep the screen on. The call is asynchronous and fire-and-forget: by the time the method returns the browser has not necessarily granted the lock yet. Observe WakeLock.activeSignal() for the actual state — see Observing Active State.

Source code
Java
Button keepOn = new Button("Keep screen on", e -> WakeLock.request());

The framework adds two conveniences on top of the raw browser API:

  • The browser releases the lock automatically when the tab becomes hidden. The client transparently re-acquires it when the tab becomes visible again, so a single request() call covers the lifetime of the view; no visibilitychange listener is needed.

  • Calling request() while a lock is already held is a no-op.

For persistent failures — the API is unavailable, the origin is insecure, or the browser refuses with NotAllowedError — there is a request(onError) overload covered in Handling Errors.

Releasing a Wake Lock

Call WakeLock.release() to drop the current lock and stop re-acquiring it on subsequent visibility changes. The call is idempotent — calling it when no lock is held is a no-op.

Source code
Java
Button stop = new Button("Allow screen off", e -> WakeLock.release());

Observing Active State

WakeLock.activeSignal() returns a read-only Signal<Boolean> that reflects whether the browser is currently holding the wake lock for this UI. It starts as false, flips to true once the browser confirms a request, and flips back to false whenever the browser releases the lock — explicitly through release(), automatically when the tab becomes hidden, or because the browser dropped it for power-saving or low-battery reasons. When the tab is shown again the client re-requests the lock if release() has not been called, so the signal flips back to true shortly after.

Use Signal.effect() to react to changes — for example, to reflect the wake-lock state in the browser’s document title so a hidden tab makes its stay-on mode obvious:

Source code
Java
Signal.effect(this, () -> {
    Page page = UI.getCurrentOrThrow().getPage();
    page.setTitle(WakeLock.activeSignal().get()
            ? "Live Dashboard (stay-on)"
            : "Live Dashboard");
});

When a component property accepts a signal directly, prefer that binding over Signal.effect(). The canonical "Start" / "Stop" toggle pair binds the signal to button visibility:

Source code
Java
Button keepOn = new Button("Keep screen on", e -> WakeLock.request());
keepOn.bindVisible(Signal.not(WakeLock.activeSignal()));

Button allowOff = new Button("Allow screen off", e -> WakeLock.release());
allowOff.bindVisible(WakeLock.activeSignal());

Handling Errors

Pass a SerializableConsumer<WakeLockError> to WakeLock.request() to be notified when the browser permanently refuses the request. The callback fires on the UI thread. Switch on err.code() to get a typed WakeLockErrorCode — the switch is exhaustive at compile time:

Source code
Java
WakeLock.request(err -> {
    String userMessage = switch (err.code()) {
        case UNSUPPORTED ->
            "Keep-screen-on isn't available in this browser.";
        case NOT_ALLOWED ->
            "The browser refused to keep the screen on.";
        case UNKNOWN ->
            "Couldn't keep the screen on.";
    };
    Notification.show(userMessage);
});

The callback is meant for persistent failures — the kinds that should surface in the UI, typically by re-enabling a "Keep screen on" toggle and showing a message. It is not invoked when the lock is merely deferred (tab hidden until the user returns) or when the browser temporarily releases the lock for power-management reasons; observe activeSignal() for those.

When availability is already known to be UNSUPPORTED (see Checking Availability), the error callback fires synchronously, without a server-to-client round-trip. This makes it cheap to wire the toggle up unconditionally and rely on the error callback to degrade gracefully on insecure origins.

For diagnostics, log err.message() alongside the code — it is a free-form browser string and isn’t meant for end users.

Checking Availability

WakeLock.availabilitySignal() returns a Signal<WakeLockAvailability> reporting whether the Screen Wake Lock API is usable in the current page context. Reading the signal does not call the browser API — it reports whether a subsequent request() has any chance of succeeding.

SUPPORTED

The browser exposes the API and the page is served from a secure context. Render the "keep screen on" toggle.

UNSUPPORTED

The browser does not implement the API, or the page is served over an insecure connection. No user action changes this — hide the toggle entirely.

UNKNOWN

The browser has not yet reported a value. This is the seed state during the brief window between UI attach and bootstrap completion; in practice applications see it only as a transient state.

Use bindVisible() to render the toggle only when the API is usable:

Source code
Java
Button keepOn = new Button("Keep screen on", e -> WakeLock.request());
keepOn.bindVisible(WakeLock.availabilitySignal()
        .map(a -> a == WakeLockAvailability.SUPPORTED));

Calling from Background Threads

The static entry points above resolve the target UI through UI.getCurrent(), which only works on a request-handling thread. Background threads (executors, scheduled tasks, push handlers) need to pass the UI explicitly. Every entry point has an overload accepting a UI argument: request(ui), request(onError, ui), release(ui), activeSignal(ui), and availabilitySignal(ui).

Source code
Java
@Override
protected void onAttach(AttachEvent event) {
    UI ui = event.getUI();
    ScheduledFuture<?> task = scheduler.schedule(
            () -> WakeLock.request(ui),
            5, TimeUnit.SECONDS);
    addDetachListener(e -> task.cancel(false));
}

The error callback on request(onError, ui) is still invoked on the UI thread, so it can update components directly without an ui.access() wrapper.

Limitations and Caveats

  • A secure context is required (HTTPS, or localhost during development).

  • Safari supports the API from 16.4; older versions report UNSUPPORTED through availabilitySignal().

  • The browser may release the lock at any time — low battery, power-saving mode, or operating-system policy. activeSignal() reflects the change so the UI can react.

  • Wake lock state is per-UI (per tab). Each tab needs its own request(); releasing in one tab does not affect another.