Class CompanionDevices

java.lang.Object
com.codename1.nearby.companion.CompanionDevices

public final class CompanionDevices extends Object

Companion-device association: the OS-managed relationship between this app and one particular accessory.

Associating is not pairing. It is the app telling the operating system "this is my device", through a chooser the OS draws and the user picks from, and getting back privileges that an ordinary Bluetooth scan does not carry:

  • The OS watches for the device instead of the app. startObservingPresence(String) asks the platform to wake the app when the accessory comes into range, which replaces a scan the app would otherwise run -- and pay for in battery -- forever.
  • Scanning stops needing location permission. On Android, finding your own associated device is not the same question as finding out where the user is, and the platform treats it accordingly.
  • The user sees one honest prompt naming one device, instead of a blanket "this app wants to find nearby devices".
AssociationRequest req = new AssociationRequest.Builder()
        .addFilter(DeviceFilter.bleService("180D"))
        .build();
CompanionDevices.associate(req).onResult((device, err) -> {
    if (err == null) {
        Preferences.set("sensor", device.getId());
        CompanionDevices.startObservingPresence(device.getId());
    }
});
Platform support
  • Android -- CompanionDeviceManager, with presence observation.
  • iOS -- AccessorySetupKit, on iOS 18 and later. The picker returns an accessory the app may then talk to over com.codename1.bluetooth without holding the blanket Bluetooth authorization. Earlier iOS versions report isSupported() false; there the app scans with com.codename1.bluetooth as before.
  • Simulator, desktop and JavaScript -- a simulated association store reporting NearbyAvailability.LOCAL_ONLY.
  • Every other port -- unsupported, and every call fails fast.
  • Method Details

    • isSupported

      public static boolean isSupported()
      true when this port can associate companion devices.
    • getAvailability

      public static NearbyAvailability getAvailability()

      How usable association is right now.

      Returns

      the current availability, never null

    • associate

      public static AsyncResource<CompanionDevice> associate(AssociationRequest request)

      Shows the system device chooser and associates whatever the user picks.

      This always involves the user -- there is no way to associate silently on either platform, by design.

      Parameters
      • request: what to offer the user
      Returns

      resolves with the associated device, or fails with NearbyError.USER_CANCELED when the user dismissed the chooser

    • getAssociations

      public static List<CompanionDevice> getAssociations()

      Every association this app currently holds.

      Associations survive restarts, so this is what an app calls on startup to find the accessory it was using last time rather than asking the user again.

      Returns

      the associations, never null and possibly empty

    • disassociate

      public static AsyncResource<Boolean> disassociate(String associationId)

      Drops an association and the privileges that came with it.

      Parameters
      Returns

      resolves true once the association is gone

    • startObservingPresence

      public static boolean startObservingPresence(String associationId)

      Asks the platform to watch for the device and tell this app when it comes and goes, delivering to every registered PresenceListener.

      Parameters
      Returns

      true when the platform accepted the request. false where presence observation is unsupported -- the association itself is unaffected, so an app can carry on scanning for the device itself.

    • stopObservingPresence

      public static void stopObservingPresence(String associationId)

      Stops watching an association. Idempotent.

      Parameters
    • addPresenceListener

      public static void addPresenceListener(PresenceListener l)

      Registers a presence listener. Callbacks arrive on the EDT.

      Register from the app's init(): presence is exactly the event that can arrive during a cold start, because the platform may start the process to deliver it. An event that arrived before any listener existed is replayed to the listeners as soon as the first one registers, so a sighting delivered into a process whose init() had not run yet is not lost. At most the 64 most recent are kept.

      This is not background execution. The platform starting the process does not make the application run: Android hands the event to a service, and Codename One does not initialize an app there, because an init() may build a Form and a service has nowhere to put one. The listener hears about the sighting, in order, when the app next initializes.

      Parameters
      • l: the listener to add
    • removePresenceListener

      public static void removePresenceListener(PresenceListener l)

      Removes a listener added by addPresenceListener(PresenceListener).

      Parameters
      • l: the listener to remove