mirror of
https://github.com/Aviortheking/Neo-Store.git
synced 2025-06-07 16:29:55 +00:00
289 lines
11 KiB
Kotlin
289 lines
11 KiB
Kotlin
package com.machiav3lli.fdroid
|
|
|
|
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.ContextWrapper
|
|
import android.content.Intent
|
|
import android.content.IntentFilter
|
|
import android.os.BatteryManager
|
|
import androidx.appcompat.app.AppCompatActivity
|
|
import coil.ImageLoader
|
|
import coil.ImageLoaderFactory
|
|
import com.google.android.material.color.DynamicColors
|
|
import com.google.android.material.color.DynamicColorsOptions
|
|
import com.machiav3lli.fdroid.content.Cache
|
|
import com.machiav3lli.fdroid.content.Preferences
|
|
import com.machiav3lli.fdroid.database.DatabaseX
|
|
import com.machiav3lli.fdroid.index.RepositoryUpdater
|
|
import com.machiav3lli.fdroid.network.CoilDownloader
|
|
import com.machiav3lli.fdroid.network.Downloader
|
|
import com.machiav3lli.fdroid.service.Connection
|
|
import com.machiav3lli.fdroid.service.PackageChangedReceiver
|
|
import com.machiav3lli.fdroid.service.SyncService
|
|
import com.machiav3lli.fdroid.ui.activities.MainActivityX
|
|
import com.machiav3lli.fdroid.utility.Utils.setLanguage
|
|
import com.machiav3lli.fdroid.utility.Utils.toInstalledItem
|
|
import com.machiav3lli.fdroid.utility.extension.android.Android
|
|
import kotlinx.coroutines.CoroutineScope
|
|
import kotlinx.coroutines.Dispatchers
|
|
import kotlinx.coroutines.launch
|
|
import java.lang.ref.WeakReference
|
|
import java.net.InetSocketAddress
|
|
import java.net.Proxy
|
|
import kotlin.time.Duration.Companion.minutes
|
|
|
|
|
|
@Suppress("unused")
|
|
class MainApplication : Application(), ImageLoaderFactory {
|
|
|
|
lateinit var db: DatabaseX
|
|
lateinit var mActivity: AppCompatActivity
|
|
//lateinit var wm: WorksManager
|
|
|
|
companion object {
|
|
private var appRef: WeakReference<MainApplication> = WeakReference(null)
|
|
private val neo_store: MainApplication get() = appRef.get()!!
|
|
|
|
//val wm: WorksManager get() = neo_store.wm
|
|
//val db: DatabaseX get() = neo_store.db
|
|
}
|
|
|
|
override fun onCreate() {
|
|
super.onCreate()
|
|
DynamicColors.applyToActivitiesIfAvailable(
|
|
this,
|
|
DynamicColorsOptions.Builder()
|
|
.setPrecondition { _, _ -> Preferences[Preferences.Key.Theme] == Preferences.Theme.Dynamic }
|
|
.build()
|
|
)
|
|
appRef = WeakReference(this)
|
|
|
|
db = DatabaseX.getInstance(applicationContext)
|
|
Preferences.init(this)
|
|
RepositoryUpdater.init(this)
|
|
listenApplications()
|
|
listenPreferences()
|
|
|
|
/*if (databaseUpdated) {
|
|
forceSyncAll()
|
|
}*/
|
|
|
|
//wm = WorksManager(applicationContext)
|
|
//wm.prune()
|
|
Cache.cleanup(this)
|
|
updateSyncJob(false)
|
|
}
|
|
|
|
private fun listenApplications() {
|
|
registerReceiver(
|
|
PackageChangedReceiver(),
|
|
IntentFilter().apply {
|
|
addAction(Intent.ACTION_PACKAGE_ADDED)
|
|
addAction(Intent.ACTION_PACKAGE_REMOVED)
|
|
addAction(Intent.ACTION_PACKAGE_REPLACED)
|
|
addDataScheme("package")
|
|
}
|
|
)
|
|
val launcherActivitiesMap =
|
|
packageManager
|
|
.queryIntentActivities(
|
|
Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER),
|
|
0
|
|
)
|
|
.mapNotNull { resolveInfo -> resolveInfo.activityInfo }
|
|
.groupBy { it.packageName }
|
|
.mapNotNull { (packageName, activityInfos) ->
|
|
val aiNameLabels = activityInfos.mapNotNull {
|
|
val label = try {
|
|
it.loadLabel(packageManager).toString()
|
|
} catch (e: Exception) {
|
|
e.printStackTrace()
|
|
null
|
|
}
|
|
label?.let { label -> Pair(it.name, label) }
|
|
}
|
|
Pair(packageName, aiNameLabels)
|
|
}.toMap()
|
|
val installedItems = packageManager
|
|
.getInstalledPackages(Android.PackageManager.signaturesFlag)
|
|
.map { it.toInstalledItem(launcherActivitiesMap[it.packageName].orEmpty()) }
|
|
CoroutineScope(Dispatchers.Default).launch {
|
|
db.installedDao.emptyTable()
|
|
db.installedDao.put(*installedItems.toTypedArray())
|
|
}
|
|
}
|
|
|
|
private fun listenPreferences() {
|
|
updateProxy()
|
|
var lastAutoSync = Preferences[Preferences.Key.AutoSync]
|
|
var lastUpdateUnstable = Preferences[Preferences.Key.UpdateUnstable]
|
|
var lastLanguage = Preferences[Preferences.Key.Language]
|
|
var lastTheme = Preferences[Preferences.Key.Theme]
|
|
CoroutineScope(Dispatchers.Default).launch {
|
|
Preferences.subject.collect {
|
|
when (it) {
|
|
Preferences.Key.ProxyType, Preferences.Key.ProxyHost, Preferences.Key.ProxyPort -> {
|
|
updateProxy()
|
|
}
|
|
Preferences.Key.AutoSync, Preferences.Key.AutoSyncInterval -> {
|
|
val autoSync = Preferences[Preferences.Key.AutoSync]
|
|
if (lastAutoSync != autoSync) {
|
|
lastAutoSync = autoSync
|
|
updateSyncJob(true)
|
|
}
|
|
}
|
|
Preferences.Key.UpdateUnstable -> {
|
|
val updateUnstable = Preferences[Preferences.Key.UpdateUnstable]
|
|
if (lastUpdateUnstable != updateUnstable) {
|
|
lastUpdateUnstable = updateUnstable
|
|
forceSyncAll()
|
|
}
|
|
}
|
|
Preferences.Key.Theme -> {
|
|
val theme = Preferences[Preferences.Key.Theme]
|
|
if (theme != lastTheme) {
|
|
lastTheme = theme
|
|
CoroutineScope(Dispatchers.Main).launch { mActivity.recreate() }
|
|
}
|
|
}
|
|
Preferences.Key.Language -> {
|
|
val language = Preferences[Preferences.Key.Language]
|
|
if (language != lastLanguage) {
|
|
lastLanguage = language
|
|
val refresh = Intent.makeRestartActivityTask(
|
|
ComponentName(
|
|
baseContext,
|
|
MainActivityX::class.java
|
|
)
|
|
)
|
|
applicationContext.startActivity(refresh)
|
|
}
|
|
}
|
|
else -> return@collect
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun updateSyncJob(force: Boolean) {
|
|
val jobScheduler = getSystemService(JOB_SCHEDULER_SERVICE) as JobScheduler
|
|
val reschedule = force || !jobScheduler.allPendingJobs.any { it.id == JOB_ID_SYNC }
|
|
if (reschedule) {
|
|
val autoSync = Preferences[Preferences.Key.AutoSync]
|
|
when (autoSync) {
|
|
is Preferences.AutoSync.Never -> {
|
|
jobScheduler.cancel(JOB_ID_SYNC)
|
|
}
|
|
is Preferences.AutoSync.Wifi -> {
|
|
autoSync(
|
|
jobScheduler = jobScheduler,
|
|
connectionType = JobInfo.NETWORK_TYPE_UNMETERED
|
|
)
|
|
}
|
|
is Preferences.AutoSync.WifiBattery -> {
|
|
if (isCharging(this)) {
|
|
autoSync(
|
|
jobScheduler = jobScheduler,
|
|
connectionType = JobInfo.NETWORK_TYPE_UNMETERED
|
|
)
|
|
}
|
|
Unit
|
|
}
|
|
is Preferences.AutoSync.Always -> {
|
|
autoSync(
|
|
jobScheduler = jobScheduler,
|
|
connectionType = JobInfo.NETWORK_TYPE_ANY
|
|
)
|
|
}
|
|
}::class.java
|
|
}
|
|
}
|
|
|
|
private fun autoSync(jobScheduler: JobScheduler, connectionType: Int) {
|
|
val period = Preferences[Preferences.Key.AutoSyncInterval].minutes.inWholeMilliseconds
|
|
jobScheduler.schedule(
|
|
JobInfo
|
|
.Builder(
|
|
JOB_ID_SYNC,
|
|
ComponentName(this, SyncService.Job::class.java)
|
|
)
|
|
.setRequiredNetworkType(connectionType)
|
|
.apply {
|
|
if (Android.sdk(26)) {
|
|
setRequiresBatteryNotLow(true)
|
|
setRequiresStorageNotLow(true)
|
|
}
|
|
if (Android.sdk(24)) setPeriodic(period, JobInfo.getMinFlexMillis())
|
|
else setPeriodic(period)
|
|
}
|
|
.build()
|
|
)
|
|
}
|
|
|
|
private fun isCharging(context: Context): Boolean {
|
|
val intent = context.registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
|
|
val plugged = intent!!.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1)
|
|
return plugged == BatteryManager.BATTERY_PLUGGED_AC
|
|
|| plugged == BatteryManager.BATTERY_PLUGGED_USB
|
|
|| plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS
|
|
}
|
|
|
|
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, it) }
|
|
Downloader.proxy = proxy
|
|
}
|
|
|
|
private fun forceSyncAll() {
|
|
db.repositoryDao.all.forEach {
|
|
if (it.lastModified.isNotEmpty() || it.entityTag.isNotEmpty()) {
|
|
db.repositoryDao.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
|
|
}
|
|
|
|
override fun newImageLoader(): ImageLoader {
|
|
return ImageLoader.Builder(this)
|
|
.callFactory(CoilDownloader.Factory(Cache.getImagesDir(this)))
|
|
.crossfade(true)
|
|
.build()
|
|
}
|
|
}
|
|
|
|
class ContextWrapperX(base: Context) : ContextWrapper(base) {
|
|
companion object {
|
|
fun wrap(context: Context): ContextWrapper {
|
|
val config = context.setLanguage()
|
|
return ContextWrapperX(context.createConfigurationContext(config))
|
|
}
|
|
}
|
|
} |