package com.github.apognu.otter import android.app.Application import androidx.appcompat.app.AppCompatDelegate import androidx.room.Room import com.github.apognu.otter.models.dao.OtterDatabase import com.github.apognu.otter.playback.MediaSession import com.github.apognu.otter.playback.QueueManager import com.github.apognu.otter.utils.AppContext import com.github.apognu.otter.utils.Cache import com.github.apognu.otter.utils.Command import com.github.apognu.otter.utils.Event import com.google.android.exoplayer2.database.ExoDatabaseProvider import com.google.android.exoplayer2.offline.DefaultDownloadIndex import com.google.android.exoplayer2.offline.DefaultDownloaderFactory import com.google.android.exoplayer2.offline.DownloadManager import com.google.android.exoplayer2.offline.DownloaderConstructorHelper import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor import com.google.android.exoplayer2.upstream.cache.SimpleCache import com.preference.PowerPreference import io.realm.Realm import kotlinx.coroutines.channels.BroadcastChannel import java.text.SimpleDateFormat import java.util.* class Otter : Application() { companion object { private var instance: Otter = Otter() fun get(): Otter = instance } var defaultExceptionHandler: Thread.UncaughtExceptionHandler? = null val eventBus: BroadcastChannel = BroadcastChannel(10) val commandBus: BroadcastChannel = BroadcastChannel(10) val database: OtterDatabase by lazy { Room .databaseBuilder(this, OtterDatabase::class.java, "otter") .build() } private val exoDatabase: ExoDatabaseProvider by lazy { ExoDatabaseProvider(this) } val exoCache: SimpleCache by lazy { PowerPreference.getDefaultFile().getInt("media_cache_size", 1).toLong().let { val cacheSize = if (it == 0L) 0 else it * 1024 * 1024 * 1024 SimpleCache( cacheDir.resolve("media"), LeastRecentlyUsedCacheEvictor(cacheSize), exoDatabase ) } } val exoDownloadCache: SimpleCache by lazy { SimpleCache( cacheDir.resolve("downloads"), NoOpCacheEvictor(), exoDatabase ) } val exoDownloadManager: DownloadManager by lazy { DownloaderConstructorHelper(exoDownloadCache, QueueManager.factory(this)).run { DownloadManager(this@Otter, DefaultDownloadIndex(exoDatabase), DefaultDownloaderFactory(this)) } } val mediaSession = MediaSession(this) override fun onCreate() { super.onCreate() Realm.init(this) defaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler() Thread.setDefaultUncaughtExceptionHandler(CrashReportHandler()) instance = this when (PowerPreference.getDefaultFile().getString("night_mode")) { "on" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES) "off" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO) else -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) } } fun deleteAllData() { PowerPreference.getFileByName(AppContext.PREFS_CREDENTIALS).clear() cacheDir.listFiles()?.forEach { it.delete() } cacheDir.resolve("picasso-cache").deleteRecursively() } inner class CrashReportHandler : Thread.UncaughtExceptionHandler { override fun uncaughtException(t: Thread, e: Throwable) { val now = Date(Date().time - (5 * 60 * 1000)) val formatter = SimpleDateFormat("MM-dd kk:mm:ss.000", Locale.US) Runtime.getRuntime().exec(listOf("logcat", "-d", "-T", formatter.format(now)).toTypedArray()).also { it.inputStream.bufferedReader().also { reader -> val builder = StringBuilder() while (true) { builder.appendln(reader.readLine() ?: break) } builder.appendln(e.toString()) Cache.set(this@Otter, "crashdump", builder.toString().toByteArray()) } } defaultExceptionHandler?.uncaughtException(t, e) } } }