Registration¶
How Registration Works¶
The Surfmeter Mobile Quality SDK uses a license-based registration system to manage access. Before your app can run any quality measurements, the device must be registered against the Surfmeter server using a registration key provided by AVEQ.
A registration key controls:
- How many devices can register with it (a finite counter, or unlimited)
- How long each device may use the SDK after registering (optional usage limit in days)
- When the key is valid (“valid until” – a time window) – this controls when new registrations are accepted, but does not affect already-registered devices
- Which measurement types and subjects the device is allowed to run (capabilities)
When a device registers, the server decrements the key's registration counter, creates a client record, and returns a unique device identity (UUID + secret) along with any configured capabilities and expiration details. These credentials are stored encrypted on the device and used for all subsequent API calls.
Registration Lifecycle¶
The following diagram shows the full lifecycle from registration to expiration or unregistration. Understanding this lifecycle is important for integrators, because registered devices hold a registration slot. For keys with a per-device usage limit, the server returns the slot automatically when the limit elapses; for keys without one, devices keep their slot until explicitly unregistered.
flowchart TD
A[App starts] --> B{Device registered?}
B -- No --> D["Integrator calls registerClientAsync()"]
B -- Yes --> C[Use stored credentials]
D --> E{Server validates key}
E -- Invalid or expired key --> F[Registration failed]
E -- No registrations left --> F
E -- Valid --> G["Server creates client,<br>decrements registration counter;<br>SDK stores UUID, secret,<br>capabilities, expiration locally"]
G --> C
C --> T["Integrator creates QualityTest"]
T --> J{SDK checks:<br>registration expired?}
J -- Yes --> L["License returned automatically:<br>SDK calls returnLicense(), or the server<br>returns it when the usage limit elapses;<br>client disabled, device must re-register"]
J -- No --> U{SDK checks:<br>type and subject allowed<br>by capabilities?}
U -- No --> V["SDK throws IllegalStateException"]
U -- Yes --> K[Test runs]
K --> M{App lifecycle event}
M -- Continue --> T
M -- Device decommissioned --> N["Integrator calls unregisterClientAsync();<br>server disables client and<br>increments registration counter"]
Billing Implications¶
Registered devices are counted toward your license usage. How a registration slot is freed depends on whether the key has a per-device usage limit:
- Keys with a usage limit (
usage_limit_days): the server automatically returns the slot to the pool when the device's usage window elapses (registration time + usage_limit_days). This happens even if the device was uninstalled and the SDK never runs again. You do not need to take any action to free these slots. - Keys without a usage limit: the device stays registered and keeps holding its slot indefinitely. The server does not free it automatically, so you must actively unregister the device when it is no longer in use.
Unregister devices on keys without a usage limit
For registration keys without a usage limit, the slot is only freed when you act. When such a device is decommissioned, replaced, or no longer running measurements, call unregisterClientAsync() to return the license. This frees the registration slot so it can be reused by another device.
Calling unregisterClientAsync() is also useful for keys with a usage limit if you want to return the slot early, before the usage window elapses.
If you are unable to do so, you can manually disable the client in our Surfmeter Dashboard. Or, please let us know the device UUIDs so we can manually free the slots on our end.
Backup, restore, and device transfer
A device that is restored from an Android cloud backup or transferred to a new phone will register again and receive a fresh UUID, because the credentials are encrypted with a Keystore-bound master key that does not move between devices. The SDK ships backup-rules resources that exclude the credentials file from Auto Backup so that the original device keeps its UUID across normal backups. See Backup and Restore Behavior for details and for the conflict-resolution path if your app declares its own backup rules.
Registration Example¶
Use the provided Registry class and call registerClientAsync with your license key. Registration is a one-time process per device – the credentials are persisted in the app's encrypted preferences.
import com.aveq.qualitytestlib.Registry;
Registry registry = Registry.Builder(this).forSurfmeterQualitySdk().build();
if (registry.isClientRegistered()) {
return;
}
registry.registerClientAsync(
"REPLACE_WITH_YOUR_REGISTRATION_KEY",
"your-client-label", // optional: a label to identify the client (must be unique across all your clients)
null, // optional: a List<String> of tags for the client (e.g. Arrays.asList("production", "eu-west")), or null for none
new Registry.OnClientRegisteredListener() {
@Override
public void onClientRegistered() {
// store the state that the client is registered
}
@Override
public void onClientRegistrationFailed(RuntimeException e) {
// log or display an error
}
}
);
Notes:
- Your implementing application should also store the state that the client is registered to avoid redundant registrations or checks.
- The registration key is provided by AVEQ. If it does not work, please contact us.
- Registration should be done asynchronously to avoid blocking the main thread. While a synchronous registration method exists, it is not recommended for production code.
Unregistration¶
When a device is no longer needed, call unregisterClientAsync() to return the license to the pool. This disables the client on the server and increments the registration counter, making the slot available for another device.
registry.unregisterClientAsync(new Registry.OnClientUnregisteredListener() {
@Override
public void onClientUnregistered() {
// client has been unregistered, clear local state
}
@Override
public void onClientUnregistrationFailed(RuntimeException e) {
// handle error
}
});
You should call this when:
- A device is being decommissioned or removed from your fleet
- A device is being replaced by a new one
- You are cleaning up test or development devices
- The app is being uninstalled (if you can intercept this event)
Remote Device Registration via ADB¶
For automated deployments or testing scenarios where you cannot manually enter a registration key, the SDK demo app supports auto-registration via an Android intent. This allows you to register the app on remote devices via ADB without any manual interaction.
First, grant the required permissions:
adb shell pm grant com.aveq.qualitytestlibdemo android.permission.ACCESS_FINE_LOCATION
adb shell pm grant com.aveq.qualitytestlibdemo android.permission.ACCESS_COARSE_LOCATION
adb shell pm grant com.aveq.qualitytestlibdemo android.permission.READ_PHONE_STATE
adb shell pm grant com.aveq.qualitytestlibdemo android.permission.POST_NOTIFICATIONS
Then send the registration intent:
adb shell am start -n com.aveq.qualitytestlibdemo/.MainActivity \
-a com.aveq.qualitytestlibdemo.action.REGISTER \
--es registration_key "YOUR_REGISTRATION_KEY" \
--es label "Device-001" \
--esa tags "production,eu-west"
Intent Parameters¶
| Parameter | Type | Required | Description |
|---|---|---|---|
registration_key |
String | Yes | The license key provided by AVEQ |
label |
String | No | A unique identifier for this device/client |
tags |
String Array | No | Comma-separated tags for categorization |
On successful registration, the client UUID will be logged to logcat under the Surfmeter.MainActivity tag.
Capabilities¶
Capabilities define which measurement types and subjects a device is allowed to run. They are configured server-side, associated with a registration key, and transmitted to the device during registration.
If no capability is assigned to a registration key, all test types and subjects are allowed by default.
How Capabilities Work¶
A capability consists of lists that control access:
allowed_measurement_types– measurement types the client may run. An empty list means all types are allowed.allowed_measurement_subjects– specific services or platforms the client may measure. An empty list means all subjects are allowed.
The Mobile Quality SDK currently supports two measurement types:
video– video streaming quality tests (VideoQualityTest, ExoPlayerQualityTest)web– web page loading performance tests (WebQualityTest)
The video type supports the following subjects: youtube, netflix_trailer, facebook, instagram, tiktok, hotstar, exoplayer.
The web type only supports website.
Note
The server-side capability system supports additional measurement types (e.g., network, speedtest, conferencing) and their corresponding subjects. These are used by other Surfmeter products but are not available in the Mobile Quality SDK. If a capability restricts your key to types or subjects not supported by this SDK, the affected tests simply cannot be created.
Querying Capabilities¶
After registration, you can inspect the client's capabilities using Registry.getCapability():
Registry registry = new Registry.Builder(context).forSurfmeterQualitySdk().build();
HashMap<String, ArrayList<String>> capabilities = registry.getCapability();
if (capabilities == null) {
// No restrictions — all test types and subjects are allowed
} else {
ArrayList<String> allowedTypes = capabilities.get("allowed_measurement_types");
ArrayList<String> allowedSubjects = capabilities.get("allowed_measurement_subjects");
// These extra fields exists but are typically not set
ArrayList<String> forbiddenTypes = capabilities.get("forbidden_measurement_types");
ArrayList<String> forbiddenSubjects = capabilities.get("forbidden_measurement_subjects");
}
Querying capabilities is useful if you want to adapt your UI – for example, to only show measurement options that the client is permitted to use.
Automatic Enforcement¶
You do not need to check capabilities manually before running a test. The SDK automatically validates the requested test type and subject when a QualityTest is instantiated. If the test is not permitted, the constructor throws an IllegalStateException:
try {
VideoQualityTest test = new VideoQualityTest.Builder(context)
.setUrl("https://www.youtube.com/watch?v=...")
.setSubject("youtube")
.build();
} catch (IllegalStateException e) {
// "Test type or subject not allowed by capability"
}
Registration Expiration¶
There are two independent expiry mechanisms that can cause a device's registration to end. Both are configured server-side and associated with the registration key.
Per-device usage limit¶
A registration key can define a usage limit in days. When a device registers, the server computes an expiration timestamp (registration time + usage_limit_days) and transmits it to the device. The SDK stores this timestamp locally.
The slot is returned by two complementary mechanisms:
- Client-side (SDK): the SDK checks for expiration whenever the stored credentials are accessed – for example, when instantiating a
QualityTest. If the expiration has passed at that point, the SDK callsreturnLicense()on the server, clears the local credentials, and throws anIllegalStateException. This check happens lazily on the next SDK operation that requires credentials. - Server-side: independently of the SDK, the server automatically returns the slot to the pool when the usage window elapses. This means the slot is reclaimed even if the app is never opened again or was uninstalled before the limit was reached.
These two mechanisms are idempotent: whichever happens first frees the slot, and the slot is never double-counted. The client-side check is an optimization that can return the slot a bit sooner; for usage-limited keys you do not need to rely on it.
This is a hard client-side expiration: once it triggers on the device, no new tests can be created until the device re-registers with a valid key.
Registration key "Valid until" date¶
Each registration key has an optional "Valid until" date, visible in the Surfmeter Dashboard. This date controls when new devices can register with the key. After it passes, new registrations are rejected.
For already-registered devices, this expiration is not yet enforced locally. In practice, this means a device with an expired key continues to produce measurements and deliver them to the integrator's onTestResult callback, but the results are not transmitted to the Surfmeter server.
Checking remaining time¶
You can check the remaining time for the per-device usage limit using Registry.getExpirationDetails():
Registry registry = new Registry.Builder(context).forSurfmeterQualitySdk().build();
Registry.ExpirationInfo expiration = registry.getExpirationDetails();
if (expiration == null) {
// No expiration set, or client is not registered
} else {
long remaining = expiration.value;
TimeUnit unit = expiration.unit;
// e.g. "Registration expires in 25 DAYS"
}
This method returns null when no expiration is configured (the registration does not expire), when the expiration has already passed, or when the client is not registered.
Note
getExpirationDetails() only reflects the per-device usage limit. It does not account for the registration key's "Valid until" date, which is only enforced server-side.