Skip to content

Commit e662936

Browse files
authored
Merge pull request #586 from namehillsoftware/bugfix/now-playing-intent-routing
[Bugfix] Now Playing Intent Routing
2 parents 122fea6 + 0c5f046 commit e662936

File tree

9 files changed

+112
-55
lines changed

9 files changed

+112
-55
lines changed

gradle/libs.versions.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ annotation = "1.9.1"
66
assertjCore = "3.27.6"
77
commonsCodec = "1.19.0"
88
commonsIo = "2.20.0"
9-
compose = "1.9.2"
9+
compose = "1.9.3"
1010
coreKtx = "1.17.0"
1111
desugar_jdk_libs = "2.1.5"
1212
gson = "2.13.2"

projectBlueWater/src/main/java/com/lasthopesoftware/bluewater/ApplicationDependenciesContainer.kt

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import com.lasthopesoftware.bluewater.client.browsing.library.access.LibraryRepo
2020
import com.lasthopesoftware.bluewater.client.browsing.library.access.ManageLibraries
2121
import com.lasthopesoftware.bluewater.client.browsing.library.access.ProvideLibraries
2222
import com.lasthopesoftware.bluewater.client.browsing.library.access.session.CachedSelectedLibraryIdProvider
23+
import com.lasthopesoftware.bluewater.client.browsing.library.access.session.SelectedLibraryIdCache
2324
import com.lasthopesoftware.bluewater.client.browsing.library.access.session.SelectedLibraryIdProvider
2425
import com.lasthopesoftware.bluewater.client.browsing.library.settings.access.CachedLibrarySettingsAccess
2526
import com.lasthopesoftware.bluewater.client.browsing.library.settings.access.LibrarySettingsAccess
@@ -56,6 +57,7 @@ import com.lasthopesoftware.bluewater.shared.messages.application.RegisterForApp
5657
import com.lasthopesoftware.bluewater.shared.messages.application.SendApplicationMessages
5758
import com.lasthopesoftware.resources.bitmaps.DefaultAwareCachingBitmapProducer
5859
import com.lasthopesoftware.resources.bitmaps.QueuedBitmapProducer
60+
import com.lasthopesoftware.resources.closables.AutoCloseableManager
5961
import com.lasthopesoftware.resources.network.ActiveNetworkFinder
6062
import com.lasthopesoftware.resources.strings.Base64Encoder
6163
import com.lasthopesoftware.resources.strings.JsonEncoderDecoder
@@ -82,13 +84,16 @@ object ApplicationDependenciesContainer {
8284
?.takeIf { it.context == applicationContext }
8385
?: run {
8486
val newDependencies = AttachedDependencies(applicationContext)
87+
attachedDependencies?.close()
8588
attachedDependencies = newDependencies
8689
newDependencies
8790
}
8891
}
8992

9093
@UnstableApi
91-
private class AttachedDependencies(val context: Context) : ApplicationDependencies {
94+
private class AttachedDependencies(val context: Context) : ApplicationDependencies, AutoCloseable {
95+
96+
private val autoCloseableManager = AutoCloseableManager()
9297

9398
private val libraryRepository by lazy { LibraryRepository(context) }
9499

@@ -135,7 +140,12 @@ object ApplicationDependenciesContainer {
135140
}
136141

137142
override val selectedLibraryIdProvider by lazy {
138-
CachedSelectedLibraryIdProvider(SelectedLibraryIdProvider(applicationSettings))
143+
CachedSelectedLibraryIdProvider(
144+
SelectedLibraryIdProvider(applicationSettings),
145+
autoCloseableManager.manage(
146+
SelectedLibraryIdCache(registerForApplicationMessages)
147+
),
148+
)
139149
}
140150

141151
override val nowPlayingStateMaintenance by lazy {
@@ -260,5 +270,9 @@ object ApplicationDependenciesContainer {
260270
override val stringResources by lazy { StringResources(context) }
261271

262272
override val nowPlayingDisplaySettings by lazy { InMemoryNowPlayingDisplaySettings() }
273+
274+
override fun close() {
275+
autoCloseableManager.close()
276+
}
263277
}
264278
}

projectBlueWater/src/main/java/com/lasthopesoftware/bluewater/android/intents/IntentBuilder.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class IntentBuilder(private val context: Context) : BuildIntents {
3232
override fun buildLibrarySettingsIntent(libraryId: LibraryId): Intent = getBrowserActivityIntent(ConnectionSettingsScreen(libraryId))
3333
override fun buildLibraryServerSettingsPendingIntent(libraryId: LibraryId): PendingIntent {
3434
val baseIntent = buildLibrarySettingsIntent(libraryId)
35-
return PendingIntent.getActivity(context, 0, baseIntent, 0.makePendingIntentImmutable())
35+
return PendingIntent.getActivity(context, 0, baseIntent, PendingIntent.FLAG_UPDATE_CURRENT.makePendingIntentImmutable())
3636
}
3737

3838
@OptIn(UnstableApi::class)
@@ -45,15 +45,15 @@ class IntentBuilder(private val context: Context) : BuildIntents {
4545

4646
override fun buildPendingNowPlayingIntent(libraryId: LibraryId): PendingIntent {
4747
val intent = buildNowPlayingIntent(libraryId)
48-
return PendingIntent.getActivity(context, 0, intent, 0.makePendingIntentImmutable())
48+
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT.makePendingIntentImmutable())
4949
}
5050

5151
@OptIn(UnstableApi::class)
5252
override fun buildPendingPausePlaybackIntent(): PendingIntent = PlaybackService.pendingPauseIntent(context)
5353

5454
override fun buildPendingShowDownloadsIntent(): PendingIntent {
5555
val baseIntent = buildShowDownloadsIntent()
56-
return PendingIntent.getActivity(context, 0, baseIntent, 0.makePendingIntentImmutable())
56+
return PendingIntent.getActivity(context, 0, baseIntent, PendingIntent.FLAG_UPDATE_CURRENT.makePendingIntentImmutable())
5757
}
5858

5959
private fun buildShowDownloadsIntent(): Intent = getBrowserActivityIntent(ActiveLibraryDownloadsScreen)

projectBlueWater/src/main/java/com/lasthopesoftware/bluewater/client/HandheldApplication.kt

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ import com.lasthopesoftware.bluewater.client.browsing.ScopedViewModelDependencie
4141
import com.lasthopesoftware.bluewater.client.browsing.ScopedViewModelRegistry
4242
import com.lasthopesoftware.bluewater.client.browsing.files.details.FileDetailsView
4343
import com.lasthopesoftware.bluewater.client.browsing.files.properties.LibraryFilePropertiesDependentsRegistry
44-
import com.lasthopesoftware.bluewater.client.browsing.library.repository.LibraryId
4544
import com.lasthopesoftware.bluewater.client.browsing.navigation.ActiveLibraryDownloadsScreen
4645
import com.lasthopesoftware.bluewater.client.browsing.navigation.ApplicationSettingsScreen
4746
import com.lasthopesoftware.bluewater.client.browsing.navigation.BrowserLibraryDestination
@@ -377,40 +376,38 @@ fun HandheldApplication(
377376
is SelectedLibraryReRouter -> {
378377
routedNavigationDependencies.apply {
379378
LaunchedEffect(key1 = Unit) {
380-
try {
381-
val settings =
382-
applicationSettings.promiseApplicationSettings().suspend()
383-
if (settings.chosenLibraryId > -1) {
384-
val libraryId = LibraryId(settings.chosenLibraryId)
385-
applicationNavigation.viewLibrary(libraryId).suspend()
386-
return@LaunchedEffect
387-
}
379+
val selectedLibraryId = try {
380+
selectedLibraryIdProvider.promiseSelectedLibraryId().suspend()
388381
} catch (e: Throwable) {
389382
logger.error("An error occurred initializing the library", e)
383+
null
390384
}
391385

392-
applicationNavigation.backOut().suspend()
386+
if (selectedLibraryId != null && selectedLibraryId.id > -1) {
387+
applicationNavigation.viewLibrary(selectedLibraryId).suspend()
388+
} else {
389+
applicationNavigation.backOut().suspend()
390+
}
393391
}
394392
}
395393
}
396394

397395
is ActiveLibraryDownloadsScreen -> {
398396
routedNavigationDependencies.apply {
399397
LaunchedEffect(key1 = Unit) {
400-
try {
401-
val settings =
402-
applicationSettings.promiseApplicationSettings().suspend()
403-
if (settings.chosenLibraryId > -1) {
404-
val libraryId = LibraryId(settings.chosenLibraryId)
405-
applicationNavigation.viewLibrary(libraryId).suspend()
406-
applicationNavigation.viewActiveDownloads(libraryId).suspend()
407-
return@LaunchedEffect
408-
}
398+
val selectedLibraryId = try {
399+
selectedLibraryIdProvider.promiseSelectedLibraryId().suspend()
409400
} catch (e: Throwable) {
410401
logger.error("An error occurred initializing the library", e)
402+
null
411403
}
412404

413-
applicationNavigation.backOut().suspend()
405+
if (selectedLibraryId != null && selectedLibraryId.id > -1) {
406+
applicationNavigation.viewLibrary(selectedLibraryId).suspend()
407+
applicationNavigation.viewActiveDownloads(selectedLibraryId).suspend()
408+
} else {
409+
applicationNavigation.backOut().suspend()
410+
}
414411
}
415412
}
416413
}
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,13 @@
11
package com.lasthopesoftware.bluewater.client.browsing.library.access.session
22

33
import com.lasthopesoftware.bluewater.client.browsing.library.repository.LibraryId
4-
import com.lasthopesoftware.bluewater.shared.messages.application.ApplicationMessageBus
5-
import com.lasthopesoftware.bluewater.shared.messages.registerReceiver
6-
import com.lasthopesoftware.promises.extensions.toPromise
74
import com.namehillsoftware.handoff.promises.Promise
8-
import java.util.concurrent.atomic.AtomicReference
95

106
class CachedSelectedLibraryIdProvider(
117
private val inner: ProvideSelectedLibraryId,
12-
private val selectedLibraryIdCache: HoldSelectedLibraryId = SelectedLibraryIdCache
8+
private val selectedLibraryIdCache: HoldSelectedLibraryId,
139
) : ProvideSelectedLibraryId
1410
{
15-
private object SelectedLibraryIdCache : HoldSelectedLibraryId, (BrowserLibrarySelection.LibraryChosenMessage) -> Unit {
16-
private val cachedPromisedLibrary = AtomicReference<Promise<LibraryId?>?>(null)
17-
18-
init {
19-
ApplicationMessageBus.getApplicationMessageBus().registerReceiver(this)
20-
}
21-
22-
override fun getOrCache(factory: () -> Promise<LibraryId?>): Promise<LibraryId?> =
23-
with(cachedPromisedLibrary) {
24-
var cachedPromise = get()
25-
while (cachedPromise == null) {
26-
set(factory())
27-
cachedPromise = get()
28-
}
29-
30-
cachedPromise
31-
}
32-
33-
override fun invoke(message: BrowserLibrarySelection.LibraryChosenMessage) {
34-
cachedPromisedLibrary.compareAndSet(cachedPromisedLibrary.get(), message.chosenLibraryId.toPromise())
35-
}
36-
}
3711

3812
override fun promiseSelectedLibraryId(): Promise<LibraryId?> = selectedLibraryIdCache.getOrCache(inner::promiseSelectedLibraryId)
3913
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.lasthopesoftware.bluewater.client.browsing.library.access.session
2+
3+
import com.lasthopesoftware.bluewater.client.browsing.library.repository.LibraryId
4+
import com.lasthopesoftware.bluewater.shared.messages.application.RegisterForApplicationMessages
5+
import com.lasthopesoftware.bluewater.shared.messages.registerReceiver
6+
import com.lasthopesoftware.bluewater.shared.updateIfDifferent
7+
import com.lasthopesoftware.promises.extensions.toPromise
8+
import com.namehillsoftware.handoff.promises.Promise
9+
import java.util.concurrent.atomic.AtomicReference
10+
11+
class SelectedLibraryIdCache(
12+
messageBus: RegisterForApplicationMessages,
13+
) : HoldSelectedLibraryId, AutoCloseable, (BrowserLibrarySelection.LibraryChosenMessage) -> Unit {
14+
val cachedPromisedLibrary = AtomicReference<Promise<LibraryId?>?>(null)
15+
16+
val subscription = messageBus.registerReceiver(this)
17+
18+
override fun getOrCache(factory: () -> Promise<LibraryId?>): Promise<LibraryId?> =
19+
with(cachedPromisedLibrary) {
20+
var cachedPromise = get()
21+
while (cachedPromise == null) {
22+
set(factory())
23+
cachedPromise = get()
24+
}
25+
26+
cachedPromise
27+
}
28+
29+
override fun invoke(message: BrowserLibrarySelection.LibraryChosenMessage) {
30+
cachedPromisedLibrary.updateIfDifferent( message.chosenLibraryId.toPromise())
31+
}
32+
33+
override fun close() {
34+
subscription.close()
35+
}
36+
}

projectBlueWater/src/main/java/com/lasthopesoftware/bluewater/client/browsing/navigation/BrowserDestinations.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ sealed interface LibraryDestination : Destination {
3535
class ConnectionSettingsScreen(override val libraryId: LibraryId) : LibraryDestination
3636

3737
@Parcelize
38-
class NowPlayingScreen(override val libraryId: LibraryId) : LibraryDestination
38+
data class NowPlayingScreen(override val libraryId: LibraryId) : LibraryDestination
3939

4040
@Parcelize
4141
class ListedFileDetailsScreen(

projectBlueWater/src/main/java/com/lasthopesoftware/bluewater/client/playback/engine/PlaybackEngine.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ class PlaybackEngine(
420420
maybeNp
421421
?.takeIf {
422422
playerId.isCurrentPlayerId() &&
423-
attachedLibraryId == activeLibraryId.get() &&
423+
it.libraryId == activeLibraryId.get() &&
424424
it.playlistPosition == p.playlistPosition &&
425425
it.filePosition == progress.millis
426426
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.lasthopesoftware.bluewater.client.playback.nowplaying.intent.GivenTheActiveLibraryIdChanges
2+
3+
import android.content.Intent
4+
import androidx.test.core.app.ApplicationProvider
5+
import com.lasthopesoftware.AndroidContext
6+
import com.lasthopesoftware.bluewater.android.intents.IntentBuilder
7+
import com.lasthopesoftware.bluewater.android.intents.safelyGetParcelableExtra
8+
import com.lasthopesoftware.bluewater.client.browsing.library.repository.LibraryId
9+
import com.lasthopesoftware.bluewater.client.browsing.navigation.NowPlayingScreen
10+
import com.lasthopesoftware.bluewater.client.destinationProperty
11+
import org.assertj.core.api.Assertions.assertThat
12+
import org.junit.Test
13+
import org.robolectric.Shadows
14+
15+
class WhenBuildingTheNowPlayingIntent : AndroidContext() {
16+
companion object {
17+
private var returnedIntent: Intent? = null
18+
}
19+
20+
override fun before() {
21+
val intentBuilder = IntentBuilder(ApplicationProvider.getApplicationContext())
22+
intentBuilder.buildPendingNowPlayingIntent(LibraryId(559))
23+
val pendingIntent = intentBuilder.buildPendingNowPlayingIntent(LibraryId(844))
24+
val shadow = Shadows.shadowOf(pendingIntent)
25+
returnedIntent = shadow.savedIntent
26+
}
27+
28+
@Test
29+
fun `then the returned intent has the correct library`() {
30+
assertThat(returnedIntent?.safelyGetParcelableExtra<NowPlayingScreen>(destinationProperty)).isEqualTo(
31+
NowPlayingScreen(
32+
LibraryId(844)
33+
)
34+
)
35+
}
36+
}

0 commit comments

Comments
 (0)