Class 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.
-
Method Summary
Modifier and TypeMethodDescriptionstatic Stringformat(byte[] bytes) Renders 16 bytes as a canonical identifier.static booleanWhetheridis a canonical identifier: 36 characters, hyphens in the four expected places, hex everywhere else.static StringUpper-cases a well-formed identifier, or returns null if it is not well-formed.static Stringrandom()A fresh random (version 4) identifier in canonical form.
-
Method Details
-
random
A fresh random (version 4) identifier in canonical form.
From
SecureRandom, deliberately, and NOT fromjava.util.Random. The device runtime's Random isthis(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
Renders 16 bytes as a canonical identifier.- Parameters:
bytes- exactly 16 bytes- Returns:
- the canonical form
- Throws:
IllegalArgumentException- ifbytesis not 16 long
-
isValid
Whetheridis a canonical identifier: 36 characters, hyphens in the four expected places, hex everywhere else. Case is not checked here -- usenormalize(String)to both check and fix the case.- Parameters:
id- the candidate, may be null- Returns:
- true if the shape is right
-
normalize
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- the candidate, may be null- Returns:
- the canonical form, or null if
idis not an identifier
-