Class Ranging
Precision ranging: how far away another device is, and in which direction.
This is ultra-wideband ranging -- Apple's Nearby Interaction on iOS and Jetpack UWB on Android -- which measures distance by timing a radio round trip rather than by guessing from signal strength. Where an RSSI estimate off a Bluetooth advertisement is worth a few meters on a good day, UWB is worth about ten centimeters, and on hardware with multiple antennas it also reports which way the peer is.
The shape of a session
Both platforms need the two devices to exchange a token over some channel they already share before any radio ranging can begin, so the API is in two steps and there is no way to collapse them:
if (!Ranging.isSupported()) {
return; // no UWB radio on this device
}
Ranging.prepareSession(RangingRole.CONTROLLER).onResult((session, err) -> {
if (err != null) {
return;
}
// 1. publish our token however the two apps already talk --
// a GATT characteristic from com.codename1.bluetooth is typical
characteristic.writeValue(session.getLocalToken().toByteArray());
// 2. when theirs arrives, start ranging
session.addRangingListener(new RangingAdapter() {
public void updated(RangingUpdate u) {
if (u.hasDistance()) {
label.setText(Math.round(u.getDistance(RangingUnit.CENTIMETERS)) + " cm");
}
}
});
session.start(RangingToken.fromByteArray(theirToken));
});
A session ranges exactly one peer. That is a hard limit of Apple's
NINearbyPeerConfiguration rather than a simplification, so an app that
tracks several peers prepares several sessions -- which is also what the
Android port does under the hood.
Threading
Every callback here -- AsyncResource results and every
RangingListener method -- is delivered on the EDT.
Platform support
- iOS -- Nearby Interaction on devices with a U1 or newer chip (iPhone 11 and later). Peer and accessory ranging, direction where the hardware provides it. Not available on tvOS, watchOS or Mac Catalyst.
- Android -- Jetpack UWB on devices that report the UWB hardware
feature. Peer ranging natively; an accessory is ranged by building a
token with
RangingToken.forUwbAddress(byte[], int, int, int, byte[]). - Simulator, desktop and JavaScript -- a simulated implementation
with peers that really move, so ranging UI is developable without
hardware. Reports
NearbyAvailability.LOCAL_ONLY. - Every other port --
isSupported()isfalseand every call fails withNearbyError.NOT_SUPPORTED.
-
Method Summary
Modifier and TypeMethodDescriptionstatic NearbyAvailabilityHow usable ranging is at this moment, which is a different question fromisSupported(): a phone with a U1 chip whose owner denied the permission is supported and unavailable.static RangingCapabilitiesWhat this device can actually measure.static booleantruewhen this port and this device can range at all.static AsyncResource<RangingSession> prepareSession(RangingRole role) Allocates a ranging session and, with it, the local token to publish to the peer.static AsyncResource<Boolean> requestPermissions(NearbyPermission... permissions) Asks for the runtime permissions ranging needs.
-
Method Details
-
isSupported
public static boolean isSupported()truewhen this port and this device can range at all.This answers for the hardware, not for whether a peer is nearby. It is the query to hide a feature on; use
getAvailability()to tell a user why a supported feature is not working right now. -
getAvailability
How usable ranging is at this moment, which is a different question from
isSupported(): a phone with a U1 chip whose owner denied the permission is supported and unavailable.Returns
the current availability, never null
-
getCapabilities
What this device can actually measure. Never null: where ranging is absent this is
RangingCapabilities.UNSUPPORTED, whose every query isfalse.Returns
the capabilities of the local device
-
requestPermissions
Asks for the runtime permissions ranging needs.
Safe to call on every platform: a port with nothing to ask for resolves
truewithout showing anything.Parameters
permissions: what the app intends to do
Returns
resolves
truewhen every requested permission is granted -
prepareSession
Allocates a ranging session and, with it, the local token to publish to the peer. The session is not ranging yet -- call
RangingSession.start(RangingToken)once the peer's token arrives.Parameters
role: which end of the session this device is. Ignored on platforms that negotiate roles themselves, but pick one anyway: Android needs exactly one controller.
Returns
resolves with the prepared session, or fails with a
NearbyException
-