Skip to content

Commit 18856e0

Browse files
authored
Merge pull request #513 from namehillsoftware/chore/use-initialization-providers
[Chore] Use Initialization Providers
2 parents 94a924b + 34bce4c commit 18856e0

23 files changed

+337
-361
lines changed

projectBlueWater/src/main/AndroidManifest.xml

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
<uses-permission android:name="android.permission.RUN_USER_INITIATED_JOBS" />
2424

2525
<application
26-
android:name=".ProjectBlueApplication"
2726
android:allowBackup="true"
2827
android:icon="@mipmap/launcher_icon"
2928
android:label="@string/app_name"
@@ -74,14 +73,6 @@
7473
<action android:name="android.intent.action.MEDIA_BUTTON" />
7574
</intent-filter>
7675
</receiver>
77-
<receiver
78-
android:name=".client.stored.sync.DeviceBootSyncScheduler"
79-
android:enabled="true"
80-
android:exported="true">
81-
<intent-filter>
82-
<action android:name="android.intent.action.BOOT_COMPLETED" />
83-
</intent-filter>
84-
</receiver>
8576

8677
<service
8778
android:name=".client.playback.service.PlaybackService"
@@ -123,7 +114,19 @@
123114
tools:node="merge">
124115

125116
<meta-data
126-
android:name="com.lasthopesoftware.bluewater.SyncSchedulerInitializer"
117+
android:name="com.lasthopesoftware.bluewater.client.stored.sync.SyncSchedulerInitializer"
118+
android:value="androidx.startup" />
119+
120+
<meta-data
121+
android:name="com.lasthopesoftware.bluewater.client.playback.nowplaying.storage.LiveNowPlayingLookupInitializer"
122+
android:value="androidx.startup" />
123+
124+
<meta-data
125+
android:name="com.lasthopesoftware.bluewater.LoggerFactoryInitializer"
126+
android:value="androidx.startup" />
127+
128+
<meta-data
129+
android:name="com.lasthopesoftware.bluewater.MessageReceiversInitializer"
127130
android:value="androidx.startup" />
128131

129132
</provider>

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.lasthopesoftware.bluewater
22

33
import androidx.activity.ComponentActivity
4-
import androidx.media3.common.util.UnstableApi
54
import com.lasthopesoftware.bluewater.client.ActivitySuppliedDependencies
65
import com.lasthopesoftware.bluewater.client.browsing.EntryDependencies
76
import com.lasthopesoftware.bluewater.client.browsing.items.list.ReusableChildItemViewModelProvider
@@ -16,7 +15,6 @@ import com.lasthopesoftware.bluewater.client.connection.settings.changes.Observa
1615
import com.lasthopesoftware.bluewater.client.connection.trust.UserSslCertificateProvider
1716
import com.lasthopesoftware.bluewater.client.playback.engine.selection.SelectedPlaybackEngineTypeAccess
1817
import com.lasthopesoftware.bluewater.client.playback.engine.selection.defaults.DefaultPlaybackEngineLookup
19-
import com.lasthopesoftware.bluewater.client.playback.nowplaying.storage.LiveNowPlayingLookup
2018
import com.lasthopesoftware.bluewater.client.stored.library.items.StateChangeBroadcastingStoredItemAccess
2119
import com.lasthopesoftware.bluewater.client.stored.library.items.files.StoredFileAccess
2220
import com.lasthopesoftware.bluewater.settings.ApplicationSettingsViewModel
@@ -31,7 +29,6 @@ import com.lasthopesoftware.bluewater.shared.messages.application.getScopedMessa
3129
import com.lasthopesoftware.resources.closables.ViewModelCloseableManager
3230
import com.lasthopesoftware.resources.uri.DocumentUriSelector
3331

34-
@UnstableApi
3532
class ActivityDependencies(
3633
activity: ComponentActivity,
3734
activitySuppliedDependencies: ActivitySuppliedDependencies,
@@ -68,8 +65,6 @@ class ActivityDependencies(
6865

6966
override val itemListMenuBackPressedHandler by lazy { ItemListMenuBackPressedHandler(menuMessageBus).also(viewModelScope::manage) }
7067

71-
override val nowPlayingState by lazy { LiveNowPlayingLookup.getInstance() }
72-
7368
override val storedItemAccess by lazy {
7469
StateChangeBroadcastingStoredItemAccess(applicationDependencies.storedItemAccess, messageBus)
7570
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import com.lasthopesoftware.bluewater.client.browsing.library.access.ILibrarySto
88
import com.lasthopesoftware.bluewater.client.browsing.library.access.session.ProvideSelectedLibraryId
99
import com.lasthopesoftware.bluewater.client.connection.libraries.ProvideLibraryConnections
1010
import com.lasthopesoftware.bluewater.client.connection.session.ManageConnectionSessions
11+
import com.lasthopesoftware.bluewater.client.playback.nowplaying.storage.GetNowPlayingState
1112
import com.lasthopesoftware.bluewater.client.playback.service.ControlPlaybackService
1213
import com.lasthopesoftware.bluewater.client.stored.library.items.AccessStoredItems
1314
import com.lasthopesoftware.bluewater.client.stored.sync.ScheduleSyncs
@@ -38,5 +39,6 @@ interface ApplicationDependencies {
3839
val selectedLibraryIdProvider: ProvideSelectedLibraryId
3940
val stringResources: GetStringResources
4041
val applicationSettings: HoldApplicationSettings
42+
val nowPlayingState: GetNowPlayingState
4143
}
4244

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ import com.lasthopesoftware.bluewater.client.connection.testing.ConnectionTester
3232
import com.lasthopesoftware.bluewater.client.connection.waking.AlarmConfiguration
3333
import com.lasthopesoftware.bluewater.client.connection.waking.ServerAlarm
3434
import com.lasthopesoftware.bluewater.client.connection.waking.ServerWakeSignal
35+
import com.lasthopesoftware.bluewater.client.playback.nowplaying.storage.LiveNowPlayingLookupInitializer
3536
import com.lasthopesoftware.bluewater.client.playback.service.PlaybackServiceController
3637
import com.lasthopesoftware.bluewater.client.stored.library.items.StoredItemAccess
38+
import com.lasthopesoftware.bluewater.client.stored.sync.SyncSchedulerInitializer
3739
import com.lasthopesoftware.bluewater.settings.repository.access.ApplicationSettingsRepository
3840
import com.lasthopesoftware.bluewater.settings.repository.access.CachingApplicationSettingsRepository
3941
import com.lasthopesoftware.bluewater.shared.android.ui.ScreenDimensions
@@ -94,6 +96,12 @@ object ApplicationDependenciesContainer {
9496
CachedSelectedLibraryIdProvider(SelectedLibraryIdProvider(applicationSettings))
9597
}
9698

99+
override val nowPlayingState by lazy {
100+
AppInitializer
101+
.getInstance(context)
102+
.initializeComponent(cls<LiveNowPlayingLookupInitializer>())
103+
}
104+
97105
override val libraryProvider: ILibraryProvider
98106
get() = libraryRepository
99107

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package com.lasthopesoftware.bluewater
2+
3+
import android.content.Context
4+
import android.os.Environment
5+
import android.os.StrictMode
6+
import android.os.StrictMode.VmPolicy
7+
import androidx.startup.Initializer
8+
import ch.qos.logback.classic.AsyncAppender
9+
import ch.qos.logback.classic.Level
10+
import ch.qos.logback.classic.Logger
11+
import ch.qos.logback.classic.LoggerContext
12+
import ch.qos.logback.classic.android.LogcatAppender
13+
import ch.qos.logback.classic.encoder.PatternLayoutEncoder
14+
import ch.qos.logback.classic.spi.ILoggingEvent
15+
import ch.qos.logback.core.rolling.RollingFileAppender
16+
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy
17+
import ch.qos.logback.core.util.StatusPrinter
18+
import com.lasthopesoftware.bluewater.ApplicationDependenciesContainer.applicationDependencies
19+
import com.lasthopesoftware.bluewater.settings.ApplicationSettingsUpdated
20+
import com.lasthopesoftware.bluewater.settings.repository.ApplicationSettings
21+
import com.lasthopesoftware.bluewater.shared.exceptions.UncaughtExceptionHandlerLogger
22+
import com.lasthopesoftware.bluewater.shared.lazyLogger
23+
import com.lasthopesoftware.bluewater.shared.messages.registerReceiver
24+
import com.lasthopesoftware.compilation.DebugFlag
25+
import com.namehillsoftware.handoff.promises.Promise
26+
import org.slf4j.ILoggerFactory
27+
import org.slf4j.LoggerFactory
28+
import java.io.File
29+
30+
class LoggerFactoryInitializer : Initializer<ILoggerFactory> {
31+
companion object {
32+
private val logger by lazyLogger<LoggerFactoryInitializer>()
33+
}
34+
35+
@Volatile
36+
private var isLoggingToFile = true
37+
38+
override fun create(context: Context): ILoggerFactory {
39+
Promise.Rejections.toggleStackTraceFiltering(true)
40+
41+
val loggerFactory = initializeLogging(context)
42+
43+
Thread.setDefaultUncaughtExceptionHandler(UncaughtExceptionHandlerLogger)
44+
Promise.Rejections.setUnhandledRejectionsReceiver(UncaughtExceptionHandlerLogger)
45+
46+
with (context.applicationDependencies) {
47+
context
48+
.applicationDependencies
49+
.applicationSettings
50+
.promiseApplicationSettings()
51+
.then { settings ->
52+
reinitializeLoggingIfNecessary(context, settings)
53+
}
54+
55+
registerForApplicationMessages.registerReceiver { _: ApplicationSettingsUpdated ->
56+
applicationSettings
57+
.promiseApplicationSettings()
58+
.then { settings ->
59+
reinitializeLoggingIfNecessary(context, settings)
60+
}
61+
}
62+
}
63+
64+
return loggerFactory
65+
}
66+
67+
override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
68+
69+
private fun reinitializeLoggingIfNecessary(context: Context, applicationSettings: ApplicationSettings) {
70+
if (applicationSettings.isLoggingToFile != isLoggingToFile) {
71+
isLoggingToFile = applicationSettings.isLoggingToFile
72+
initializeLogging(context)
73+
74+
logger.info("File logging {}.", if (isLoggingToFile) "enabled" else "disabled")
75+
}
76+
}
77+
78+
private fun initializeLogging(context: Context): ILoggerFactory {
79+
val loggerFactory = LoggerFactory.getILoggerFactory()
80+
val lc = loggerFactory as? LoggerContext ?: return loggerFactory
81+
lc.reset()
82+
83+
// setup LogcatAppender
84+
val logcatEncoder = PatternLayoutEncoder()
85+
logcatEncoder.context = lc
86+
logcatEncoder.pattern = "[%thread] %msg%n"
87+
logcatEncoder.start()
88+
val logcatAppender = LogcatAppender()
89+
logcatAppender.context = lc
90+
logcatAppender.encoder = logcatEncoder
91+
logcatAppender.start()
92+
// add the newly created appenders to the root logger;
93+
// qualify Logger to disambiguate from org.slf4j.Logger
94+
val rootLogger = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME) as Logger
95+
rootLogger.level = Level.WARN
96+
rootLogger.addAppender(logcatAppender)
97+
if (isLoggingToFile && Environment.MEDIA_MOUNTED == Environment.getExternalStorageState() && context.getExternalFilesDir(null) != null) {
98+
val asyncAppender = AsyncAppender()
99+
asyncAppender.context = lc
100+
asyncAppender.name = "ASYNC"
101+
val externalFilesDir = context.getExternalFilesDir(null)
102+
if (externalFilesDir != null) {
103+
val logDir = File(externalFilesDir.path + File.separator + "logs")
104+
if (!logDir.exists()) logDir.mkdirs()
105+
val rollingFileAppender = RollingFileAppender<ILoggingEvent>().apply {
106+
lazy = true
107+
isAppend = true
108+
this.context = lc
109+
file = File(logDir, "log.log").absolutePath
110+
111+
rollingPolicy = TimeBasedRollingPolicy<ILoggingEvent>()
112+
.also { it.setParent(this) }
113+
.apply {
114+
fileNamePattern = File(logDir, "%d{yyyy-MM-dd}.log").absolutePath
115+
maxHistory = 5
116+
this.context = lc
117+
start()
118+
}
119+
120+
encoder = PatternLayoutEncoder().apply {
121+
pattern = "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
122+
this.context = lc
123+
start()
124+
}
125+
126+
start()
127+
}
128+
129+
asyncAppender.addAppender(rollingFileAppender)
130+
}
131+
132+
// UNCOMMENT TO TWEAK OPTIONAL SETTINGS
133+
// excluding caller data (used for stack traces) improves appender's performance
134+
asyncAppender.isIncludeCallerData = !DebugFlag.isDebugCompilation
135+
136+
asyncAppender.start()
137+
rootLogger.addAppender(asyncAppender)
138+
StatusPrinter.print(lc)
139+
}
140+
141+
if (DebugFlag.isDebugCompilation) {
142+
rootLogger.level = Level.DEBUG
143+
logger.info("DEBUG_MODE active")
144+
StrictMode.setThreadPolicy(
145+
StrictMode.ThreadPolicy.Builder()
146+
.detectDiskReads()
147+
.detectDiskWrites()
148+
.detectNetwork() // or .detectAll() for all detectable problems
149+
.penaltyLog()
150+
.build()
151+
)
152+
StrictMode.setVmPolicy(
153+
VmPolicy.Builder()
154+
.detectLeakedSqlLiteObjects()
155+
.penaltyLog()
156+
.build()
157+
)
158+
}
159+
160+
return loggerFactory
161+
}
162+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package com.lasthopesoftware.bluewater
2+
3+
import android.app.NotificationManager
4+
import android.content.Context
5+
import androidx.startup.Initializer
6+
import com.lasthopesoftware.bluewater.ApplicationDependenciesContainer.applicationDependencies
7+
import com.lasthopesoftware.bluewater.client.connection.libraries.LibraryConnectionRegistry
8+
import com.lasthopesoftware.bluewater.client.connection.session.ConnectionSessionSettingsChangeReceiver
9+
import com.lasthopesoftware.bluewater.client.playback.nowplaying.broadcasters.notification.NotificationsConfiguration
10+
import com.lasthopesoftware.bluewater.client.playback.service.receivers.scrobble.PlaybackFileStartedScrobbleDroidProxy
11+
import com.lasthopesoftware.bluewater.client.playback.service.receivers.scrobble.PlaybackFileStoppedScrobbleDroidProxy
12+
import com.lasthopesoftware.bluewater.client.playback.service.receivers.scrobble.ScrobbleIntentProvider
13+
import com.lasthopesoftware.bluewater.client.stored.library.permissions.StoragePermissionsRequestNotificationBuilder
14+
import com.lasthopesoftware.bluewater.client.stored.library.permissions.read.StorageReadPermissionsRequestNotificationBuilder
15+
import com.lasthopesoftware.bluewater.client.stored.library.permissions.read.StorageReadPermissionsRequestedBroadcaster
16+
import com.lasthopesoftware.bluewater.client.stored.sync.notifications.SyncChannelProperties
17+
import com.lasthopesoftware.bluewater.client.stored.sync.receivers.SyncItemStateChangedListener
18+
import com.lasthopesoftware.bluewater.shared.messages.registerReceiver
19+
20+
class MessageReceiversInitializer : Initializer<Unit> {
21+
override fun create(context: Context) {
22+
with (context.applicationDependencies) {
23+
registerForApplicationMessages.registerReceiver(ConnectionSessionSettingsChangeReceiver(connectionSessions))
24+
25+
val notificationManager by lazy { context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager }
26+
27+
val syncChannelProperties by lazy { SyncChannelProperties(context) }
28+
29+
val storageReadPermissionsConfiguration by lazy {
30+
NotificationsConfiguration(
31+
syncChannelProperties.channelId,
32+
336
33+
)
34+
}
35+
36+
val storagePermissionsRequestNotificationBuilder by lazy {
37+
StoragePermissionsRequestNotificationBuilder(
38+
context,
39+
stringResources,
40+
intentBuilder,
41+
syncChannelProperties
42+
)
43+
}
44+
45+
val storageReadPermissionsRequestNotificationBuilder by lazy {
46+
StorageReadPermissionsRequestNotificationBuilder(storagePermissionsRequestNotificationBuilder)
47+
}
48+
49+
registerForApplicationMessages.registerReceiver { readPermissionsNeeded : StorageReadPermissionsRequestedBroadcaster.ReadPermissionsNeeded ->
50+
notificationManager.notify(
51+
storageReadPermissionsConfiguration.notificationId,
52+
storageReadPermissionsRequestNotificationBuilder
53+
.buildReadPermissionsRequestNotification(readPermissionsNeeded.libraryId.id))
54+
}
55+
56+
registerForApplicationMessages.registerReceiver(
57+
PlaybackFileStartedScrobbleDroidProxy(
58+
context,
59+
LibraryConnectionRegistry(this).libraryFilePropertiesProvider,
60+
ScrobbleIntentProvider,
61+
)
62+
)
63+
64+
registerForApplicationMessages.registerReceiver(
65+
PlaybackFileStoppedScrobbleDroidProxy(context, ScrobbleIntentProvider)
66+
)
67+
68+
registerForApplicationMessages.registerReceiver(SyncItemStateChangedListener(syncScheduler))
69+
}
70+
}
71+
72+
override fun dependencies(): List<Class<out Initializer<*>>> = emptyList()
73+
}

0 commit comments

Comments
 (0)