Headless Mode on Android
Wire SmartSpectra SDK lifecycle and metrics LiveData into your own Android UI — useful for background monitoring or custom interfaces.
The SDK doesn't ship UI. SmartSpectraSdk.shared exposes LiveData for
processingStatus, validationStatus, metrics, error, and
(optionally) imageOutput. Observe them from your Fragment or Activity
with observe(viewLifecycleOwner). The sample apps include a measurement
UI; your own integration looks however you want.
Use this when you want to:
- Monitor vitals in the background while the app shows other content
- Build a custom measurement UI
Lifecycle states:
| Status | Meaning |
|---|---|
| Idle | Pipeline is not running |
| Starting | Pipeline is initializing |
| Running | Actively measuring — data is flowing |
| Stopping | Teardown in progress, will return to Idle |
| Error | Something went wrong |
Use SmartSpectraSdk.shared directly for headless processing:
import android.Manifest
import android.os.Bundle
import android.content.pm.PackageManager
import android.view.View
import android.widget.ImageView
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.presagetech.smartspectra.CameraPosition
import com.presagetech.smartspectra.ProcessingStatus
import com.presagetech.smartspectra.SmartSpectraError
import com.presagetech.smartspectra.SmartSpectraSdk
import kotlinx.coroutines.launch
class HeadlessFragment : Fragment() {
private val sdk by lazy {
SmartSpectraSdk.shared.apply {
config.apiKey = "YOUR_API_KEY"
config.cameraPosition = CameraPosition.FRONT
config.imageOutputEnabled = true
}
}
private val requestCameraPermission =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
if (granted) {
startMonitoring()
} else {
showCameraPermissionUi()
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val previewImage: ImageView = view.findViewById(R.id.headless_preview_image)
sdk.processingStatus.observe(viewLifecycleOwner) { status ->
when (status) {
ProcessingStatus.IDLE -> showIdleUi()
ProcessingStatus.STARTING -> showLoadingUi()
ProcessingStatus.RUNNING -> showRecordingUi()
ProcessingStatus.STOPPING -> showStoppingUi()
ProcessingStatus.ERROR -> showErrorUi()
}
}
sdk.validationStatus.observe(viewLifecycleOwner) { status ->
updateStatusHint(status?.hint.orEmpty())
}
sdk.imageOutput.observe(viewLifecycleOwner) { bitmap ->
previewImage.setImageBitmap(bitmap)
}
sdk.metrics.observe(viewLifecycleOwner) { metrics ->
renderMetrics(metrics)
}
sdk.error.observe(viewLifecycleOwner) { error ->
if (error?.code == SmartSpectraError.Code.INPUT_UNAVAILABLE) {
showCameraPermissionUi()
}
}
}
private fun startMonitoring() {
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED
) {
requestCameraPermission.launch(Manifest.permission.CAMERA)
return
}
viewLifecycleOwner.lifecycleScope.launch {
sdk.start()
}
}
private fun stopMonitoring() {
viewLifecycleOwner.lifecycleScope.launch {
sdk.stop()
}
}
}sdk.metrics is the same LiveData property here as in any other
integration — there's no separate "headless" API. See
Android Metrics for the metric request configuration and the
field-by-field reading guide.
LLM Insights
Ask natural-language questions about a measurement and receive LLM Insights through the SmartSpectra Android SDK, alongside the metrics stream.
Headless Testing in CI
Run a full SmartSpectra measurement on an Android emulator in CI by feeding a recorded video, or smoke-test that the SDK builds and initializes.