Class Intents

java.lang.Object
com.codename1.intents.Intents

public final class Intents extends Object

The entry point for app intents: the capabilities your application offers to the outside world.

You do not register intents here. You declare them with com.codename1.annotations.AppIntent on a public static method and the build generates the table, because the platforms compile their intent catalogues into the native binary and a runtime-only registration could never reach them. What this class gives you is everything around that declaration: running an intent yourself, telling the system one just happened, publishing content to device search, and asking what the current platform can actually do.

// In your application code, once:
@AppIntent(value = "log_workout", title = "Log a workout",
        phrases = {"Log a workout in ${applicationName}"}, headless = true)
public static IntentResult logWorkout(
        @IntentParam("minutes") int minutes) {
    WorkoutStore.append(minutes);
    return IntentResult.spoken("Logged " + minutes + " minutes.");
}

// Later, after the user does it by hand, so the system learns to suggest it:
Intents.donate("log_workout", params);
What is honestly supported where

Ask, do not assume. areIntentsSupported() is true wherever intents can be exposed to the platform at all, but the interesting question is usually isVoiceInvocationSupported(), which is true on iOS and false on Android -- Android has no assistant contract that hands a typed result back to an app. Android gets launcher shortcuts and headless execution; it does not get Siri. The package documentation has the full table.

Zero cost when unused

Referencing this package is what makes the build inject the native plumbing. An application that never touches com.codename1.intents gets none of it and builds exactly as it did before.

  • Method Details

    • areIntentsSupported

      public static boolean areIntentsSupported()

      True when this platform can expose intents to the system.

      False does not make the API useless: invoke(String, Map) still runs your handlers in-process on every platform, because the dispatch table is generated code rather than a platform service. Only the projections outward -- voice, search indexing, shortcuts -- go quiet.

    • isHeadlessExecutionSupported

      public static boolean isHeadlessExecutionSupported()
      True when this platform can run an intent without bringing the app to the foreground.
    • isVoiceInvocationSupported

      public static boolean isVoiceInvocationSupported()

      True when a voice assistant can invoke intents here.

      This is the honest discriminator between the platforms. Branch on it rather than on areIntentsSupported() when deciding whether to tell a user they can talk to your app.

    • isIndexingSupported

      public static boolean isIndexingSupported()
      True when index(List) can publish content to a system-wide search index.
    • getDeclarations

      public static List<IntentDeclaration> getDeclarations()

      Every intent this application declares, from the build-time table and from registerDynamicIntent(DynamicIntent).

      The simulator's Intents window is built from exactly this list, which is what makes it trustworthy: it can only show what actually shipped.

    • getDeclaration

      public static IntentDeclaration getDeclaration(String intentId)

      The declaration with this id, or null.

      Parameters
      • intentId: the intent id
    • registerDynamicIntent

      public static void registerDynamicIntent(DynamicIntent intent)

      Declares a parameterization of an intent the application already declares -- a specific shortcut such as "reorder my usual", built from data only known once the app is running.

      It runs by running the intent it names, with the bound values filled in, which is what makes it invokable at all. It cannot introduce a new capability: the native catalogue is compiled into the app, so a genuinely new verb could never reach the platform.

      Ignored when the base intent is not declared, or when the id would shadow a declared one.

      Parameters
      • intent: the parameterization
    • getDynamicIntent

      public static DynamicIntent getDynamicIntent(String intentId)

      The parameterization registered under this id, or null when the id is a build-time declaration or nothing at all.

      Ports need this to resolve a donation: a shortcut outlives the process while a parameterization does not, so the shortcut has to record the base intent and the bound values rather than a runtime id nothing will recognise later.

      Parameters
      • intentId: the id to look up
    • invoke

      public static IntentResult invoke(String intentId, Map<String,Object> params)

      Runs an intent on the calling thread and returns its result.

      This is the in-app path -- your own code deciding to perform one of its declared capabilities -- and it works on every platform, including those with no intent support at all, because the dispatch table is generated code rather than a platform service.

      Platform-initiated invocations do not come through here; they arrive at dispatchInvocation(String, Map, IntentSource, boolean, IntentCompletion), which adds thread marshalling and an enforced deadline.

      The deadline on this path is a budget the handler may consult, not a cutoff: your own thread is blocked in this call, nothing else is waiting to report an outcome, and a handler that overruns has still done the work and produced the answer you asked for. So a late result is returned rather than discarded. Discarding is the right behaviour under dispatchInvocation(String, Map, IntentSource, boolean, IntentCompletion), where the framework has already told the platform the invocation failed and a second answer would be a protocol violation.

      Parameters
      • intentId: the declared intent id
      • params: parameter values keyed by name; may be null
      Returns

      the handler's result, or a failed result when no such intent exists

    • dispatchInvocation

      public static void dispatchInvocation(String intentId, Map<String,Object> params, IntentSource source, boolean headless, IntentCompletion completion)

      Framework/port entry point: runs an intent the platform asked for and reports the outcome exactly once.

      Ports call this after decoding their platform payload. It owns everything the ports should not each reinvent: queuing across a cold start, running the handler off the event dispatch thread, enforcing the deadline, and guaranteeing the completion fires once and only once.

      Parameters
      • intentId: the intent to run
      • params: parameter values keyed by name; may be null
      • source: where the invocation came from
      • headless: true when the app has no UI on screen
      • completion: notified with the outcome; may be null
    • setDefaultTimeout

      public static void setDefaultTimeout(int seconds)

      Overrides how long a handler may run before the framework gives up, for intents that did not state their own budget.

      Raising this is rarely the right fix. The platform's patience is not the constraint that matters -- a spoken interaction that takes ten seconds has already failed as an interaction. An intent that genuinely needs longer should return IntentResult.opens(String) and do the work in the app.

      Parameters
      • seconds: the default budget; values below 1 are ignored
    • getDefaultTimeout

      public static int getDefaultTimeout()
      The default handler time budget in seconds.
    • donate

      public static void donate(String intentId, Map<String,Object> params)

      Tells the system the user just performed this capability, so it can suggest or predict it later.

      Donate when the user does the thing in your app by hand. That is the signal the system learns from; donating on every intent invocation teaches it only that the user uses shortcuts.

      Callable from any thread. A no-op where unsupported.

      Parameters
      • intentId: the capability that was performed
      • params: the values it was performed with; may be null
    • index

      public static void index(List<AppEntity> entities)

      Publishes app content to the device's search index, replacing any entry carrying the same type and id.

      Threading

      A background thread is the right thread, not merely a permitted one. This writes through to the platform index and encodes any thumbnails on the way, so calling it on the event dispatch thread looks instantaneous in the simulator and stalls the UI on a device.

      Parameters
      • entities: the content to publish; null and empty are no-ops
    • index

      public static void index(AppEntity entity)

      Publishes a single entity. Shorthand for the list form.

      Parameters
      • entity: the content to publish
    • removeFromIndex

      public static void removeFromIndex(String entityType, String id)

      Removes one entry from the search index.

      Removal matters more than it looks. An index entry outlives the data behind it, so content the user deleted keeps appearing in device search and taps resolve to nothing until the app removes it.

      Parameters
      • entityType: the entity type id
      • id: the entity id
    • clearIndex

      public static void clearIndex(String entityType)

      Removes every indexed entry of one type, or everything this app indexed.

      Parameters
      • entityType: the type to clear, or null for all of this app's entries
    • queryEntities

      public static List<AppEntity> queryEntities(String entityType, String kind, String argument)

      Runs one of an entity type's declared queries.

      The platform calls this on its own when it has to disambiguate a parameter -- "which playlist?" -- and the simulator calls it to populate its picker, which is why the simulator exercises the real query rather than a stand-in.

      Parameters
      • entityType: the entity type id
      • kind: byId, suggested or search
      • argument: the id, the search text, or null
      Returns

      the matching entities, never null

    • asTools

      public static List<Tool> asTools()

      The intents that opted into Exposure.MODEL, projected down to com.codename1.ai.Tool so they can be handed to a language model or an MCP host.

      Nothing is exposed by calling this. It returns descriptions; the application decides whether to give them to a model, which is deliberately a separate act from declaring the intent, because a model calls a capability because it inferred it should rather than because a person asked by name.

      The projection is one-way and lossy on purpose. A Tool is stringly typed -- a JSON schema in, a JSON string out -- which is right for a model and wrong for the platform, where entity types let the system run its own picker before the handler is reached. So the richer declaration projects down to the weaker one, never the reverse.

      Returns

      one tool per model-exposed intent, never null

    • setSelectionHandler

      public static void setSelectionHandler(EntitySelectionHandler handler)

      Registers the single handler that receives taps on content published with index(List).

      Registration drains anything that arrived before it, which is the normal case: a tap in device search is frequently what started the process, so the selection is already waiting by the time your init() runs.

      Parameters
      • handler: the handler, or null to clear
    • dispatchSpotlightSelection

      public static void dispatchSpotlightSelection(String uniqueId)

      Framework/port entry point: the user opened an indexed item. The id is the composite the framework indexed under, type:id.

      Parameters
      • uniqueId: the identifier the platform handed back
    • dispatchUserActivity

      public static boolean dispatchUserActivity(String activityType, Map<String,Object> params)

      Framework/port entry point: a platform activity arrived that is not a web link. Returns true when this application claimed it.

      Answering honestly matters. Claiming everything would swallow handoff and third-party activities the app never declared, so an activity is claimed only when its type names an intent this application actually declares -- which is the shape the platform uses to continue a donated action.

      Parameters
      • activityType: the platform activity type
      • params: the activity payload, may be null
    • setDispatcher

      public static void setDispatcher(IntentDispatcher d)

      Internal: installs the build-time-generated dispatcher and drains any invocation that arrived before it. Invoked once during startup by the generated bootstrap; application code should not call this.

      Parameters
      • d: the generated dispatcher
    • publishPendingDeclarations

      public static void publishPendingDeclarations()

      Framework/port entry point: resolves the platform bridge, which publishes any declarations that were installed before one existed.

      The generated bootstrap installs the dispatcher before the port has booted -- from main() on iOS, and before startContext on Android -- so the first publication finds no bridge and is deferred. Something has to ask for the bridge afterwards or the platform never learns the catalogue, and on Android a request parked at a cold start is never judged, so the shortcut opens the app and runs nothing.

      Ports call this once the runtime is up. It is safe to call at any time and does nothing when there is nothing owed.

    • setBridge

      public static void setBridge(IntentBridge b)

      Framework/port/test entry point: overrides the bridge resolved from the platform port. Passing null restores platform resolution.

      Parameters
      • b: the bridge, or null