public final class Surfaces
- Object
- Surfaces
The static entry point for external surfaces: home-screen widgets and live activities – the
two faces of one concept, a live source of information that resides outside your app. Declare
your widget kinds and register an action handler in init(), then publish content whenever
your data changes:
Surfaces.registerWidgetKind(new WidgetKind("delivery_status")
.setDisplayName("Delivery").setDescription("Track your order"));
Surfaces.setActionHandler(evt -> showOrder(evt.getParams()));
...
Surfaces.publish("delivery_status", new WidgetTimeline()
.setContent(layout).addEntry(new Date(), state));
How surfaces render
Surfaces render while your app process may be dead: the published timeline is serialized (a
JSON descriptor plus PNG blobs) and persisted where the platform renderer can reach it – the
iOS widget extension, the Android widget provider or a desktop surface window. Layouts embed
${key} placeholders resolved from each timeline entry’s state map, and SurfaceDynamicText
countdowns tick natively on the OS clock with no app wakeups. To refresh content periodically
implement com.codename1.background.BackgroundFetch and re-publish there.
Widget kinds must also be declared at build time in the project’s surfaces.json resource –
the platform widget galleries are compiled into the native app. See the package documentation.
Zero cost when unused
Merely referencing this package makes the build inject the native plumbing (the WidgetKit
extension and app group on iOS, the widget receivers on Android). Apps that never touch
com.codename1.surfaces get none of it. On the simulator the Widgets preview window renders
published surfaces; on unsupported ports the API is an inert no-op.
Methods
Inherited methods
Method details
areWidgetsSupported
public static boolean areWidgetsSupported()Returns
registerWidgetKind
public static void registerWidgetKind(WidgetKind kind)init(). The id must
match a kind declared in the project’s surfaces.json build-time manifest; a mismatch logs
a prominent warning on supporting platforms.Parameters
kindWidgetKind- the kind declaration
getRegisteredKinds
public static List<WidgetKind> getRegisteredKinds()setDiagnosticsEnabled
public static void setDiagnosticsEnabled(Boolean enabled)Overrides whether the simulator-only surface diagnostics run. They are on in the simulator
and off everywhere else, which is almost always what you want: they catch usage that works
in the simulator but stalls or silently does nothing on a device (rasterizing a surface
image on the EDT, publishing to a kind that was never registered, republishing far past the
platform’s reload budget), and they cost nothing in a shipped build because they never run
there. Diagnostics that are certain to misbehave on a device throw IllegalStateException;
the rest log a one-time warning.
Pass null to restore the default behaviour. Turning them off is a last resort for a case a check gets wrong – please report it if you hit one.
Parameters
enabledBoolean- true to force diagnostics on, false to force them off, null for the default
isDiagnosticsEnabled
public static boolean isDiagnosticsEnabled()Returns
publish
public static void publish(String kindId, WidgetTimeline timeline)Publishes a widget kind’s content, atomically replacing any previously published timeline and asking the platform to re-render the kind’s widget instances. A no-op on platforms without widget support.
Threading
Callable from any thread – including
com.codename1.background.BackgroundFetch#performBackgroundFetch(long, com.codename1.util.Callback)
callbacks while the app UI is not running (on Android the fetch runs in a background
service with no Activity at all). Publishing is data-only: the timeline is serialized,
persisted where the platform renderer can reach it and the renderer is poked
asynchronously. Implementing background fetch and re-publishing there is the intended way
to keep widgets fresh; see the com.codename1.surfaces.spi package documentation for the
per-platform background update story.
A background thread is the RIGHT thread, not merely a permitted one. On a device this
writes the payload into the shared container and makes a synchronous native call, and any
SurfaceImage holding an Image that is not an EncodedImage is rasterized here – on
iOS that encode blocks the caller on the platform UI thread while the pixels are read back
off the GPU. Publishing on the EDT therefore stalls the UI on hardware while looking
instantaneous in the simulator. Pass EncodedImages and publish off the EDT; the simulator
diagnostics flag both mistakes (see setDiagnosticsEnabled(Boolean)).
Parameters
kindIdString- the widget kind id
timelineWidgetTimeline- the content to publish
publishRemote
public static void publishRemote(String kindId, String timelineJson)Push-framework entry point for a server-rendered timeline descriptor. The descriptor uses
the same wire format as publish(). The descriptor is persisted directly once the
Codename One runtime receives it. A platform that doesn’t run application code for a
background push applies it when the application next starts or resumes.
Equivalent to publishRemote(String,String,Map) with no imagery. A descriptor that
references an image by name renders a gap where it should be, so prefer the overload
whenever the artwork travelled with the descriptor.
publishRemote
public static void publishRemote(String kindId, String timelineJson, Map<String, byte[]> images)As publishRemote(String,String), with the imagery the descriptor references.
A timeline’s node tree names its images rather than embedding them – SurfaceSerializer
hashes the bytes and puts the hash on the wire – so a descriptor that arrived from
somewhere else is only complete if its side-map arrived too. Without this overload
publishRemote discarded the imagery unconditionally and every referenced image rendered
as a gap.
The two callers are a server push and the phone-to-watch mirror, which forwards a
phone-side publish() of a watch-bearing kind to the watch. Both are the same operation:
a descriptor produced elsewhere, applied here.
Parameters
kindIdString- the widget kind id
timelineJsonString- the serialized timeline, in the same wire format
publish()produces imagesMap<String, byte[]>- the referenced images by name, or an empty map when the descriptor names none
reloadWidgets
public static void reloadWidgets(String kindId)Parameters
kindIdString- the kind to reload, or null for all kinds
getInstalledWidgetCount
public static int getInstalledWidgetCount(String kindId)Parameters
kindIdString- the widget kind id
Returns
setActionHandler
public static void setActionHandler(SurfaceActionHandler handler)Parameters
handlerSurfaceActionHandler- the handler, or null to clear
dispatchAction
public static void dispatchAction(String source, String actionId, Map<String, Object> params)Parameters
sourceString- the widget kind id or live activity type
actionIdString- the action id of the tapped node
paramsMap<String, Object>- the action parameters, may be null
setBridge
public static void setBridge(SurfaceBridge b)Parameters
bSurfaceBridge- the bridge, or null to resolve from the platform again