talk-android/app/src/main/java/com/nextcloud/talk/application/NextcloudTalkApplication.kt
Andy Scherzinger 3eabf9bb83
Add SPDX header
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
2024-03-29 12:55:12 +01:00

261 lines
9.0 KiB
Kotlin

/*
* Nextcloud Talk - Android Client
*
* SPDX-FileCopyrightText: 2022 Andy Scherzinger <info@andy-scherzinger.de>
* SPDX-FileCopyrightText: 2022 Marcel Hibbe <dev@mhibbe.de>
* SPDX-FileCopyrightText: 2022 Tim Krüger <t@timkrueger.me>
* SPDX-FileCopyrightText: 2017 Mario Danic <mario@lovelyhq.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
package com.nextcloud.talk.application
import android.content.Context
import android.os.Build.VERSION.SDK_INT
import android.os.Build.VERSION_CODES.P
import android.util.Log
import androidx.appcompat.app.AppCompatDelegate
import androidx.emoji2.bundled.BundledEmojiCompatConfig
import androidx.emoji2.text.EmojiCompat
import androidx.lifecycle.LifecycleObserver
import androidx.multidex.MultiDex
import androidx.multidex.MultiDexApplication
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.OneTimeWorkRequest
import androidx.work.PeriodicWorkRequest
import androidx.work.WorkManager
import autodagger.AutoComponent
import autodagger.AutoInjector
import coil.Coil
import coil.ImageLoader
import coil.decode.GifDecoder
import coil.decode.ImageDecoderDecoder
import coil.decode.SvgDecoder
import coil.memory.MemoryCache
import coil.util.DebugLogger
import com.nextcloud.talk.BuildConfig
import com.nextcloud.talk.components.filebrowser.webdav.DavUtils
import com.nextcloud.talk.dagger.modules.BusModule
import com.nextcloud.talk.dagger.modules.ContextModule
import com.nextcloud.talk.dagger.modules.DatabaseModule
import com.nextcloud.talk.dagger.modules.RepositoryModule
import com.nextcloud.talk.dagger.modules.RestModule
import com.nextcloud.talk.dagger.modules.UtilsModule
import com.nextcloud.talk.dagger.modules.ViewModelModule
import com.nextcloud.talk.jobs.AccountRemovalWorker
import com.nextcloud.talk.jobs.CapabilitiesWorker
import com.nextcloud.talk.jobs.SignalingSettingsWorker
import com.nextcloud.talk.jobs.WebsocketConnectionsWorker
import com.nextcloud.talk.ui.theme.ThemeModule
import com.nextcloud.talk.utils.ClosedInterfaceImpl
import com.nextcloud.talk.utils.DeviceUtils
import com.nextcloud.talk.utils.NotificationUtils
import com.nextcloud.talk.utils.database.arbitrarystorage.ArbitraryStorageModule
import com.nextcloud.talk.utils.database.user.UserModule
import com.nextcloud.talk.utils.preferences.AppPreferences
import com.vanniktech.emoji.EmojiManager
import com.vanniktech.emoji.google.GoogleEmojiProvider
import de.cotech.hw.SecurityKeyManager
import de.cotech.hw.SecurityKeyManagerConfig
import net.sqlcipher.database.SQLiteDatabase
import net.sqlcipher.database.SQLiteDatabaseHook
import okhttp3.OkHttpClient
import org.conscrypt.Conscrypt
import org.webrtc.PeerConnectionFactory
import java.security.Security
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Singleton
@AutoComponent(
modules = [
BusModule::class,
ContextModule::class,
DatabaseModule::class,
RestModule::class,
UserModule::class,
ArbitraryStorageModule::class,
ViewModelModule::class,
RepositoryModule::class,
UtilsModule::class,
ThemeModule::class
]
)
@Singleton
@AutoInjector(NextcloudTalkApplication::class)
class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
//region Fields (components)
lateinit var componentApplication: NextcloudTalkApplicationComponent
private set
//endregion
//region Getters
@Inject
lateinit var appPreferences: AppPreferences
@Inject
lateinit var okHttpClient: OkHttpClient
//endregion
val hook: SQLiteDatabaseHook = object : SQLiteDatabaseHook {
override fun preKey(database: SQLiteDatabase) {
// unused atm
}
override fun postKey(database: SQLiteDatabase) {
Log.i("TalkApplication", "DB cipher_migrate START")
database.rawExecSQL("PRAGMA cipher_migrate;")
Log.i("TalkApplication", "DB cipher_migrate END")
}
}
//region private methods
private fun initializeWebRtc() {
try {
PeerConnectionFactory.initialize(
PeerConnectionFactory.InitializationOptions.builder(this)
.createInitializationOptions()
)
} catch (e: UnsatisfiedLinkError) {
Log.w(TAG, e)
}
}
//endregion
//region Overridden methods
override fun onCreate() {
Log.d(TAG, "onCreate")
sharedApplication = this
val securityKeyManager = SecurityKeyManager.getInstance()
val securityKeyConfig = SecurityKeyManagerConfig.Builder()
.setEnableDebugLogging(BuildConfig.DEBUG)
.build()
securityKeyManager.init(this, securityKeyConfig)
initializeWebRtc()
buildComponent()
DavUtils.registerCustomFactories()
componentApplication.inject(this)
Coil.setImageLoader(buildDefaultImageLoader())
setAppTheme(appPreferences.theme)
super.onCreate()
Security.insertProviderAt(Conscrypt.newProvider(), 1)
ClosedInterfaceImpl().providerInstallerInstallIfNeededAsync()
DeviceUtils.ignoreSpecialBatteryFeatures()
initWorkers()
val config = BundledEmojiCompatConfig(this)
config.setReplaceAll(true)
val emojiCompat = EmojiCompat.init(config)
EmojiManager.install(GoogleEmojiProvider())
NotificationUtils.registerNotificationChannels(applicationContext, appPreferences)
}
private fun initWorkers() {
val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
val capabilitiesUpdateWork = OneTimeWorkRequest.Builder(CapabilitiesWorker::class.java).build()
val signalingSettingsWork = OneTimeWorkRequest.Builder(SignalingSettingsWorker::class.java).build()
val websocketConnectionsWorker = OneTimeWorkRequest.Builder(WebsocketConnectionsWorker::class.java).build()
WorkManager.getInstance(applicationContext)
.beginWith(accountRemovalWork)
.then(capabilitiesUpdateWork)
.then(signalingSettingsWork)
.then(websocketConnectionsWorker)
.enqueue()
val periodicCapabilitiesUpdateWork = PeriodicWorkRequest.Builder(
CapabilitiesWorker::class.java,
HALF_DAY,
TimeUnit.HOURS
).build()
WorkManager.getInstance(applicationContext).enqueueUniquePeriodicWork(
"DailyCapabilitiesUpdateWork",
ExistingPeriodicWorkPolicy.REPLACE,
periodicCapabilitiesUpdateWork
)
}
override fun onTerminate() {
super.onTerminate()
sharedApplication = null
}
//endregion
//region Protected methods
protected fun buildComponent() {
componentApplication = DaggerNextcloudTalkApplicationComponent.builder()
.busModule(BusModule())
.contextModule(ContextModule(applicationContext))
.databaseModule(DatabaseModule())
.restModule(RestModule(applicationContext))
.arbitraryStorageModule(ArbitraryStorageModule())
.build()
}
override fun attachBaseContext(base: Context) {
super.attachBaseContext(base)
MultiDex.install(this)
}
private fun buildDefaultImageLoader(): ImageLoader {
val imageLoaderBuilder = ImageLoader.Builder(applicationContext)
.memoryCache {
// Use 50% of the application's available memory.
MemoryCache.Builder(applicationContext).maxSizePercent(FIFTY_PERCENT).build()
}
.crossfade(true) // Show a short crossfade when loading images from network or disk into an ImageView.
.components {
if (SDK_INT >= P) {
add(ImageDecoderDecoder.Factory())
} else {
add(GifDecoder.Factory())
}
add(SvgDecoder.Factory())
}
if (BuildConfig.DEBUG) {
imageLoaderBuilder.logger(DebugLogger())
}
imageLoaderBuilder.okHttpClient(okHttpClient)
return imageLoaderBuilder.build()
}
companion object {
private val TAG = NextcloudTalkApplication::class.java.simpleName
const val FIFTY_PERCENT = 0.5
const val HALF_DAY: Long = 12
const val CIPHER_V4_MIGRATION: Int = 7
//region Singleton
//endregion
var sharedApplication: NextcloudTalkApplication? = null
protected set
//endregion
//region Setters
fun setAppTheme(theme: String) {
when (theme) {
"night_no" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
"night_yes" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
"battery_saver" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
else ->
// will be "follow_system" only for now
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
}
}
//endregion
}