Previewer Host Activity (Android Only)#
Platform-only: Android UIWidget. This feature has no iOS equivalent.
HaapiUIPreviewerHostActivity and HaapiUIPreviewerScenarioListActivity complement the lighter-weight Compose @Preview mechanism documented in Preview Tools by running the real production code path — actual FragmentManager, actual ViewModels, actual view-binding, actual lifecycle. Use them when you want to validate that your theme renders correctly through the same code that ships to users.
Experimental, debug-only. The Activities are annotated @ExperimentalHaapiApi and live in the widget module’s src/debug/ source set. They do not exist in release AARs. Add @OptIn(ExperimentalHaapiApi::class) or @file:OptIn(ExperimentalHaapiApi::class) at the call site.
When to Use the Host Activity#
Reach for the Host Activity (and away from Compose @Preview) when:
- Compose
@Previewand production UI disagree. The Compose preview’s manual layout inflation skipsFragmentManager, ViewModels, and lifecycle hooks; some Fragments make conditional rendering decisions inonViewCreated()based on ViewModel state. The Host Activity exercises that real path. - You need to validate the full
HaapiFlowActivitylayout — header, scroll view, close button, background — applied throughsetTheme()inonCreate()the same way as production. - You want a final theme check before shipping without spinning up a full Curity Identity Server connection.
For day-to-day theming iteration, stay with Compose @Preview — the Host Activity requires build + install + launch, while Compose previews refresh on Kotlin save.
Setup#
No additional dependencies beyond the standard HAAPI UI Widget. Both Activities are registered in the widget module’s debug manifest and become available automatically in any debug build.
Launching the Scenario List#
HaapiUIPreviewerScenarioListActivity shows all 10 built-in scenarios as a list; tap any row to open it in the host:
@file:OptIn(ExperimentalHaapiApi::class)
import se.curity.identityserver.haapi.android.ui.widget.ExperimentalHaapiApi
import se.curity.identityserver.haapi.android.ui.widget.previewer.host.HaapiUIPreviewerScenarioListActivity
// All 10 built-in scenarios with the default theme:
startActivity(HaapiUIPreviewerScenarioListActivity.newIntent(this))
// With your custom theme applied to every preview:
startActivity(HaapiUIPreviewerScenarioListActivity.newIntent(
this,
themeResId = R.style.MyCustomHaapiTheme
))
Launching a Specific Screen with Custom JSON#
Bypass the scenario list and open a single screen with your own HAAPI JSON via HaapiUIPreviewerHostActivity:
import se.curity.identityserver.haapi.android.ui.widget.previewer.host.HaapiUIPreviewerHostActivity
val customJson = """
{
"type": "authentication-step",
"actions": [{
"template": "form",
"kind": "login",
"model": {
"href": "/login",
"method": "POST",
"type": "application/x-www-form-urlencoded",
"actionTitle": "Sign In",
"fields": [
{"name": "email", "type": "text", "label": "Email Address"},
{"name": "code", "type": "text", "label": "Verification Code"}
]
}
}]
}
""".trimIndent()
startActivity(HaapiUIPreviewerHostActivity.newIntent(
context = this,
json = customJson,
themeResId = R.style.MyCustomHaapiTheme
))
The JSON must conform to the HAAPI response format expected by the production parser — refer to the Curity HAAPI documentation for the schema.
How It Works#
- JSON is parsed through the same pipeline as Compose
@Preview—HaapiManager.haapiResponseOf→HaapiDataMappersFactory. HaapiFlowFragmentResolver(the same resolver used in productionHaapiFlowActivity) maps the resultingUIModelto the correct production Fragment.- The Fragment is committed into a real
FragmentManagerwith full lifecycle. - Theme is applied via
setTheme()inonCreate()beforesuper.onCreate()— same as production. - WebAuthn uses no-op credential factory stubs, so biometric and security-key prompts never fire.
For the default fragment classes the resolver maps to, see UI Extensibility ’s Default Model → View Mapping table.
What to Expect#
- Tapping buttons or links triggers the real Fragment’s action handling (
submit(),followLink()), which fires aFragmentResult. Since noHaapiFlowViewModelis listening, the button enters its loading state and stays there. This is expected — the Activity previews visual appearance, not flow navigation. - No navigation between screens. Each preview shows a single Fragment in isolation.
- WebAuthn credential ceremonies are blocked. No-op credential factory stubs prevent biometric / security-key prompts on device.
- The close button (X) in the flow layout header finishes the Activity, returning to the scenario list or your app.
The Host Activity intentionally does not connect to a Curity Identity Server. A button that enters a stuck loading state is the correct outcome — the Activity is for visual validation, not flow-behavior verification. If you need to test navigation between screens or end-to-end token exchange, run the real app against a real server.
How to implement this: Preview Tools · Theming · UI Extensibility · Android UIWidget