Wake Lock API
- Acquiring a Wake Lock
- Releasing a Wake Lock
- Observing Active State
- Handling Errors
- Checking Availability
- Calling from Background Threads
- Limitations and Caveats
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; novisibilitychangelistener 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.getCurrent().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
localhostduring development). -
Safari supports the API from 16.4; older versions report
UNSUPPORTEDthroughavailabilitySignal(). -
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.