diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt index 16cfbd1ba..f07f54bdd 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt @@ -95,27 +95,24 @@ class WidgetComponent(private val context: Context) : } // We resize the image in a such a way that we don't hit the RemoteView size - // limit, which is the size of an RGB_8888 bitmap 1.5x the screen size. When - // enabling rounded corners, we further reduce it by a factor of 8 to get 16-dp - // rounded corners, whereas we only downsize it by 2 when there is rounded - // corners just to ensure that we *really* do not hit the memory limit. + // limit, which is the size of an RGB_8888 bitmap 1.5x the screen size. val metrics = context.resources.displayMetrics val sw = metrics.widthPixels val sh = metrics.heightPixels return if (cornerRadius > 0) { - this@WidgetComponent.logD("Loading round covers: $cornerRadius") - + // Reduce the size by 10x, not only to make 16dp-ish corners, but also + // to work around a bug in Android 13 where the bitmaps aren't pooled + // properly, massively reducing the memory size we can work with. builder - .size(sqrt((6f / 4f / 8f) * sw * sh).toInt()) + .size(computeSize(sw, sh, 10f)) .transformations( SquareFrameTransform.INSTANCE, - // RoundedCornersTransformation is used instead of clipToOutline - // since our hack to get a 1:1 cover on the widget actually does - // not result in a square view, making clipToOutline not work. RoundedCornersTransformation(cornerRadius.toFloat())) } else { - builder.size(sqrt((6f / 4f / 2f) * sw * sh).toInt()) + // Divide by two to really make sure we aren't hitting the memory limit. + + builder.size(computeSize(sw, sh, 2f)) } } @@ -126,6 +123,9 @@ class WidgetComponent(private val context: Context) : }) } + private fun computeSize(sw: Int, sh: Int, modifier: Float) = + sqrt((6f / 4f / modifier) * sw * sh).toInt() + /* * Release this instance, removing the callbacks and resetting all widgets */ diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetProvider.kt b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetProvider.kt index d23b1cf60..a99bccfef 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetProvider.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetProvider.kt @@ -63,7 +63,15 @@ class WidgetProvider : AppWidgetProvider() { SizeF(180f, 272f) to createMediumWidget(context, state), SizeF(272f, 272f) to createLargeWidget(context, state)) - AppWidgetManager.getInstance(context).updateAppWidgetCompat(context, views) + val awm = AppWidgetManager.getInstance(context) + + try { + awm.updateAppWidgetCompat(context, views) + } catch (e: Exception) { + logW("Unable to update widget: $e") + awm.updateAppWidget( + ComponentName(context, this::class.java), createDefaultWidget(context)) + } } /* @@ -158,21 +166,12 @@ class WidgetProvider : AppWidgetProvider() { } } - val layout = candidates.maxByOrNull { it.height * it.width } + val layout = + candidates.maxByOrNull { it.height * it.width } + ?: unlikelyToBeNull(views.minOfOrNull { it.key.width * it.key.height }) - if (layout != null) { - logD("Using widget layout $layout") - updateAppWidget(id, views[layout]) - continue - } else { - // Default to the smallest view if no layout fits - logW("No good widget layout found") - - val minimum = - unlikelyToBeNull(views.minByOrNull { it.key.width * it.key.height }).value - - updateAppWidget(id, minimum) - } + logD("Using widget layout $layout") + updateAppWidget(id, views[layout]) } } }