Measurement Sync¶
The measurement synchronization feature (available since v1.16.0) automatically uploads test results to AVEQ's servers. When enabled, the SDK queues completed measurements and uploads them to the server in the background. The queue is persistent (stored in a local database), so measurements survive app restarts and are retried on network failures.
Note
This feature is only available for select customers who have opted to have their measurement data hosted on AVEQ's servers. Standalone builds of the SDK do not include this functionality — measurements are only returned locally via the result callbacks, and no data is sent to AVEQ except for telemetry data. If you are interested in enabling measurement sync for your app, please contact AVEQ support!
Timing¶
Measurement data are queued immediately after a test completes. The upload is deferred while a test is actively running (to avoid network contention). In other words, the queue pauses uploads while a quality test is running. This is handled internally by the SDK — you don't need to manage this yourself. If you're implementing custom test orchestration, you can use:
// Check if a test is currently active
boolean testRunning = MeasurementQueueManager.isTestActive();
Queue Status¶
You can query the current state of the measurement queue:
import com.aveq.qualitytestlib.queue.MeasurementQueueManager;
// Get the number of pending measurements
int pending = MeasurementQueueManager.getPendingCount(context);
// Check if measurements are currently being sent
boolean sending = MeasurementQueueManager.isSending(context);
Broadcast Notifications¶
The SDK broadcasts local intents when measurements are sent successfully or fail. You can register a BroadcastReceiver to receive these notifications and update your UI accordingly.
The following broadcast actions and extras are available:
| Constant | Value | Description |
|---|---|---|
ACTION_MEASUREMENT_SENT |
com.aveq.qualitytestlib.MEASUREMENT_SENT |
Broadcast when a measurement is successfully uploaded |
ACTION_MEASUREMENT_FAILED |
com.aveq.qualitytestlib.MEASUREMENT_FAILED |
Broadcast when a measurement permanently fails to upload |
For ACTION_MEASUREMENT_SENT, the following extras are included:
| Extra | Type | Description |
|---|---|---|
EXTRA_MEASUREMENT_ID |
int |
The server-assigned measurement ID |
EXTRA_MEASUREMENT_TYPE |
String |
The measurement type (e.g., video_measurement, web_measurement) |
For ACTION_MEASUREMENT_FAILED, the following extra is included:
| Extra | Type | Description |
|---|---|---|
EXTRA_ERROR_MESSAGE |
String |
Description of the failure reason |
Example: Registering a BroadcastReceiver¶
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.aveq.qualitytestlib.queue.MeasurementSendWorker;
public class MyActivity extends AppCompatActivity {
private final BroadcastReceiver measurementReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (MeasurementSendWorker.ACTION_MEASUREMENT_SENT.equals(action)) {
int measurementId = intent.getIntExtra(
MeasurementSendWorker.EXTRA_MEASUREMENT_ID, -1);
String type = intent.getStringExtra(
MeasurementSendWorker.EXTRA_MEASUREMENT_TYPE);
// Handle successful upload
Log.i("MyApp", "Measurement uploaded: id=" + measurementId);
} else if (MeasurementSendWorker.ACTION_MEASUREMENT_FAILED.equals(action)) {
String error = intent.getStringExtra(
MeasurementSendWorker.EXTRA_ERROR_MESSAGE);
// Handle upload failure
Log.e("MyApp", "Measurement upload failed: " + error);
}
}
};
@Override
protected void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter();
filter.addAction(MeasurementSendWorker.ACTION_MEASUREMENT_SENT);
filter.addAction(MeasurementSendWorker.ACTION_MEASUREMENT_FAILED);
LocalBroadcastManager.getInstance(this)
.registerReceiver(measurementReceiver, filter);
}
@Override
protected void onStop() {
LocalBroadcastManager.getInstance(this)
.unregisterReceiver(measurementReceiver);
super.onStop();
}
}
Manual Queue Control¶
In most cases, the queue operates on its own. However, you can manually trigger an immediate sync attempt:
// Trigger an immediate sync attempt (if not already sending)
MeasurementQueueManager.scheduleImmediateSend(context);
If measurements get stuck in a "sending" state (e.g., due to a crash during upload), you can reset them: