public final class CallId

  1. Object
  2. CallId

Canonical form of the identifier that names one call everywhere: in this API, in CallKit, in Telecom, and in the VoIP push payload a server sends.

It is an RFC 4122 identifier written as 36 characters, uppercase, with hyphens – 6B29FC40-CA47-1067-B31D-00DD010662DA. The case is fixed rather than ignored because the identifier is compared as a string on every hop, including by a server that did not come from this API, and “compare case-insensitively everywhere” is a rule that only has to be forgotten once.

Who allocates one

  • For a call this app places or learns about over its own connection, this app allocates with random().
  • For a call that arrives as a VoIP push, the sending server allocates and the identifier travels in the payload, because on iOS the call must be reported to the system before any of this app’s code runs. See VoipPush.

Either way the same identifier must be used by both ends for the whole life of the call, or the two sides will disagree about which call an action refers to.

This class is not instantiated; it holds the format and the generator.

Methods

public static String random()A fresh random (version 4) identifier in canonical form.
public static String format(byte[] bytes)Renders 16 bytes as a canonical identifier.
public static boolean isValid(String id)Whether id is a canonical identifier: 36 characters, hyphens in the four expected places, hex everywhere else.
public static String normalize(String id)Upper-cases a well-formed identifier, or returns null if it is not well-formed.

Inherited methods

Method details

random

public static String random()

A fresh random (version 4) identifier in canonical form.

From SecureRandom, deliberately, and NOT from java.util.Random. The device runtime’s Random is this(System.currentTimeMillis()) over a 48-bit LCG – see vm/JavaAPI/src/java/util/Random.java – so two processes that reach this class in the same millisecond produce the same sequence of identifiers, and it is the SEED that collides rather than the 122 random bits, which is a far smaller space than the format suggests. A call id is not decoration: it is the key CallKit and Telecom hold the session under and the token the app’s server routes signalling by, so two calls sharing one aliases them – CallKit answers a duplicate report with CallUUIDAlreadyExists, and a server hands the wrong session an answer or an end.

Every port that supports calling implements secureRandomBytes, so this does not narrow which PLATFORMS the API works on – but it does require the runtime to be up, because the bytes come through the implementation. That is true wherever application code runs and is NOT true in a platform service the OS starts on its own: Android’s CN1ConnectionService can be created by Telecom in a process with no Display, and it mints its own id there rather than calling this. A port adding a similar entry point has to do the same.

Returns

36 uppercase characters with hyphens

format

public static String format(byte[] bytes)
Renders 16 bytes as a canonical identifier.

Parameters

bytes byte[]
exactly 16 bytes

Returns

the canonical form

Throws

IllegalArgumentException
if bytes is not 16 long

isValid

public static boolean isValid(String id)
Whether id is a canonical identifier: 36 characters, hyphens in the four expected places, hex everywhere else. Case is not checked here – use normalize(String) to both check and fix the case.

Parameters

id String
the candidate, may be null

Returns

true if the shape is right

normalize

public static String normalize(String id)

Upper-cases a well-formed identifier, or returns null if it is not well-formed.

Ports call this on the way in, so a lowercase identifier from a server payload is accepted and stored canonically rather than becoming a call nothing can later find. A null return is the signal to answer CallError.INVALID_ID; this never throws, because the value routinely comes from off the device.

Parameters

id String
the candidate, may be null

Returns

the canonical form, or null if id is not an identifier