dotnet / dotnet/android-libraries

Compose: painterResource(Int, Composer) not bound in Xamarin.AndroidX.Compose.UI.Android (PainterResources_androidKt wrapper is empty)

Open
#1,443 0 comments 1 reaction 2 assignees Claimed by @jonathanpeppers View on GitHub
Dominant language
C#
Stars
317
Forks
73
Avg merge
1d 8h
Merged PRs (30d)
17

Description

## Summary

`Painter` and the painter implementations (`BitmapPainter`, `BrushPainter`, `ColorPainter`) **are** bound in `Xamarin.AndroidX.Compose.UI.Graphics`, but the loader `painterResource(@DrawableRes id: Int): Painter` from `androidx.compose.ui.res.PainterResources_androidKt` is not reachable from C# — only an empty `PainterResources_androidKt` wrapper class is emitted, with zero static methods.

Without `painterResource`, the bound `Painter` types are unreachable from typical Compose code (`Image(painter = painterResource(R.drawable.foo), …)`).

## Library / NuGet

- AAR: `androidx.compose.ui:ui-android` (the `Kt` class lives here, not in `ui-graphics-android`)
- NuGet: `Xamarin.AndroidX.Compose.UI.Android`
- Source dir: [`source/androidx.compose.ui/ui-android/`](https://github.com/dotnet/android-libraries/tree/main/source/androidx.compose.ui/ui-android)

## Verified state today (commit eb2f50b)

`source/androidx.compose.ui/ui-android/PublicAPI/PublicAPI.Unshipped.txt` contains exactly two `PainterResources_androidKt` lines:

```
AndroidX.Compose.UI.Res.PainterResources_androidKt
override AndroidX.Compose.UI.Res.PainterResources_androidKt.JniPeerMembers.get -> Java.Interop.JniPeerMembers!
```

…i.e. the class wrapper is bound but **no `painterResource` static method is exposed**. The Kotlin function is:

```kotlin
@Composable
@ReadOnlyComposable
fun painterResource(@DrawableRes id: Int): Painter
```

There is no `@JvmInline value class` parameter, so this is **not** the same hash-mangled-name pattern as [dotnet/java-interop#1440](https://github.com/dotnet/java-interop/pull/1440). The `@Composable` annotation alone causes the JVM signature to include trailing `Composer` + `Int $changed` parameters, but those bind fine elsewhere. Something more specific is dropping this overload — likely the `@ReadOnlyComposable` attribute or the `Painter` return type's nullability/inheritance metadata.

For comparison, `Painter` itself binds fine in `Xamarin.AndroidX.Compose.UI.Graphics`:

```
AndroidX.Compose.UI.Graphics.Painter.Painter
abstract AndroidX.Compose.UI.Graphics.Painter.Painter.IntrinsicSize.get -> long
virtual AndroidX.Compose.UI.Graphics.Painter.Painter.ApplyAlpha(float alpha) -> bool
virtual AndroidX.Compose.UI.Graphics.Painter.Painter.ApplyColorFilter(AndroidX.Compose.UI.Graphics.ColorFilter? colorFilter) -> bool

AndroidX.Compose.UI.Graphics.Painter.BitmapPainter
AndroidX.Compose.UI.Graphics.Painter.BrushPainter
AndroidX.Compose.UI.Graphics.Painter.ColorPainter
```

## Metadata.xml today

`source/androidx.compose.ui/ui-android/Transforms/Metadata.xml` has surgical removes for inline-class hash-mangled overloads but nothing referencing `painterResource` / `PainterResources_androidKt`. The method is being dropped by the binder itself, not by the project's transforms.

## Reproduction / evidence

`compose-net` works around this with a hand-written JNI bridge:

- [`ComposeBridges.cs`](https://github.com/jonathanpeppers/compose-net/blob/main/src/ComposeNet.Compose/ComposeBridges.cs) – `[ComposeBridge(Class = "androidx/compose/ui/res/PainterResources_androidKt", JvmName = "painterResource", Signature = "(ILandroidx/compose/runtime/Composer;I)Landroidx/compose/ui/graphics/painter/Painter;")]`

The bridge calls successfully at runtime and returns a usable `Painter` handle, so the underlying Java method exists and behaves correctly — only the binding-time projection is missing.

## Suggested fix

Add the `painterResource(int, Composer, int)` static to `AndroidX.Compose.UI.Res.PainterResources_androidKt`. If it can't be generated automatically, an `add-node` transform in `Transforms/Metadata.xml` should suffice.

## Cross-references

- compose-net tracking: none filed yet (Painter usage is documented in [`src/ComposeNet.Compose/Image.cs`](https://github.com/jonathanpeppers/compose-net/blob/main/src/ComposeNet.Compose/Image.cs))
- Master inline-class blocker: [dotnet/java-interop#1440](https://github.com/dotnet/java-interop/pull/1440) — **note**: `painterResource` does **not** appear blocked on #1440 because it has no inline-class parameters.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.