0

When I try to display a bitmap image (of my app icon) in the app, it works ok, but crashes when I try to display it in Widget Glance.

This is my code for bitmap:

    val icon = packageManager.getApplicationIcon("com.myapp.packagename")
    val bitmap: Bitmap = try {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            getAppIconV26(applicationContext, "com.myapp.packagename")
        } else {
            (icon as BitmapDrawable).bitmap
        }
    } catch (e: Exception) {
        (ResourcesCompat.getDrawable(applicationContext.resources, R.drawable.placeholder, null) as BitmapDrawable).bitmap

And this is jetpack compose Image, which loads bitmap fine:

androidx.compose.foundation.Image(
    modifier = Modifier.size(46.dp), 
    bitmap = bitmap.asImageBitmap(),
    contentDescription = null),
}

but when I try to load the same bitmap in the widget using Jetpack Glance Image, the widget crashes:

androidx.glance.Image(
    modifier = GlanceModifier.size(46.dp),
    provider = ImageProvider(bitmap),
    contentDescription = null,
)

Crash:

E/GlanceAppWidget: Error in Glance App Widget
    java.lang.RuntimeException: Tried to marshall a Parcel that contained Binder objects.
        at android.os.Parcel.nativeMarshall(Native Method)
        at android.os.Parcel.marshall(Parcel.java:620)
        at androidx.core.widget.RemoteViewsCompatService$RemoteViewsCompatServiceData$Companion.serializeToBytes$core_remoteviews_release(RemoteViewsCompatService.kt:245)
        at androidx.core.widget.RemoteViewsCompatService$RemoteViewsCompatServiceData$Companion.create(RemoteViewsCompatService.kt:166)
        at androidx.core.widget.RemoteViewsCompatService$Companion.saveItems(RemoteViewsCompatService.kt:306)
        at androidx.core.widget.RemoteViewsCompat.setRemoteAdapter(RemoteViewsCompat.kt:86)
        at androidx.glance.appwidget.translators.LazyListTranslatorKt.translateEmittableLazyList(LazyListTranslator.kt:90)
        at androidx.glance.appwidget.translators.LazyListTranslatorKt.translateEmittableLazyColumn(LazyListTranslator.kt:45)
        at androidx.glance.appwidget.RemoteViewsTranslatorKt.translateChild(RemoteViewsTranslator.kt:143)
        at androidx.glance.appwidget.RemoteViewsTranslatorKt.setChildren(RemoteViewsTranslator.kt:335)
        at androidx.glance.appwidget.RemoteViewsTranslatorKt.translateEmittableColumn(RemoteViewsTranslator.kt:268)
        at androidx.glance.appwidget.RemoteViewsTranslatorKt.translateChild(RemoteViewsTranslator.kt:140)
        at androidx.glance.appwidget.RemoteViewsTranslatorKt.translateComposition(RemoteViewsTranslator.kt:96)
        at androidx.glance.appwidget.RemoteViewsTranslatorKt.translateComposition-mU3eQPI(RemoteViewsTranslator.kt:63)
        at androidx.glance.appwidget.GlanceAppWidget$composeForSize$2.invokeSuspend(GlanceAppWidget.kt:393)
        at androidx.glance.appwidget.GlanceAppWidget$composeForSize$2.invoke(Unknown Source:8)
        at androidx.glance.appwidget.GlanceAppWidget$composeForSize$2.invoke(Unknown Source:4)
        at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:89)
        at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:165)
        at kotlinx.coroutines.BuildersKt.withContext(Unknown Source:1)
        at androidx.glance.appwidget.GlanceAppWidget.composeForSize-AAqiGWc$glance_appwidget_release(GlanceAppWidget.kt:371)
        at androidx.glance.appwidget.GlanceAppWidget.compose$glance_appwidget_release(GlanceAppWidget.kt:218)
        at androidx.glance.appwidget.GlanceAppWidget.compose$glance_appwidget_release(GlanceAppWidget.kt:201)
        at androidx.glance.appwidget.GlanceAppWidget$compose$1.invokeSuspend(Unknown Source:19)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)

I don't understand this crash. Can somebody please help me understand what's wrong?

Blank空白
  • 117
  • 8

3 Answers3

2

Glance translates into actual RemoteViews. Those are then passed to the host process (i.e the launcher/homescreen). There is a limitation in the size of the object that can be passed between process.

It seems you are using a LazyColumn (thus a ListView) that displays many Bitmaps. It could be that you hit that size limit.

Couple of things to try:

  • Try displaying just one with the same code
    • Does it work?
    • Does it work if you pass another small Bitmap? Maybe the issue is with the bitmap size or type?
  • Alternatively try using URIs instead of bitmaps or limit the number of items to be displayed.
Marcel
  • 2,094
  • 3
  • 23
  • 37
  • I used this png: ibb.co/MnqFPWC, with GlanceModifier.size(42.dp) in my test. I was able to display the Image. I was also able to create a Column(GlanceModifier.fillMaxSize().background(widgetBackground)) with 10 Images (but column can't be scrolled). I wasn't able to create a LazyColumn(GlanceModifier.fillMaxSize().background(widgetBackground)) with even just one Image, it produced the same error. – Blank空白 Jan 26 '22 at 13:44
  • 2
    I tried to extract app icons with Uri.parse("android.resource://${myapp.packageName}/${myapp.icon}"). Then I tried to display Image with that uri, and it worked. It also worked with LazyColumn, even if I displayed 30 items. Thanks!!! This was tested on Pixel 5, I will also try older devices. – Blank空白 Jan 26 '22 at 13:59
  • @Blank空白 could you please provide how you implemented your solution? – mars8 Apr 19 '22 at 08:40
  • 1
    @mairs8 Image(modifier = GlanceModifier.size(42.dp), provider = ImageProvider(Uri.parse("android.resource://${packageName}/${appInfo.icon}")), contentDescription = "App icon") – Blank空白 Apr 19 '22 at 09:47
  • @Blank空白 Thanks, I have tried something similar with `getUriForFile( context,"${context.packageName}.fileprovider", filename)` but the widget is only showing a "loading..." message. Have raised a separate question on it https://stackoverflow.com/q/71938442/15597975 – mars8 Apr 20 '22 at 11:02
  • @Marcel can you please elaborate on "try using URIs instead of bitmaps"? The LazyColumn does not work with any Bitmap. I am trying to pass a png file that I have saved via URI but I that does not seem to work either. The only working URI examples I have seen are those that point to an android resource. Please help. stackoverflow.com/q/71938442/15597975 – mars8 May 08 '22 at 19:14
  • Unfortunately it's not trivial. Have you provide read access to the file? Check https://developer.android.com/training/secure-file-sharing – Marcel Jun 08 '22 at 03:36
  • Same Here. LazyColumn + a NetworkImage (using suspend in beta01). Works great on Android13, fails with this error on Android11 even using BitmapImageProvider and right Context :/ – Jscti Jun 28 '23 at 19:35
1

I don't think the underlying library supports passing Bitmaps in lists, because it would be very easy to exceed the binder limit when passing the Bitmaps. You need to implement a content provider and pass uris instead of the bitmaps I think

Stevie Kideckel
  • 1,928
  • 2
  • 17
  • 21
0

Could you use val context = LocalContext.current instead of applicationContext? Moreover, please use BitmapImageProvider instead of ImageProvider.

Enes Zor
  • 973
  • 8
  • 14
  • +1 for the context but there is no BitmapImageProvider in Glance. The use of ImageProvider(glance) is correct – Marcel Jan 26 '22 at 03:48
  • Are you sure about BitmapImageProvider? I can import it with import androidx.glance.BitmapImageProvider – Enes Zor Jan 26 '22 at 07:48
  • This class is internal to the library and annotated as such https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:glance/glance/src/androidMain/kotlin/androidx/glance/Image.kt;l=41 – Marcel Jan 26 '22 at 11:14
  • Thanks for the notice about the context. I looked at the BitmapImageProvider but I don't see how that makes any difference. From what I see, ImageProvider automatically picks the right type so I don't have to manually declare it. That also didn't change anything in my error - is still the same. – Blank空白 Jan 26 '22 at 11:29