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 @Preview and production UI disagree. The Compose preview’s manual layout inflation skips FragmentManager, ViewModels, and lifecycle hooks; some Fragments make conditional rendering decisions in onViewCreated() based on ViewModel state. The Host Activity exercises that real path.
  • You need to validate the full HaapiFlowActivity layout — header, scroll view, close button, background — applied through setTheme() in onCreate() 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#

  1. JSON is parsed through the same pipeline as Compose @PreviewHaapiManager.haapiResponseOfHaapiDataMappersFactory.
  2. HaapiFlowFragmentResolver (the same resolver used in production HaapiFlowActivity) maps the resulting UIModel to the correct production Fragment.
  3. The Fragment is committed into a real FragmentManager with full lifecycle.
  4. Theme is applied via setTheme() in onCreate() before super.onCreate() — same as production.
  5. 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 a FragmentResult. Since no HaapiFlowViewModel is 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.

Was this helpful?