refactor: Use androidx.startup for startup activities (#762)
Move initialisation of WorkManager and Timber in to new `Initializer` classes, managed by `androidx.startup`. There's a false-positive `BadConfigurationProvider` lint message because the `Configuration.Provider` is in the content provider and not the application class.
This commit is contained in:
parent
b373ee9ffe
commit
bd6bc95b01
|
@ -73,6 +73,13 @@
|
||||||
column="9"/>
|
column="9"/>
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
<issue
|
||||||
|
id="BadConfigurationProvider"
|
||||||
|
message="Expected Application subtype to implement Configuration.Provider">
|
||||||
|
<location
|
||||||
|
file="src/main/java/app/pachli/PachliApplication.kt"/>
|
||||||
|
</issue>
|
||||||
|
|
||||||
<issue
|
<issue
|
||||||
id="SelectedPhotoAccess"
|
id="SelectedPhotoAccess"
|
||||||
message="Your app is currently not handling Selected Photos Access introduced in Android 14+"
|
message="Your app is currently not handling Selected Photos Access introduced in Android 14+"
|
||||||
|
|
|
@ -218,8 +218,22 @@
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.startup.InitializationProvider"
|
android:name="androidx.startup.InitializationProvider"
|
||||||
android:authorities="${applicationId}.androidx-startup"
|
android:authorities="${applicationId}.androidx-startup"
|
||||||
tools:node="remove" />
|
android:exported="false"
|
||||||
|
tools:node="merge">
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="app.pachli.initializer.DependencyGraphInitializer"
|
||||||
|
android:value="androidx.startup" />
|
||||||
|
<meta-data
|
||||||
|
android:name="app.pachli.initializer.TimberInitializer"
|
||||||
|
android:value="androidx.startup" />
|
||||||
|
<meta-data
|
||||||
|
android:name="app.pachli.initializer.WorkManagerInitializer"
|
||||||
|
android:value="androidx.startup" />
|
||||||
|
<meta-data
|
||||||
|
android:name="androidx.work.WorkManagerInitializer"
|
||||||
|
android:value="androidx.startup"
|
||||||
|
tools:node="remove" />
|
||||||
|
</provider>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -19,14 +19,11 @@ package app.pachli
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.hilt.work.HiltWorkerFactory
|
|
||||||
import androidx.work.Constraints
|
import androidx.work.Constraints
|
||||||
import androidx.work.ExistingPeriodicWorkPolicy
|
import androidx.work.ExistingPeriodicWorkPolicy
|
||||||
import androidx.work.PeriodicWorkRequestBuilder
|
import androidx.work.PeriodicWorkRequestBuilder
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import app.pachli.components.notifications.createWorkerNotificationChannel
|
import app.pachli.components.notifications.createWorkerNotificationChannel
|
||||||
import app.pachli.core.activity.LogEntryTree
|
|
||||||
import app.pachli.core.activity.TreeRing
|
|
||||||
import app.pachli.core.activity.initCrashReporter
|
import app.pachli.core.activity.initCrashReporter
|
||||||
import app.pachli.core.preferences.AppTheme
|
import app.pachli.core.preferences.AppTheme
|
||||||
import app.pachli.core.preferences.NEW_INSTALL_SCHEMA_VERSION
|
import app.pachli.core.preferences.NEW_INSTALL_SCHEMA_VERSION
|
||||||
|
@ -50,18 +47,12 @@ import timber.log.Timber
|
||||||
|
|
||||||
@HiltAndroidApp
|
@HiltAndroidApp
|
||||||
class PachliApplication : Application() {
|
class PachliApplication : Application() {
|
||||||
@Inject
|
|
||||||
lateinit var workerFactory: HiltWorkerFactory
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var localeManager: LocaleManager
|
lateinit var localeManager: LocaleManager
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var sharedPreferencesRepository: SharedPreferencesRepository
|
lateinit var sharedPreferencesRepository: SharedPreferencesRepository
|
||||||
|
|
||||||
@Inject
|
|
||||||
lateinit var logEntryTree: LogEntryTree
|
|
||||||
|
|
||||||
override fun attachBaseContext(base: Context?) {
|
override fun attachBaseContext(base: Context?) {
|
||||||
super.attachBaseContext(base)
|
super.attachBaseContext(base)
|
||||||
|
|
||||||
|
@ -83,12 +74,6 @@ class PachliApplication : Application() {
|
||||||
|
|
||||||
Security.insertProviderAt(Conscrypt.newProvider(), 1)
|
Security.insertProviderAt(Conscrypt.newProvider(), 1)
|
||||||
|
|
||||||
when {
|
|
||||||
BuildConfig.DEBUG -> Timber.plant(Timber.DebugTree())
|
|
||||||
BuildConfig.FLAVOR_color == "orange" -> Timber.plant(TreeRing)
|
|
||||||
}
|
|
||||||
Timber.plant(logEntryTree)
|
|
||||||
|
|
||||||
// Migrate shared preference keys and defaults from version to version.
|
// Migrate shared preference keys and defaults from version to version.
|
||||||
val oldVersion = sharedPreferencesRepository.getInt(PrefKeys.SCHEMA_VERSION, NEW_INSTALL_SCHEMA_VERSION)
|
val oldVersion = sharedPreferencesRepository.getInt(PrefKeys.SCHEMA_VERSION, NEW_INSTALL_SCHEMA_VERSION)
|
||||||
if (oldVersion != SCHEMA_VERSION) {
|
if (oldVersion != SCHEMA_VERSION) {
|
||||||
|
@ -108,12 +93,8 @@ class PachliApplication : Application() {
|
||||||
|
|
||||||
createWorkerNotificationChannel(this)
|
createWorkerNotificationChannel(this)
|
||||||
|
|
||||||
WorkManager.initialize(
|
|
||||||
this,
|
|
||||||
androidx.work.Configuration.Builder().setWorkerFactory(workerFactory).build(),
|
|
||||||
)
|
|
||||||
|
|
||||||
val workManager = WorkManager.getInstance(this)
|
val workManager = WorkManager.getInstance(this)
|
||||||
|
|
||||||
// Prune the database every ~ 12 hours when the device is idle.
|
// Prune the database every ~ 12 hours when the device is idle.
|
||||||
val pruneCacheWorker = PeriodicWorkRequestBuilder<PruneCacheWorker>(12, TimeUnit.HOURS)
|
val pruneCacheWorker = PeriodicWorkRequestBuilder<PruneCacheWorker>(12, TimeUnit.HOURS)
|
||||||
.setConstraints(Constraints.Builder().setRequiresDeviceIdle(true).build())
|
.setConstraints(Constraints.Builder().setRequiresDeviceIdle(true).build())
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Pachli Association
|
||||||
|
*
|
||||||
|
* This file is a part of Pachli.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
* Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||||
|
* see <http://www.gnu.org/licenses>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package app.pachli.di
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import app.pachli.initializer.TimberInitializer
|
||||||
|
import app.pachli.initializer.WorkManagerInitializer
|
||||||
|
import dagger.hilt.EntryPoint
|
||||||
|
import dagger.hilt.InstallIn
|
||||||
|
import dagger.hilt.android.EntryPointAccessors
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry point that allows [androidx.startup.Initializer] implementations
|
||||||
|
* to inject their dependencies.
|
||||||
|
*/
|
||||||
|
@EntryPoint
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
interface InitializerEntryPoint {
|
||||||
|
fun inject(timberInitializer: TimberInitializer)
|
||||||
|
fun inject(workManagerInitializer: WorkManagerInitializer)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun resolve(context: Context): InitializerEntryPoint {
|
||||||
|
val appContext = context.applicationContext ?: throw IllegalStateException()
|
||||||
|
return EntryPointAccessors.fromApplication(
|
||||||
|
appContext,
|
||||||
|
InitializerEntryPoint::class.java,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Pachli Association
|
||||||
|
*
|
||||||
|
* This file is a part of Pachli.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
* Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||||
|
* see <http://www.gnu.org/licenses>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package app.pachli.initializer
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.startup.Initializer
|
||||||
|
import app.pachli.di.InitializerEntryPoint
|
||||||
|
|
||||||
|
/** Empty root initializer other initialisers can depend on. */
|
||||||
|
class DependencyGraphInitializer : Initializer<Unit> {
|
||||||
|
override fun create(context: Context) {
|
||||||
|
InitializerEntryPoint.resolve(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dependencies(): List<Class<out Initializer<*>>> {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Pachli Association
|
||||||
|
*
|
||||||
|
* This file is a part of Pachli.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
* Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||||
|
* see <http://www.gnu.org/licenses>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package app.pachli.initializer
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.startup.Initializer
|
||||||
|
import app.pachli.BuildConfig
|
||||||
|
import app.pachli.core.activity.LogEntryTree
|
||||||
|
import app.pachli.core.activity.TreeRing
|
||||||
|
import app.pachli.di.InitializerEntryPoint
|
||||||
|
import javax.inject.Inject
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
/** Initialise [Timber]. */
|
||||||
|
class TimberInitializer : Initializer<Unit> {
|
||||||
|
@Inject
|
||||||
|
lateinit var logEntryTree: LogEntryTree
|
||||||
|
|
||||||
|
override fun create(context: Context) {
|
||||||
|
InitializerEntryPoint.resolve(context).inject(this)
|
||||||
|
|
||||||
|
when {
|
||||||
|
BuildConfig.DEBUG -> Timber.plant(Timber.DebugTree())
|
||||||
|
BuildConfig.FLAVOR_color == "orange" -> Timber.plant(TreeRing)
|
||||||
|
}
|
||||||
|
Timber.plant(logEntryTree)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dependencies(): List<Class<out Initializer<*>>> {
|
||||||
|
return listOf(DependencyGraphInitializer::class.java)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2024 Pachli Association
|
||||||
|
*
|
||||||
|
* This file is a part of Pachli.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||||
|
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||||
|
* License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Pachli is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||||
|
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||||
|
* Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with Pachli; if not,
|
||||||
|
* see <http://www.gnu.org/licenses>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package app.pachli.initializer
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.hilt.work.HiltWorkerFactory
|
||||||
|
import androidx.startup.Initializer
|
||||||
|
import androidx.work.Configuration
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import app.pachli.di.InitializerEntryPoint
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/** Initialise [WorkManager] with a [HiltWorkerFactory]. */
|
||||||
|
class WorkManagerInitializer : Initializer<WorkManager>, Configuration.Provider {
|
||||||
|
@Inject
|
||||||
|
lateinit var workerFactory: HiltWorkerFactory
|
||||||
|
|
||||||
|
override val workManagerConfiguration: Configuration
|
||||||
|
get() = Configuration.Builder().setWorkerFactory(workerFactory).build()
|
||||||
|
|
||||||
|
override fun create(context: Context): WorkManager {
|
||||||
|
InitializerEntryPoint.resolve(context).inject(this)
|
||||||
|
|
||||||
|
WorkManager.initialize(context, workManagerConfiguration)
|
||||||
|
return WorkManager.getInstance(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dependencies(): List<Class<out Initializer<*>>> {
|
||||||
|
return listOf(
|
||||||
|
DependencyGraphInitializer::class.java,
|
||||||
|
TimberInitializer::class.java,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@ androidx-preference = "1.2.1"
|
||||||
androidx-recyclerview = "1.3.2"
|
androidx-recyclerview = "1.3.2"
|
||||||
androidx-sharetarget = "1.2.0"
|
androidx-sharetarget = "1.2.0"
|
||||||
androidx-splashscreen = "1.0.1"
|
androidx-splashscreen = "1.0.1"
|
||||||
|
androidx-startup = "1.1.1"
|
||||||
androidx-swiperefresh-layout = "1.1.0"
|
androidx-swiperefresh-layout = "1.1.0"
|
||||||
androidx-testing = "2.2.0"
|
androidx-testing = "2.2.0"
|
||||||
androidx-test-core-ktx = "1.5.0"
|
androidx-test-core-ktx = "1.5.0"
|
||||||
|
@ -143,6 +144,7 @@ androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "androidx
|
||||||
androidx-room-testing = { module = "androidx.room:room-testing", version.ref = "androidx-room" }
|
androidx-room-testing = { module = "androidx.room:room-testing", version.ref = "androidx-room" }
|
||||||
androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "androidx-recyclerview" }
|
androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "androidx-recyclerview" }
|
||||||
androidx-sharetarget = { module = "androidx.sharetarget:sharetarget", version.ref = "androidx-sharetarget" }
|
androidx-sharetarget = { module = "androidx.sharetarget:sharetarget", version.ref = "androidx-sharetarget" }
|
||||||
|
androidx-startup = { module = "androidx.startup:startup-runtime", version.ref = "androidx-startup" }
|
||||||
androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "androidx-swiperefresh-layout" }
|
androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "androidx-swiperefresh-layout" }
|
||||||
androidx-test-core-ktx = { module = "androidx.test:core-ktx", version.ref = "androidx-test-core-ktx" }
|
androidx-test-core-ktx = { module = "androidx.test:core-ktx", version.ref = "androidx-test-core-ktx" }
|
||||||
androidx-test-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-junit" }
|
androidx-test-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-junit" }
|
||||||
|
@ -235,8 +237,7 @@ androidx = ["androidx-core-ktx", "androidx-appcompat", "androidx-fragment-ktx",
|
||||||
"androidx-constraintlayout", "androidx-paging-runtime-ktx", "androidx-viewpager2", "androidx-work-runtime-ktx",
|
"androidx-constraintlayout", "androidx-paging-runtime-ktx", "androidx-viewpager2", "androidx-work-runtime-ktx",
|
||||||
"androidx-core-splashscreen", "androidx-activity", "androidx-media3-exoplayer", "androidx-media3-exoplayer-dash",
|
"androidx-core-splashscreen", "androidx-activity", "androidx-media3-exoplayer", "androidx-media3-exoplayer-dash",
|
||||||
"androidx-media3-exoplayer-hls", "androidx-media3-exoplayer-rtsp", "androidx-media3-datasource-okhttp", "androidx-media3-ui",
|
"androidx-media3-exoplayer-hls", "androidx-media3-exoplayer-rtsp", "androidx-media3-datasource-okhttp", "androidx-media3-ui",
|
||||||
"androidx-transition",
|
"androidx-transition", "android-material", "androidx-startup"]
|
||||||
"android-material"]
|
|
||||||
filemojicompat = ["filemojicompat-core", "filemojicompat-ui", "filemojicompat-defaults"]
|
filemojicompat = ["filemojicompat-core", "filemojicompat-ui", "filemojicompat-defaults"]
|
||||||
glide = ["glide-core", "glide-okhttp3-integration", "glide-animation-plugin"]
|
glide = ["glide-core", "glide-okhttp3-integration", "glide-animation-plugin"]
|
||||||
lint-api = ["kotlin-stdlib", "lint-api", "lint-checks"]
|
lint-api = ["kotlin-stdlib", "lint-api", "lint-checks"]
|
||||||
|
|
Loading…
Reference in New Issue