widget: fix widget failing to update

Turns out WidgetProvider doesn't support Hilt. Of course, it let me
know by silently failing on an exception for no reason.
This commit is contained in:
Alexander Capehart 2023-02-20 21:32:47 -07:00
parent 055d25e3e1
commit 9c7fa86ead
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
3 changed files with 58 additions and 55 deletions

View file

@ -25,6 +25,8 @@ import androidx.core.content.ContextCompat
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject import javax.inject.Inject
import org.oxycblt.auxio.playback.state.PlaybackStateManager import org.oxycblt.auxio.playback.state.PlaybackStateManager
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logE
/** /**
* A [BroadcastReceiver] that forwards [Intent.ACTION_MEDIA_BUTTON] [Intent]s to [PlaybackService]. * A [BroadcastReceiver] that forwards [Intent.ACTION_MEDIA_BUTTON] [Intent]s to [PlaybackService].
@ -35,6 +37,7 @@ class MediaButtonReceiver : BroadcastReceiver() {
@Inject lateinit var playbackManager: PlaybackStateManager @Inject lateinit var playbackManager: PlaybackStateManager
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
super.onRecieve()
if (playbackManager.queue.currentSong != null) { if (playbackManager.queue.currentSong != null) {
// We have a song, so we can assume that the service will start a foreground state. // We have a song, so we can assume that the service will start a foreground state.
// At least, I hope. Again, *this is why we don't do this*. I cannot describe how // At least, I hope. Again, *this is why we don't do this*. I cannot describe how

View file

@ -65,7 +65,7 @@ constructor(
val song = playbackManager.queue.currentSong val song = playbackManager.queue.currentSong
if (song == null) { if (song == null) {
logD("No song, resetting widget") logD("No song, resetting widget")
widgetProvider.update(context, null) widgetProvider.update(context, uiSettings, null)
return return
} }
@ -105,7 +105,7 @@ constructor(
override fun onCompleted(bitmap: Bitmap?) { override fun onCompleted(bitmap: Bitmap?) {
val state = PlaybackState(song, bitmap, isPlaying, repeatMode, isShuffled) val state = PlaybackState(song, bitmap, isPlaying, repeatMode, isShuffled)
widgetProvider.update(context, state) widgetProvider.update(context, uiSettings, state)
} }
}) })
} }

View file

@ -27,8 +27,6 @@ import android.os.Bundle
import android.util.SizeF import android.util.SizeF
import android.view.View import android.view.View
import android.widget.RemoteViews import android.widget.RemoteViews
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.resolveNames import org.oxycblt.auxio.music.resolveNames
@ -42,10 +40,7 @@ import org.oxycblt.auxio.util.*
* state alongside actions to control it. * state alongside actions to control it.
* @author Alexander Capehart (OxygenCobalt) * @author Alexander Capehart (OxygenCobalt)
*/ */
@AndroidEntryPoint
class WidgetProvider : AppWidgetProvider() { class WidgetProvider : AppWidgetProvider() {
@Inject lateinit var uiSettings: UISettings
override fun onUpdate( override fun onUpdate(
context: Context, context: Context,
appWidgetManager: AppWidgetManager, appWidgetManager: AppWidgetManager,
@ -75,9 +70,10 @@ class WidgetProvider : AppWidgetProvider() {
/** /**
* Update the currently shown layout based on the given [WidgetComponent.PlaybackState] * Update the currently shown layout based on the given [WidgetComponent.PlaybackState]
* @param context [Context] required to update the widget layout. * @param context [Context] required to update the widget layout.
* @param uiSettings [UISettings] to obtain round mode configuration
* @param state [WidgetComponent.PlaybackState] to show, or null if no playback is going on. * @param state [WidgetComponent.PlaybackState] to show, or null if no playback is going on.
*/ */
fun update(context: Context, state: WidgetComponent.PlaybackState?) { fun update(context: Context, uiSettings: UISettings, state: WidgetComponent.PlaybackState?) {
if (state == null) { if (state == null) {
// No state, use the default widget. // No state, use the default widget.
reset(context) reset(context)
@ -89,11 +85,11 @@ class WidgetProvider : AppWidgetProvider() {
// the widget elements, plus some leeway for text sizing. // the widget elements, plus some leeway for text sizing.
val views = val views =
mapOf( mapOf(
SizeF(180f, 100f) to newThinLayout(context, state), SizeF(180f, 100f) to newThinLayout(context, uiSettings, state),
SizeF(180f, 152f) to newSmallLayout(context, state), SizeF(180f, 152f) to newSmallLayout(context, uiSettings, state),
SizeF(272f, 152f) to newWideLayout(context, state), SizeF(272f, 152f) to newWideLayout(context, uiSettings, state),
SizeF(180f, 272f) to newMediumLayout(context, state), SizeF(180f, 272f) to newMediumLayout(context, uiSettings, state),
SizeF(272f, 272f) to newLargeLayout(context, state)) SizeF(272f, 272f) to newLargeLayout(context, uiSettings, state))
// Manually update AppWidgetManager with the new views. // Manually update AppWidgetManager with the new views.
val awm = AppWidgetManager.getInstance(context) val awm = AppWidgetManager.getInstance(context)
@ -131,66 +127,66 @@ class WidgetProvider : AppWidgetProvider() {
// --- LAYOUTS --- // --- LAYOUTS ---
/**
* Create and configure a [RemoteViews] for [R.layout.widget_default], intended for situations
* where no other widget layout is applicable.
* @param context [Context] required to create the [RemoteViews].
*/
private fun newDefaultLayout(context: Context) = private fun newDefaultLayout(context: Context) =
newRemoteViews(context, R.layout.widget_default) newRemoteViews(context, R.layout.widget_default)
/** private fun newThinLayout(
* Create and configure a [RemoteViews] for [R.layout.widget_thin], intended for extremely small context: Context,
* grid sizes on phones in landscape mode. uiSettings: UISettings,
* @param context [Context] required to create the [RemoteViews]. state: WidgetComponent.PlaybackState
*/ ) =
private fun newThinLayout(context: Context, state: WidgetComponent.PlaybackState) =
newRemoteViews(context, R.layout.widget_thin) newRemoteViews(context, R.layout.widget_thin)
.setupBackground() .setupBackground(
uiSettings,
)
.setupPlaybackState(context, state) .setupPlaybackState(context, state)
.setupTimelineControls(context, state) .setupTimelineControls(context, state)
/** private fun newSmallLayout(
* Create and configure a [RemoteViews] for [R.layout.widget_small], intended to be a context: Context,
* modestly-sized default layout for most devices. uiSettings: UISettings,
* @param context [Context] required to create the [RemoteViews]. state: WidgetComponent.PlaybackState
*/ ) =
private fun newSmallLayout(context: Context, state: WidgetComponent.PlaybackState) =
newRemoteViews(context, R.layout.widget_small) newRemoteViews(context, R.layout.widget_small)
.setupBar() .setupBar(
uiSettings,
)
.setupCover(context, state) .setupCover(context, state)
.setupTimelineControls(context, state) .setupTimelineControls(context, state)
/** private fun newMediumLayout(
* Create and configure a [RemoteViews] for [R.layout.widget_medium], intended to be a taller context: Context,
* widget that shows more information about the currently playing song. uiSettings: UISettings,
* @param context [Context] required to create the [RemoteViews]. state: WidgetComponent.PlaybackState
*/ ) =
private fun newMediumLayout(context: Context, state: WidgetComponent.PlaybackState) =
newRemoteViews(context, R.layout.widget_medium) newRemoteViews(context, R.layout.widget_medium)
.setupBackground() .setupBackground(
uiSettings,
)
.setupPlaybackState(context, state) .setupPlaybackState(context, state)
.setupTimelineControls(context, state) .setupTimelineControls(context, state)
/** private fun newWideLayout(
* Create and configure a [RemoteViews] for [R.layout.widget_wide], intended to be a wider context: Context,
* version of [R.layout.widget_small] that shows additional controls. uiSettings: UISettings,
* @param context [Context] required to create the [RemoteViews]. state: WidgetComponent.PlaybackState
*/ ) =
private fun newWideLayout(context: Context, state: WidgetComponent.PlaybackState) =
newRemoteViews(context, R.layout.widget_wide) newRemoteViews(context, R.layout.widget_wide)
.setupBar() .setupBar(
uiSettings,
)
.setupCover(context, state) .setupCover(context, state)
.setupFullControls(context, state) .setupFullControls(context, state)
/** private fun newLargeLayout(
* Create and configure a [RemoteViews] for [R.layout.widget_large], intended to be a wider context: Context,
* version of [R.layout.widget_medium] that shows additional controls. uiSettings: UISettings,
* @param context [Context] required to create the [RemoteViews]. state: WidgetComponent.PlaybackState
*/ ) =
private fun newLargeLayout(context: Context, state: WidgetComponent.PlaybackState) =
newRemoteViews(context, R.layout.widget_large) newRemoteViews(context, R.layout.widget_large)
.setupBackground() .setupBackground(
uiSettings,
)
.setupPlaybackState(context, state) .setupPlaybackState(context, state)
.setupFullControls(context, state) .setupFullControls(context, state)
@ -198,7 +194,9 @@ class WidgetProvider : AppWidgetProvider() {
* Set up the control bar in a [RemoteViews] layout that contains one. This is a kind of * Set up the control bar in a [RemoteViews] layout that contains one. This is a kind of
* "floating" drawable that sits in front of the cover and contains the controls. * "floating" drawable that sits in front of the cover and contains the controls.
*/ */
private fun RemoteViews.setupBar(): RemoteViews { private fun RemoteViews.setupBar(
uiSettings: UISettings,
): RemoteViews {
// Below API 31, enable a rounded bar only if round mode is enabled. // Below API 31, enable a rounded bar only if round mode is enabled.
// On API 31+, the bar should always be round in order to fit in with other widgets. // On API 31+, the bar should always be round in order to fit in with other widgets.
val background = val background =
@ -215,7 +213,9 @@ class WidgetProvider : AppWidgetProvider() {
* Set up the background in a [RemoteViews] layout that contains one. This is largely * Set up the background in a [RemoteViews] layout that contains one. This is largely
* self-explanatory, being a solid-color background that sits behind the cover and controls. * self-explanatory, being a solid-color background that sits behind the cover and controls.
*/ */
private fun RemoteViews.setupBackground(): RemoteViews { private fun RemoteViews.setupBackground(
uiSettings: UISettings,
): RemoteViews {
// Below API 31, enable a rounded background only if round mode is enabled. // Below API 31, enable a rounded background only if round mode is enabled.
// On API 31+, the background should always be round in order to fit in with other // On API 31+, the background should always be round in order to fit in with other
// widgets. // widgets.