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 javax.inject.Inject
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].
@ -35,6 +37,7 @@ class MediaButtonReceiver : BroadcastReceiver() {
@Inject lateinit var playbackManager: PlaybackStateManager
override fun onReceive(context: Context, intent: Intent) {
super.onRecieve()
if (playbackManager.queue.currentSong != null) {
// 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

View file

@ -65,7 +65,7 @@ constructor(
val song = playbackManager.queue.currentSong
if (song == null) {
logD("No song, resetting widget")
widgetProvider.update(context, null)
widgetProvider.update(context, uiSettings, null)
return
}
@ -105,7 +105,7 @@ constructor(
override fun onCompleted(bitmap: Bitmap?) {
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.view.View
import android.widget.RemoteViews
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.resolveNames
@ -42,10 +40,7 @@ import org.oxycblt.auxio.util.*
* state alongside actions to control it.
* @author Alexander Capehart (OxygenCobalt)
*/
@AndroidEntryPoint
class WidgetProvider : AppWidgetProvider() {
@Inject lateinit var uiSettings: UISettings
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
@ -75,9 +70,10 @@ class WidgetProvider : AppWidgetProvider() {
/**
* Update the currently shown layout based on the given [WidgetComponent.PlaybackState]
* @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.
*/
fun update(context: Context, state: WidgetComponent.PlaybackState?) {
fun update(context: Context, uiSettings: UISettings, state: WidgetComponent.PlaybackState?) {
if (state == null) {
// No state, use the default widget.
reset(context)
@ -89,11 +85,11 @@ class WidgetProvider : AppWidgetProvider() {
// the widget elements, plus some leeway for text sizing.
val views =
mapOf(
SizeF(180f, 100f) to newThinLayout(context, state),
SizeF(180f, 152f) to newSmallLayout(context, state),
SizeF(272f, 152f) to newWideLayout(context, state),
SizeF(180f, 272f) to newMediumLayout(context, state),
SizeF(272f, 272f) to newLargeLayout(context, state))
SizeF(180f, 100f) to newThinLayout(context, uiSettings, state),
SizeF(180f, 152f) to newSmallLayout(context, uiSettings, state),
SizeF(272f, 152f) to newWideLayout(context, uiSettings, state),
SizeF(180f, 272f) to newMediumLayout(context, uiSettings, state),
SizeF(272f, 272f) to newLargeLayout(context, uiSettings, state))
// Manually update AppWidgetManager with the new views.
val awm = AppWidgetManager.getInstance(context)
@ -131,66 +127,66 @@ class WidgetProvider : AppWidgetProvider() {
// --- 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) =
newRemoteViews(context, R.layout.widget_default)
/**
* Create and configure a [RemoteViews] for [R.layout.widget_thin], intended for extremely small
* grid sizes on phones in landscape mode.
* @param context [Context] required to create the [RemoteViews].
*/
private fun newThinLayout(context: Context, state: WidgetComponent.PlaybackState) =
private fun newThinLayout(
context: Context,
uiSettings: UISettings,
state: WidgetComponent.PlaybackState
) =
newRemoteViews(context, R.layout.widget_thin)
.setupBackground()
.setupBackground(
uiSettings,
)
.setupPlaybackState(context, state)
.setupTimelineControls(context, state)
/**
* Create and configure a [RemoteViews] for [R.layout.widget_small], intended to be a
* modestly-sized default layout for most devices.
* @param context [Context] required to create the [RemoteViews].
*/
private fun newSmallLayout(context: Context, state: WidgetComponent.PlaybackState) =
private fun newSmallLayout(
context: Context,
uiSettings: UISettings,
state: WidgetComponent.PlaybackState
) =
newRemoteViews(context, R.layout.widget_small)
.setupBar()
.setupBar(
uiSettings,
)
.setupCover(context, state)
.setupTimelineControls(context, state)
/**
* Create and configure a [RemoteViews] for [R.layout.widget_medium], intended to be a taller
* widget that shows more information about the currently playing song.
* @param context [Context] required to create the [RemoteViews].
*/
private fun newMediumLayout(context: Context, state: WidgetComponent.PlaybackState) =
private fun newMediumLayout(
context: Context,
uiSettings: UISettings,
state: WidgetComponent.PlaybackState
) =
newRemoteViews(context, R.layout.widget_medium)
.setupBackground()
.setupBackground(
uiSettings,
)
.setupPlaybackState(context, state)
.setupTimelineControls(context, state)
/**
* Create and configure a [RemoteViews] for [R.layout.widget_wide], intended to be a wider
* version of [R.layout.widget_small] that shows additional controls.
* @param context [Context] required to create the [RemoteViews].
*/
private fun newWideLayout(context: Context, state: WidgetComponent.PlaybackState) =
private fun newWideLayout(
context: Context,
uiSettings: UISettings,
state: WidgetComponent.PlaybackState
) =
newRemoteViews(context, R.layout.widget_wide)
.setupBar()
.setupBar(
uiSettings,
)
.setupCover(context, state)
.setupFullControls(context, state)
/**
* Create and configure a [RemoteViews] for [R.layout.widget_large], intended to be a wider
* version of [R.layout.widget_medium] that shows additional controls.
* @param context [Context] required to create the [RemoteViews].
*/
private fun newLargeLayout(context: Context, state: WidgetComponent.PlaybackState) =
private fun newLargeLayout(
context: Context,
uiSettings: UISettings,
state: WidgetComponent.PlaybackState
) =
newRemoteViews(context, R.layout.widget_large)
.setupBackground()
.setupBackground(
uiSettings,
)
.setupPlaybackState(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
* "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.
// On API 31+, the bar should always be round in order to fit in with other widgets.
val background =
@ -215,7 +213,9 @@ class WidgetProvider : AppWidgetProvider() {
* 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.
*/
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.
// On API 31+, the background should always be round in order to fit in with other
// widgets.