Files
michas-droid/src/main/kotlin/com/michatec/store/MainApplication.kt
T
Michatec bdd204d9de - Migrate dependencies to Version Catalog (libs.versions.toml)
- Update Kotlin to 2.3.20 and Jackson Core to 2.21.2
- Update Gradle Wrapper to 9.4.1
- Bump version code to 17 and version name to 1.7
- Remove unused `percentTranslationY` property from `FragmentLinearLayout`
- Clean up semicolons in `MainApplication.kt`
- Update `.gitignore` to include `gradle-daemon-jvm.properties`
2026-03-24 13:07:06 +01:00

192 lines
6.7 KiB
Kotlin

package com.michatec.store
import android.annotation.SuppressLint
import android.app.Application
import android.app.job.JobInfo
import android.app.job.JobScheduler
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageInfo
import com.squareup.picasso.OkHttp3Downloader
import com.squareup.picasso.Picasso
import io.reactivex.rxjava3.disposables.Disposable
import com.michatec.store.content.Cache
import com.michatec.store.content.Preferences
import com.michatec.store.content.ProductPreferences
import com.michatec.store.database.Database
import com.michatec.store.entity.InstalledItem
import com.michatec.store.index.RepositoryUpdater
import com.michatec.store.network.Downloader
import com.michatec.store.network.PicassoDownloader
import com.michatec.store.service.Connection
import com.michatec.store.service.SyncService
import com.michatec.store.utility.Utils
import com.michatec.store.utility.extension.android.*
import java.net.InetSocketAddress
import java.net.Proxy
import org.woheller69.freeDroidWarn.FreeDroidWarn
class MainApplication: Application() {
private fun PackageInfo.toInstalledItem(): InstalledItem {
val signatureString = singleSignature?.let(Utils::calculateHash).orEmpty()
return InstalledItem(packageName, versionName.orEmpty(), versionCodeCompat, signatureString)
}
override fun attachBaseContext(base: Context) {
super.attachBaseContext(Utils.configureLocale(base))
}
private var preferencesDisposable: Disposable? = null
override fun onCreate() {
super.onCreate()
FreeDroidWarn.showWarningOnUpgrade(this, BuildConfig.VERSION_CODE)
val databaseUpdated = Database.init(this)
Preferences.init(this)
ProductPreferences.init(this)
RepositoryUpdater.init()
listenApplications()
listenPreferences()
Picasso.setSingletonInstance(Picasso.Builder(this)
.downloader(OkHttp3Downloader(PicassoDownloader.Factory(Cache.getImagesDir(this)))).build())
if (databaseUpdated) {
forceSyncAll()
}
Cache.cleanup(this)
updateSyncJob(false)
}
@SuppressLint("QueryPermissionsNeeded")
private fun listenApplications() {
registerReceiver(object: BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val packageName = intent.data?.let { if (it.scheme == "package") it.schemeSpecificPart else null }
if (packageName != null) {
when (intent.action.orEmpty()) {
Intent.ACTION_PACKAGE_ADDED,
Intent.ACTION_PACKAGE_REMOVED -> {
val packageInfo = try {
packageManager.getPackageInfo(packageName, Android.PackageManager.signaturesFlag)
} catch (_: Exception) {
null
}
if (packageInfo != null) {
Database.InstalledAdapter.put(packageInfo.toInstalledItem())
} else {
Database.InstalledAdapter.delete(packageName)
}
}
}
}
}
}, IntentFilter().apply {
addAction(Intent.ACTION_PACKAGE_ADDED)
addAction(Intent.ACTION_PACKAGE_REMOVED)
addDataScheme("package")
})
val installedItems = packageManager.getInstalledPackages(Android.PackageManager.signaturesFlag)
.map { it.toInstalledItem() }
Database.InstalledAdapter.putAll(installedItems)
}
private fun listenPreferences() {
updateProxy()
val lastAutoSync = Preferences[Preferences.Key.AutoSync]
val lastUpdateUnstable = Preferences[Preferences.Key.UpdateUnstable]
preferencesDisposable?.dispose()
preferencesDisposable = Preferences.observable.subscribe {
if (it == Preferences.Key.ProxyType || it == Preferences.Key.ProxyHost || it == Preferences.Key.ProxyPort) {
updateProxy()
} else if (it == Preferences.Key.AutoSync) {
val autoSync = Preferences[Preferences.Key.AutoSync]
if (lastAutoSync != autoSync) {
updateSyncJob(true)
}
} else if (it == Preferences.Key.UpdateUnstable) {
val updateUnstable = Preferences[Preferences.Key.UpdateUnstable]
if (lastUpdateUnstable != updateUnstable) {
forceSyncAll()
}
}
}
}
private fun updateSyncJob(force: Boolean) {
val jobScheduler = getSystemService(JOB_SCHEDULER_SERVICE) as JobScheduler
val reschedule = force || !jobScheduler.allPendingJobs.any { it.id == Common.JOB_ID_SYNC }
if (reschedule) {
val autoSync = Preferences[Preferences.Key.AutoSync]
when (autoSync) {
Preferences.AutoSync.Never -> {
jobScheduler.cancel(Common.JOB_ID_SYNC)
}
Preferences.AutoSync.Wifi, Preferences.AutoSync.Always -> {
val period = 12 * 60 * 60 * 1000L // 12 hours
val wifiOnly = autoSync == Preferences.AutoSync.Wifi
jobScheduler.schedule(JobInfo
.Builder(Common.JOB_ID_SYNC, ComponentName(this, SyncService.Job::class.java))
.setRequiredNetworkType(if (wifiOnly) JobInfo.NETWORK_TYPE_UNMETERED else JobInfo.NETWORK_TYPE_ANY)
.apply {
if (Android.sdk(26)) {
setRequiresBatteryNotLow(true)
setRequiresStorageNotLow(true)
}
if (Android.sdk(24)) {
setPeriodic(period, JobInfo.getMinFlexMillis())
} else {
setPeriodic(period)
}
}
.build())
Unit
}
}::class.java
}
}
private fun updateProxy() {
val type = Preferences[Preferences.Key.ProxyType].proxyType
val host = Preferences[Preferences.Key.ProxyHost]
val port = Preferences[Preferences.Key.ProxyPort]
val socketAddress = when (type) {
Proxy.Type.DIRECT -> {
null
}
Proxy.Type.HTTP, Proxy.Type.SOCKS -> {
try {
InetSocketAddress.createUnresolved(host, port)
} catch (e: Exception) {
e.printStackTrace()
null
}
}
}
val proxy = socketAddress?.let { Proxy(type, socketAddress) }
Downloader.proxy = proxy
}
private fun forceSyncAll() {
Database.RepositoryAdapter.getAll(null).forEach {
if (it.lastModified.isNotEmpty() || it.entityTag.isNotEmpty()) {
Database.RepositoryAdapter.put(it.copy(lastModified = "", entityTag = ""))
}
}
Connection(SyncService::class.java, onBind = { connection, binder ->
binder.sync(SyncService.SyncRequest.FORCE)
connection.unbind(this)
}).bind(this)
}
class BootReceiver: BroadcastReceiver() {
@SuppressLint("UnsafeProtectedBroadcastReceiver")
override fun onReceive(context: Context, intent: Intent) = Unit
}
}