Enable Material 3 dynamic color
The standard Material Android host is the preferred integration because it resolves one Context for the native tree, overlays, and framework tokens. Use this task when an application wants wallpaper-derived color on supported Android versions. For token ownership and renderer isolation, see the theme architecture.
Select the host policy
UseIfAvailable is the default. Declaring it explicitly makes product policy visible:
class DynamicColorGuideActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setMaterial3UiContent(
dynamicColorPolicy = Material3DynamicColorPolicy.UseIfAvailable,
) {
Text("Dynamic Material color")
}
}
}
Choose Disabled when the product requires a fixed Android XML palette. On platforms without
dynamic-color support, UseIfAvailable keeps the resolved Material theme and static fallback
rules; application code does not need a second version branch.
Keep one resolved Context
setMaterial3UiContent resolves the themed Context before creating the root and uses it for native
descendants, AndroidView, default overlays, and Material3Theme. A low-level custom host must do
the same with Material3ThemeBridge.resolveContext and create every related View from
resolvedTheme.context. Reading tokens from the resolved wrapper while constructing Views from the
original Activity Context is invalid.
The standard host observes configuration changes and advances Environment.resourceRevision.
Material3Theme then refreshes its stable wrapper and maps a new immutable snapshot. Do not add a
second configuration callback in the Material layer.
Refresh imperative resource changes
Some locale wrappers, theme overlays, or calls to setTheme change resources without dispatching
the configuration callback observed by the host. Pass one AndroidResourceRefreshController to
setMaterial3UiContent, apply the resource change, and call its refresh() method on the main
thread. That controller refreshes both the host environment and the Material wrapper in one
ordered operation.
Use Material3ThemeRefreshController only in a custom low-level host that does not install the
standard Android resource environment. It must not become a parallel refresh path in an ordinary
Material Android host.
Verify the task
Compile with ./gradlew :samples:tutorials:compileDebugKotlin, then verify:
- On Android 12 or newer, change wallpaper colors and recreate the Activity; root surfaces,
framework controls,
AndroidView, and overlays must use one coherent dynamic palette. - On an older or unsupported device, confirm the configured Material XML/static fallback remains readable and no dynamic-color exception occurs.
- Toggle light/dark configuration and confirm
Theme.current.metadata.revisionadvances with no mixed old/new token families. - Apply one imperative test theme or locale mutation, invoke the host resource controller, and confirm both native resources and framework tokens update in the same root.
A split palette between overlays and the page, a stale AndroidView, duplicate refresh work, or a
background-thread refresh is a failed integration.