Rework updates check & install setup
Merge updates checking logic into UpdateWorker and move trigger methods to UpdateHelper class, similar to how DownloadHelper works. Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -23,8 +23,6 @@ object Constants {
|
|||||||
|
|
||||||
const val PARCEL_DOWNLOAD = "PARCEL_DOWNLOAD"
|
const val PARCEL_DOWNLOAD = "PARCEL_DOWNLOAD"
|
||||||
|
|
||||||
const val APP_ID = "com.aurora.store"
|
|
||||||
|
|
||||||
const val URL_TOS = "https://play.google.com/about/play-terms/"
|
const val URL_TOS = "https://play.google.com/about/play-terms/"
|
||||||
const val URL_LICENSE = "https://gitlab.com/AuroraOSS/AuroraStore/blob/master/LICENSE"
|
const val URL_LICENSE = "https://gitlab.com/AuroraOSS/AuroraStore/blob/master/LICENSE"
|
||||||
const val URL_DISCLAIMER = "https://gitlab.com/AuroraOSS/AuroraStore/blob/master/DISCLAIMER.md"
|
const val URL_DISCLAIMER = "https://gitlab.com/AuroraOSS/AuroraStore/blob/master/DISCLAIMER.md"
|
||||||
|
|||||||
@@ -34,8 +34,6 @@ import androidx.lifecycle.lifecycleScope
|
|||||||
import androidx.navigation.FloatingWindow
|
import androidx.navigation.FloatingWindow
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import androidx.navigation.ui.setupWithNavController
|
import androidx.navigation.ui.setupWithNavController
|
||||||
import com.aurora.store.data.event.BusEvent
|
|
||||||
import com.aurora.store.data.event.InstallerEvent
|
|
||||||
import com.aurora.store.data.model.NetworkStatus
|
import com.aurora.store.data.model.NetworkStatus
|
||||||
import com.aurora.store.data.receiver.MigrationReceiver
|
import com.aurora.store.data.receiver.MigrationReceiver
|
||||||
import com.aurora.store.databinding.ActivityMainBinding
|
import com.aurora.store.databinding.ActivityMainBinding
|
||||||
@@ -149,22 +147,6 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Updates
|
// Updates
|
||||||
lifecycleScope.launch {
|
|
||||||
AuroraApp.events.installerEvent.collect {
|
|
||||||
when (it) {
|
|
||||||
is InstallerEvent.Installed -> updateHelper.deleteUpdate(it.packageName)
|
|
||||||
is InstallerEvent.Uninstalled -> updateHelper.deleteUpdate(it.packageName)
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lifecycleScope.launch {
|
|
||||||
AuroraApp.events.busEvent.collect {
|
|
||||||
if (it is BusEvent.Blacklisted) updateHelper.deleteUpdate(it.packageName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
updateHelper.updates.collectLatest { list ->
|
updateHelper.updates.collectLatest { list ->
|
||||||
B.navView.getOrCreateBadge(R.id.updatesFragment).apply {
|
B.navView.getOrCreateBadge(R.id.updatesFragment).apply {
|
||||||
|
|||||||
@@ -1,156 +1,168 @@
|
|||||||
package com.aurora.store.data.helper
|
package com.aurora.store.data.helper
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageInfo
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.core.content.pm.PackageInfoCompat
|
import androidx.work.Constraints
|
||||||
import com.aurora.Constants
|
import androidx.work.Data
|
||||||
import com.aurora.gplayapi.data.models.App
|
import androidx.work.ExistingPeriodicWorkPolicy
|
||||||
import com.aurora.gplayapi.helpers.AppDetailsHelper
|
import androidx.work.ExistingWorkPolicy
|
||||||
import com.aurora.gplayapi.network.IHttpClient
|
import androidx.work.NetworkType
|
||||||
|
import androidx.work.OutOfQuotaPolicy
|
||||||
|
import androidx.work.OneTimeWorkRequestBuilder
|
||||||
|
import androidx.work.PeriodicWorkRequest
|
||||||
|
import androidx.work.PeriodicWorkRequestBuilder
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import com.aurora.extensions.isMAndAbove
|
||||||
import com.aurora.store.AuroraApp
|
import com.aurora.store.AuroraApp
|
||||||
import com.aurora.store.BuildConfig
|
import com.aurora.store.data.event.BusEvent
|
||||||
import com.aurora.store.data.model.SelfUpdate
|
import com.aurora.store.data.event.InstallerEvent
|
||||||
import com.aurora.store.data.providers.AuthProvider
|
import com.aurora.store.data.model.UpdateMode
|
||||||
import com.aurora.store.data.providers.BlacklistProvider
|
|
||||||
import com.aurora.store.data.room.update.Update
|
|
||||||
import com.aurora.store.data.room.update.UpdateDao
|
import com.aurora.store.data.room.update.UpdateDao
|
||||||
import com.aurora.store.util.CertUtil
|
import com.aurora.store.data.work.UpdateWorker
|
||||||
import com.aurora.store.util.PackageUtil
|
|
||||||
import com.aurora.store.util.Preferences
|
import com.aurora.store.util.Preferences
|
||||||
import com.google.gson.Gson
|
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_CHECK_INTERVAL
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.flow.SharingStarted
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.firstOrNull
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import javax.inject.Inject
|
|
||||||
import kotlinx.coroutines.flow.firstOrNull
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import java.util.concurrent.TimeUnit.HOURS
|
||||||
|
import java.util.concurrent.TimeUnit.MINUTES
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to work with the [UpdateWorker].
|
||||||
|
*/
|
||||||
class UpdateHelper @Inject constructor(
|
class UpdateHelper @Inject constructor(
|
||||||
private val gson: Gson,
|
|
||||||
private val authProvider: AuthProvider,
|
|
||||||
private val updateDao: UpdateDao,
|
private val updateDao: UpdateDao,
|
||||||
private val blacklistProvider: BlacklistProvider,
|
|
||||||
private val httpClient: IHttpClient,
|
|
||||||
@ApplicationContext private val context: Context
|
@ApplicationContext private val context: Context
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val UPDATE_MODE = "UPDATE_MODE"
|
||||||
|
|
||||||
|
private const val UPDATE_WORKER = "UPDATE_WORKER"
|
||||||
|
private const val EXPEDITED_UPDATE_WORKER = "EXPEDITED_UPDATE_WORKER"
|
||||||
|
}
|
||||||
|
|
||||||
private val TAG = UpdateHelper::class.java.simpleName
|
private val TAG = UpdateHelper::class.java.simpleName
|
||||||
|
|
||||||
private val RELEASE = "release"
|
private val isExtendedUpdateEnabled
|
||||||
private val NIGHTLY = "nightly"
|
get() = Preferences.getBoolean(context, Preferences.PREFERENCE_UPDATES_EXTENDED)
|
||||||
|
|
||||||
private val isExtendedUpdateEnabled get() = Preferences.getBoolean(
|
|
||||||
context, Preferences.PREFERENCE_UPDATES_EXTENDED
|
|
||||||
)
|
|
||||||
val updates = updateDao.updates()
|
val updates = updateDao.updates()
|
||||||
.map { list -> if (!isExtendedUpdateEnabled) list.filter { it.hasValidCert } else list }
|
.map { list -> if (!isExtendedUpdateEnabled) list.filter { it.hasValidCert } else list }
|
||||||
.stateIn(AuroraApp.scope, SharingStarted.WhileSubscribed(), null)
|
.stateIn(AuroraApp.scope, SharingStarted.WhileSubscribed(), null)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
AuroraApp.scope.launch {
|
AuroraApp.scope.launch {
|
||||||
updateDao.updates().firstOrNull()?.forEach { update ->
|
deleteInvalidUpdates()
|
||||||
if (!update.isInstalled(context) || update.isUpToDate(context)) {
|
}.invokeOnCompletion {
|
||||||
deleteUpdate(update.packageName)
|
observeUpdates()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun observeUpdates() {
|
||||||
|
AuroraApp.events.installerEvent.onEach {
|
||||||
|
when (it) {
|
||||||
|
is InstallerEvent.Installed -> deleteUpdate(it.packageName)
|
||||||
|
is InstallerEvent.Uninstalled -> deleteUpdate(it.packageName)
|
||||||
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}.launchIn(AuroraApp.scope)
|
||||||
|
|
||||||
|
AuroraApp.events.busEvent.onEach {
|
||||||
|
if (it is BusEvent.Blacklisted) deleteUpdate(it.packageName)
|
||||||
|
}.launchIn(AuroraApp.scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun checkUpdates(): List<Update> {
|
/**
|
||||||
Log.i(TAG, "Checking for updates")
|
* Checks for updates using an expedited worker
|
||||||
val packageInfoMap = PackageUtil.getPackageInfoMap(context)
|
*/
|
||||||
val appUpdatesList = getFilteredInstalledApps(packageInfoMap)
|
fun checkUpdatesNow() {
|
||||||
.filter {
|
val inputData = Data.Builder()
|
||||||
val packageInfo = packageInfoMap[it.packageName]
|
.putInt(UPDATE_MODE, UpdateMode.CHECK_ONLY.ordinal)
|
||||||
if (packageInfo != null) {
|
.build()
|
||||||
it.versionCode.toLong() > PackageInfoCompat.getLongVersionCode(packageInfo)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}.toMutableList()
|
|
||||||
|
|
||||||
if (canSelfUpdate(context)) {
|
val work = OneTimeWorkRequestBuilder<UpdateWorker>()
|
||||||
getSelfUpdate(context, gson)?.let { appUpdatesList.add(it) }
|
.addTag(EXPEDITED_UPDATE_WORKER)
|
||||||
}
|
.setExpedited(OutOfQuotaPolicy.DROP_WORK_REQUEST)
|
||||||
|
.setInputData(inputData)
|
||||||
|
.build()
|
||||||
|
|
||||||
return appUpdatesList.map { Update.fromApp(context, it) }.also {
|
WorkManager.getInstance(context)
|
||||||
// Cache the updates into the database
|
.enqueueUniqueWork(EXPEDITED_UPDATE_WORKER, ExistingWorkPolicy.KEEP, work)
|
||||||
updateDao.insertUpdates(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun deleteUpdate(packageName: String) {
|
/**
|
||||||
|
* Delete update for a package from the database
|
||||||
|
* @param packageName Name of the package
|
||||||
|
*/
|
||||||
|
private suspend fun deleteUpdate(packageName: String) {
|
||||||
updateDao.delete(packageName)
|
updateDao.delete(packageName)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getFilteredInstalledApps(
|
/**
|
||||||
packageInfoMap: MutableMap<String, PackageInfo>? = null
|
* Cancels the automated updates check
|
||||||
): List<App> {
|
* @see [UpdateWorker]
|
||||||
return withContext(Dispatchers.IO) {
|
*/
|
||||||
val appDetailsHelper = AppDetailsHelper(authProvider.authData!!)
|
fun cancelAutomatedCheck() {
|
||||||
.using(httpClient)
|
Log.i(TAG, "Cancelling periodic app updates!")
|
||||||
|
WorkManager.getInstance(context).cancelUniqueWork(UPDATE_WORKER)
|
||||||
(packageInfoMap ?: PackageUtil.getPackageInfoMap(context)).keys.let { packages ->
|
|
||||||
val filtersPackages = packages.filter { !blacklistProvider.isBlacklisted(it) }
|
|
||||||
|
|
||||||
appDetailsHelper.getAppByPackageName(filtersPackages)
|
|
||||||
.filter { it.displayName.isNotEmpty() }
|
|
||||||
.map { it.isInstalled = true; it }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun canSelfUpdate(context: Context): Boolean {
|
/**
|
||||||
return !CertUtil.isFDroidApp(context, BuildConfig.APPLICATION_ID) &&
|
* Schedules the automated updates check
|
||||||
!CertUtil.isAppGalleryApp(context, BuildConfig.APPLICATION_ID)
|
* @see [UpdateWorker]
|
||||||
|
*/
|
||||||
|
fun scheduleAutomatedCheck() {
|
||||||
|
Log.i(TAG,"Scheduling periodic app updates!")
|
||||||
|
WorkManager.getInstance(context)
|
||||||
|
.enqueueUniquePeriodicWork(
|
||||||
|
UPDATE_WORKER,
|
||||||
|
ExistingPeriodicWorkPolicy.KEEP,
|
||||||
|
getAutoUpdateWork()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getSelfUpdate(context: Context, gson: Gson): App? {
|
/**
|
||||||
return withContext(Dispatchers.IO) {
|
* Updates the automated updates check to reconsider the new user preferences
|
||||||
@Suppress("KotlinConstantConditions") // False-positive for build type always not being release
|
* @see [UpdateWorker]
|
||||||
val updateUrl = when (BuildConfig.BUILD_TYPE) {
|
*/
|
||||||
RELEASE -> Constants.UPDATE_URL_STABLE
|
fun updateAutomatedCheck() {
|
||||||
NIGHTLY -> Constants.UPDATE_URL_NIGHTLY
|
Log.i(TAG,"Updating periodic app updates!")
|
||||||
else -> {
|
WorkManager.getInstance(context).updateWork(getAutoUpdateWork())
|
||||||
Log.i(TAG, "Self-updates are not available for this build!")
|
}
|
||||||
return@withContext null
|
|
||||||
}
|
private fun getAutoUpdateWork(): PeriodicWorkRequest {
|
||||||
|
val updateCheckInterval = Preferences.getInteger(
|
||||||
|
context,
|
||||||
|
PREFERENCE_UPDATES_CHECK_INTERVAL,
|
||||||
|
3
|
||||||
|
).toLong()
|
||||||
|
|
||||||
|
val constraints = Constraints.Builder()
|
||||||
|
.setRequiredNetworkType(NetworkType.UNMETERED)
|
||||||
|
.setRequiresBatteryNotLow(true)
|
||||||
|
|
||||||
|
if (isMAndAbove()) constraints.setRequiresDeviceIdle(true)
|
||||||
|
|
||||||
|
return PeriodicWorkRequestBuilder<UpdateWorker>(
|
||||||
|
repeatInterval = updateCheckInterval,
|
||||||
|
repeatIntervalTimeUnit = HOURS,
|
||||||
|
flexTimeInterval = 30,
|
||||||
|
flexTimeIntervalUnit = MINUTES
|
||||||
|
).setConstraints(constraints.build()).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun deleteInvalidUpdates() {
|
||||||
|
updateDao.updates().firstOrNull()?.forEach { update ->
|
||||||
|
if (!update.isInstalled(context) || update.isUpToDate(context)) {
|
||||||
|
deleteUpdate(update.packageName)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
val response = httpClient.get(updateUrl, mapOf())
|
|
||||||
val selfUpdate =
|
|
||||||
gson.fromJson(String(response.responseBytes), SelfUpdate::class.java)
|
|
||||||
|
|
||||||
val isUpdate = when (BuildConfig.BUILD_TYPE) {
|
|
||||||
RELEASE -> selfUpdate.versionCode > BuildConfig.VERSION_CODE
|
|
||||||
NIGHTLY -> selfUpdate.timestamp > BuildConfig.TIMESTAMP
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isUpdate) {
|
|
||||||
if (CertUtil.isFDroidApp(context, BuildConfig.APPLICATION_ID)) {
|
|
||||||
if (selfUpdate.fdroidBuild.isNotEmpty()) {
|
|
||||||
return@withContext SelfUpdate.toApp(selfUpdate, context)
|
|
||||||
}
|
|
||||||
} else if (selfUpdate.auroraBuild.isNotEmpty()) {
|
|
||||||
return@withContext SelfUpdate.toApp(selfUpdate, context)
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "Update file is missing!")
|
|
||||||
return@withContext null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
Log.e(TAG, "Failed to check self-updates", exception)
|
|
||||||
return@withContext null
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.i(TAG, "No self-updates found!")
|
|
||||||
return@withContext null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.aurora.store.data.model
|
||||||
|
|
||||||
|
enum class BuildType {
|
||||||
|
RELEASE,
|
||||||
|
NIGHTLY,
|
||||||
|
DEBUG
|
||||||
|
}
|
||||||
@@ -53,7 +53,7 @@ data class SelfUpdate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return App(
|
return App(
|
||||||
packageName = Constants.APP_ID,
|
packageName = context.packageName,
|
||||||
versionCode = selfUpdate.versionCode,
|
versionCode = selfUpdate.versionCode,
|
||||||
versionName = selfUpdate.versionName,
|
versionName = selfUpdate.versionName,
|
||||||
changes = selfUpdate.changelog,
|
changes = selfUpdate.changelog,
|
||||||
@@ -64,7 +64,7 @@ data class SelfUpdate(
|
|||||||
iconArtwork = Artwork(url = "$BASE_URL/$icon"),
|
iconArtwork = Artwork(url = "$BASE_URL/$icon"),
|
||||||
fileList = mutableListOf(
|
fileList = mutableListOf(
|
||||||
File(
|
File(
|
||||||
name = "${Constants.APP_ID}.apk",
|
name = "${context.packageName}.apk",
|
||||||
url = downloadURL,
|
url = downloadURL,
|
||||||
size = selfUpdate.size
|
size = selfUpdate.size
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package com.aurora.store.data.model
|
||||||
|
|
||||||
|
enum class UpdateMode {
|
||||||
|
DISABLED,
|
||||||
|
CHECK_ONLY,
|
||||||
|
CHECK_AND_INSTALL
|
||||||
|
}
|
||||||
@@ -59,8 +59,8 @@ data class Update(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isSelfUpdate(): Boolean {
|
fun isSelfUpdate(context: Context): Boolean {
|
||||||
return packageName == Constants.APP_ID
|
return packageName == context.packageName
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isInstalled(context: Context): Boolean {
|
fun isInstalled(context: Context): Boolean {
|
||||||
|
|||||||
@@ -4,179 +4,220 @@ import android.app.NotificationManager
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
|
import androidx.core.content.pm.PackageInfoCompat
|
||||||
import androidx.hilt.work.HiltWorker
|
import androidx.hilt.work.HiltWorker
|
||||||
import androidx.work.Constraints
|
|
||||||
import androidx.work.CoroutineWorker
|
import androidx.work.CoroutineWorker
|
||||||
import androidx.work.ExistingPeriodicWorkPolicy.KEEP
|
import androidx.work.ForegroundInfo
|
||||||
import androidx.work.NetworkType
|
|
||||||
import androidx.work.PeriodicWorkRequest
|
|
||||||
import androidx.work.PeriodicWorkRequestBuilder
|
|
||||||
import androidx.work.WorkManager
|
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
|
import com.aurora.Constants
|
||||||
import com.aurora.extensions.isIgnoringBatteryOptimizations
|
import com.aurora.extensions.isIgnoringBatteryOptimizations
|
||||||
import com.aurora.extensions.isMAndAbove
|
import com.aurora.gplayapi.data.models.App
|
||||||
|
import com.aurora.gplayapi.helpers.AppDetailsHelper
|
||||||
|
import com.aurora.gplayapi.network.IHttpClient
|
||||||
|
import com.aurora.store.BuildConfig
|
||||||
import com.aurora.store.data.installer.AppInstaller
|
import com.aurora.store.data.installer.AppInstaller
|
||||||
import com.aurora.store.data.providers.AuthProvider
|
import com.aurora.store.data.providers.AuthProvider
|
||||||
import com.aurora.store.data.helper.UpdateHelper
|
|
||||||
import com.aurora.store.data.helper.DownloadHelper
|
import com.aurora.store.data.helper.DownloadHelper
|
||||||
|
import com.aurora.store.data.helper.UpdateHelper
|
||||||
|
import com.aurora.store.data.model.BuildType
|
||||||
|
import com.aurora.store.data.model.SelfUpdate
|
||||||
|
import com.aurora.store.data.model.UpdateMode
|
||||||
|
import com.aurora.store.data.providers.AccountProvider
|
||||||
|
import com.aurora.store.data.providers.BlacklistProvider
|
||||||
|
import com.aurora.store.data.room.update.Update
|
||||||
|
import com.aurora.store.data.room.update.UpdateDao
|
||||||
|
import com.aurora.store.util.CertUtil
|
||||||
import com.aurora.store.util.NotificationUtil
|
import com.aurora.store.util.NotificationUtil
|
||||||
|
import com.aurora.store.util.PackageUtil
|
||||||
import com.aurora.store.util.Preferences
|
import com.aurora.store.util.Preferences
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_AUTO
|
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_AUTO
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_CHECK_INTERVAL
|
import com.google.gson.Gson
|
||||||
import com.aurora.store.util.save
|
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.util.concurrent.TimeUnit.HOURS
|
|
||||||
import java.util.concurrent.TimeUnit.MINUTES
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A periodic worker to check for updates for installed apps based on
|
* A worker to check for updates for installed apps based on
|
||||||
* filters and the auto-updates mode selected by the user. The repeat interval
|
* filters and the auto-updates mode selected by the user. The repeat interval
|
||||||
* is configurable by the user, defaulting to 3 hours with a flex time of 30 minutes.
|
* is configurable by the user, defaulting to 3 hours with a flex time of 30 minutes.
|
||||||
|
*
|
||||||
|
* Avoid using this worker directly and prefer using [UpdateHelper] instead.
|
||||||
*/
|
*/
|
||||||
@HiltWorker
|
@HiltWorker
|
||||||
class UpdateWorker @AssistedInject constructor(
|
class UpdateWorker @AssistedInject constructor(
|
||||||
private val updateHelper: UpdateHelper,
|
private val gson: Gson,
|
||||||
|
private val blacklistProvider: BlacklistProvider,
|
||||||
|
private val httpClient: IHttpClient,
|
||||||
|
private val updateDao: UpdateDao,
|
||||||
private val downloadHelper: DownloadHelper,
|
private val downloadHelper: DownloadHelper,
|
||||||
private val authProvider: AuthProvider,
|
private val authProvider: AuthProvider,
|
||||||
@Assisted private val appContext: Context,
|
@Assisted private val appContext: Context,
|
||||||
@Assisted workerParams: WorkerParameters
|
@Assisted workerParams: WorkerParameters
|
||||||
) : CoroutineWorker(appContext, workerParams) {
|
) : CoroutineWorker(appContext, workerParams) {
|
||||||
|
|
||||||
companion object {
|
private val TAG = UpdateWorker::class.java.simpleName
|
||||||
private const val TAG = "UpdateWorker"
|
|
||||||
private const val UPDATE_WORKER = "UPDATE_WORKER"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cancels the automated updates check
|
|
||||||
* @param context Current [Context]
|
|
||||||
* @see [UpdateWorker]
|
|
||||||
*/
|
|
||||||
fun cancelAutomatedCheck(context: Context) {
|
|
||||||
Log.i(TAG, "Cancelling periodic app updates!")
|
|
||||||
WorkManager.getInstance(context).cancelUniqueWork(UPDATE_WORKER)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schedules the automated updates check
|
|
||||||
* @param context Current [Context]
|
|
||||||
* @see [UpdateWorker]
|
|
||||||
*/
|
|
||||||
fun scheduleAutomatedCheck(context: Context) {
|
|
||||||
Log.i(TAG,"Scheduling periodic app updates!")
|
|
||||||
WorkManager.getInstance(context)
|
|
||||||
.enqueueUniquePeriodicWork(UPDATE_WORKER, KEEP, buildUpdateWork(context))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the automated updates check to reconsider the new user preferences
|
|
||||||
* @param context Current [Context]
|
|
||||||
* @see [UpdateWorker]
|
|
||||||
*/
|
|
||||||
fun updateAutomatedCheck(context: Context) {
|
|
||||||
Log.i(TAG,"Updating periodic app updates!")
|
|
||||||
WorkManager.getInstance(context).updateWork(buildUpdateWork(context))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildUpdateWork(context: Context): PeriodicWorkRequest {
|
|
||||||
val updateCheckInterval = Preferences.getInteger(
|
|
||||||
context,
|
|
||||||
PREFERENCE_UPDATES_CHECK_INTERVAL,
|
|
||||||
3
|
|
||||||
).toLong()
|
|
||||||
|
|
||||||
val constraints = Constraints.Builder()
|
|
||||||
.setRequiredNetworkType(NetworkType.UNMETERED)
|
|
||||||
.setRequiresBatteryNotLow(true)
|
|
||||||
|
|
||||||
if (isMAndAbove()) constraints.setRequiresDeviceIdle(true)
|
|
||||||
|
|
||||||
return PeriodicWorkRequestBuilder<UpdateWorker>(
|
|
||||||
repeatInterval = updateCheckInterval,
|
|
||||||
repeatIntervalTimeUnit = HOURS,
|
|
||||||
flexTimeInterval = 30,
|
|
||||||
flexTimeIntervalUnit = MINUTES
|
|
||||||
).setConstraints(constraints.build()).build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val notificationID = 100
|
private val notificationID = 100
|
||||||
|
|
||||||
|
@Suppress("KotlinConstantConditions")
|
||||||
|
private val buildType = when (BuildConfig.BUILD_TYPE) {
|
||||||
|
"release" -> BuildType.RELEASE
|
||||||
|
"nightly" -> BuildType.NIGHTLY
|
||||||
|
else -> BuildType.DEBUG
|
||||||
|
}
|
||||||
|
|
||||||
|
private val canSelfUpdate = !CertUtil.isFDroidApp(appContext, BuildConfig.APPLICATION_ID) &&
|
||||||
|
!CertUtil.isAppGalleryApp(appContext, BuildConfig.APPLICATION_ID) &&
|
||||||
|
buildType != BuildType.DEBUG
|
||||||
|
|
||||||
override suspend fun doWork(): Result {
|
override suspend fun doWork(): Result {
|
||||||
Log.i(TAG, "Checking for app updates")
|
Log.i(TAG, "Checking for app updates")
|
||||||
|
val updateMode = UpdateMode.entries[inputData.getInt(
|
||||||
|
UpdateHelper.UPDATE_MODE,
|
||||||
|
Preferences.getInteger(appContext, PREFERENCE_UPDATES_AUTO, 3)
|
||||||
|
)]
|
||||||
|
|
||||||
val autoUpdatesMode = Preferences.getInteger(appContext, PREFERENCE_UPDATES_AUTO, 3)
|
if (updateMode == UpdateMode.DISABLED || !AccountProvider.isLoggedIn(appContext)) {
|
||||||
val notificationManager = appContext.getSystemService<NotificationManager>()
|
Log.i(TAG, "Updates are disabled, bailing out!")
|
||||||
|
|
||||||
// Exit if auto-updates is turned off in settings
|
|
||||||
if (autoUpdatesMode == 0) {
|
|
||||||
Log.i(TAG, "Auto-updates is disabled, bailing out!")
|
|
||||||
return Result.failure()
|
return Result.failure()
|
||||||
}
|
}
|
||||||
|
|
||||||
withContext(Dispatchers.IO) {
|
if (!authProvider.isSavedAuthDataValid()) {
|
||||||
if (!authProvider.isSavedAuthDataValid()) {
|
Log.i(TAG, "AuthData is not valid, retrying later!")
|
||||||
Log.i(TAG, "AuthData is not valid, retrying later!")
|
return Result.retry()
|
||||||
return@withContext Result.retry()
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
val updates = checkUpdates()
|
||||||
|
|
||||||
|
if (updates.isEmpty()) {
|
||||||
|
Log.i(TAG, "No updates found!")
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify and exit if we are only checking for updates or if battery optimizations are enabled
|
||||||
|
if (updateMode == UpdateMode.CHECK_ONLY || !appContext.isIgnoringBatteryOptimizations()) {
|
||||||
|
Log.i(TAG, "Found updates, notifying!")
|
||||||
|
notifyUpdates(updates)
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean the update list to prepare for installing
|
||||||
|
val filteredUpdates = updates
|
||||||
|
.filter { it.hasValidCert }
|
||||||
|
.filterNot { it.isSelfUpdate(appContext) }
|
||||||
|
.partition {
|
||||||
|
AppInstaller.canInstallSilently(appContext, it.packageName, it.targetSdk)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify about apps that cannot be auto-updated
|
||||||
|
notifyUpdates(filteredUpdates.second)
|
||||||
|
|
||||||
|
// Trigger download for apps if they can be auto-updated
|
||||||
|
filteredUpdates.first.forEach { downloadHelper.enqueueUpdate(it) }
|
||||||
|
|
||||||
|
return Result.success()
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
Log.e(TAG, "Failed to fetch updates", exception)
|
||||||
|
return Result.failure()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getForegroundInfo(): ForegroundInfo {
|
||||||
|
return ForegroundInfo(
|
||||||
|
notificationID,
|
||||||
|
NotificationUtil.getUpdateNotification(appContext)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks and returns updates for all possible apps
|
||||||
|
*/
|
||||||
|
private suspend fun checkUpdates(): List<Update> {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
val packageInfoMap = PackageUtil.getPackageInfoMap(appContext)
|
||||||
|
val appDetailsHelper = AppDetailsHelper(authProvider.authData!!)
|
||||||
|
.using(httpClient)
|
||||||
|
|
||||||
|
val updates = packageInfoMap.keys.let { packages ->
|
||||||
|
val filteredPackages = packages.filter { !blacklistProvider.isBlacklisted(it) }
|
||||||
|
appDetailsHelper.getAppByPackageName(filteredPackages)
|
||||||
|
.filter { it.displayName.isNotEmpty() }
|
||||||
|
.map { it.isInstalled = true; it }
|
||||||
|
}.filter {
|
||||||
|
val packageInfo = packageInfoMap[it.packageName]
|
||||||
|
if (packageInfo != null) {
|
||||||
|
it.versionCode.toLong() > PackageInfoCompat.getLongVersionCode(packageInfo)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}.toMutableList()
|
||||||
|
|
||||||
|
if (canSelfUpdate) getSelfUpdate()?.let { updates.add(it) }
|
||||||
|
|
||||||
|
return@withContext updates.map { Update.fromApp(appContext, it) }.also {
|
||||||
|
// Cache the updates into the database
|
||||||
|
updateDao.insertUpdates(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks and returns updates for Aurora Store if available
|
||||||
|
*/
|
||||||
|
private suspend fun getSelfUpdate(): App? {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
val updateUrl = when (buildType) {
|
||||||
|
BuildType.RELEASE -> Constants.UPDATE_URL_STABLE
|
||||||
|
BuildType.NIGHTLY -> Constants.UPDATE_URL_NIGHTLY
|
||||||
|
else -> {
|
||||||
|
Log.i(TAG, "Self-updates are not available for this build!")
|
||||||
|
return@withContext null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val updatesList = updateHelper.checkUpdates()
|
val response = httpClient.get(updateUrl, mapOf())
|
||||||
.filter { it.hasValidCert }
|
val selfUpdate = gson.fromJson(
|
||||||
.filterNot { it.isSelfUpdate() }
|
String(response.responseBytes),
|
||||||
|
SelfUpdate::class.java
|
||||||
|
)
|
||||||
|
|
||||||
if (updatesList.isNotEmpty()) {
|
val isUpdate = when (buildType) {
|
||||||
if (autoUpdatesMode == 1) {
|
BuildType.RELEASE -> selfUpdate.versionCode > BuildConfig.VERSION_CODE
|
||||||
Log.i(TAG, "Found updates, notifying!")
|
BuildType.NIGHTLY -> selfUpdate.timestamp > BuildConfig.TIMESTAMP
|
||||||
notificationManager!!.notify(
|
else -> false
|
||||||
notificationID,
|
}
|
||||||
NotificationUtil.getUpdateNotification(appContext, updatesList)
|
|
||||||
)
|
if (isUpdate) {
|
||||||
} else {
|
if (CertUtil.isFDroidApp(appContext, BuildConfig.APPLICATION_ID)) {
|
||||||
if (appContext.isIgnoringBatteryOptimizations()) {
|
if (selfUpdate.fdroidBuild.isNotEmpty()) {
|
||||||
// Trigger download for apps if they can be auto-updated (if any)
|
return@withContext SelfUpdate.toApp(selfUpdate, appContext)
|
||||||
updatesList.filter {
|
}
|
||||||
AppInstaller.canInstallSilently(appContext, it.packageName, it.targetSdk)
|
} else if (selfUpdate.auroraBuild.isNotEmpty()) {
|
||||||
}.let { list ->
|
return@withContext SelfUpdate.toApp(selfUpdate, appContext)
|
||||||
if (list.isEmpty()) return@let
|
} else {
|
||||||
|
Log.e(TAG, "Update file is missing!")
|
||||||
Log.i(TAG, "Found auto-update enabled apps, updating!")
|
return@withContext null
|
||||||
list.forEach { downloadHelper.enqueueUpdate(it) }
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Notify about remaining apps (if any)
|
|
||||||
updatesList.filterNot {
|
|
||||||
AppInstaller.canInstallSilently(appContext, it.packageName, it.targetSdk)
|
|
||||||
}.let { list ->
|
|
||||||
if (list.isEmpty()) return@let
|
|
||||||
|
|
||||||
Log.i(TAG, "Found apps that cannot be auto-updated, notifying!")
|
|
||||||
notificationManager!!.notify(
|
|
||||||
notificationID,
|
|
||||||
NotificationUtil.getUpdateNotification(appContext, list)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Fallback to notification if battery optimizations are enabled
|
|
||||||
Log.i(TAG, "Found updates, but battery optimizations are enabled!")
|
|
||||||
notificationManager!!.notify(
|
|
||||||
notificationID,
|
|
||||||
NotificationUtil.getUpdateNotification(appContext, updatesList)
|
|
||||||
)
|
|
||||||
appContext.save(PREFERENCE_UPDATES_AUTO, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.i(TAG, "No updates found!")
|
|
||||||
}
|
}
|
||||||
return@withContext Result.success()
|
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Log.e(TAG, "Failed to fetch updates", exception)
|
Log.e(TAG, "Failed to check self-updates", exception)
|
||||||
return@withContext Result.failure()
|
return@withContext null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.i(TAG, "No self-updates found!")
|
||||||
|
return@withContext null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun notifyUpdates(updates: List<Update>) {
|
||||||
|
with(appContext.getSystemService<NotificationManager>()!!) {
|
||||||
|
notify(
|
||||||
|
notificationID,
|
||||||
|
NotificationUtil.getUpdateNotification(appContext, updates)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return Result.success()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,6 +190,14 @@ object NotificationUtil {
|
|||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getUpdateNotification(context: Context): Notification {
|
||||||
|
return NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_UPDATES)
|
||||||
|
.setSmallIcon(R.drawable.ic_updates)
|
||||||
|
.setContentTitle(context.getString(R.string.checking_updates))
|
||||||
|
.setOngoing(true)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
fun getUpdateNotification(context: Context, updatesList: List<Update>): Notification {
|
fun getUpdateNotification(context: Context, updatesList: List<Update>): Notification {
|
||||||
val contentIntent = NavDeepLinkBuilder(context)
|
val contentIntent = NavDeepLinkBuilder(context)
|
||||||
.setGraph(R.navigation.mobile_navigation)
|
.setGraph(R.navigation.mobile_navigation)
|
||||||
@@ -261,6 +269,7 @@ object NotificationUtil {
|
|||||||
.setSmallIcon(R.drawable.ic_file_copy)
|
.setSmallIcon(R.drawable.ic_file_copy)
|
||||||
.setContentTitle(context.getString(R.string.export_app_title))
|
.setContentTitle(context.getString(R.string.export_app_title))
|
||||||
.setContentText(context.getString(R.string.export_app_summary))
|
.setContentText(context.getString(R.string.export_app_summary))
|
||||||
|
.setOngoing(true)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ class DownloadFragment : BaseFragment<FragmentDownloadBinding>() {
|
|||||||
.id(it.packageName)
|
.id(it.packageName)
|
||||||
.download(it)
|
.download(it)
|
||||||
.click { _ ->
|
.click { _ ->
|
||||||
if (it.packageName == Constants.APP_ID) {
|
if (it.packageName == requireContext().packageName) {
|
||||||
requireContext().browse(GITLAB_URL)
|
requireContext().browse(GITLAB_URL)
|
||||||
} else {
|
} else {
|
||||||
openDetailsFragment(it.packageName)
|
openDetailsFragment(it.packageName)
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ import com.aurora.Constants
|
|||||||
import com.aurora.extensions.areNotificationsEnabled
|
import com.aurora.extensions.areNotificationsEnabled
|
||||||
import com.aurora.extensions.isIgnoringBatteryOptimizations
|
import com.aurora.extensions.isIgnoringBatteryOptimizations
|
||||||
import com.aurora.store.R
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.data.helper.UpdateHelper
|
||||||
import com.aurora.store.data.work.CacheWorker
|
import com.aurora.store.data.work.CacheWorker
|
||||||
import com.aurora.store.data.work.UpdateWorker
|
|
||||||
import com.aurora.store.databinding.FragmentOnboardingBinding
|
import com.aurora.store.databinding.FragmentOnboardingBinding
|
||||||
import com.aurora.store.util.CertUtil
|
import com.aurora.store.util.CertUtil
|
||||||
import com.aurora.store.util.PackageUtil
|
import com.aurora.store.util.PackageUtil
|
||||||
@@ -59,10 +59,14 @@ import com.aurora.store.util.save
|
|||||||
import com.aurora.store.view.ui.commons.BaseFragment
|
import com.aurora.store.view.ui.commons.BaseFragment
|
||||||
import com.google.android.material.tabs.TabLayoutMediator
|
import com.google.android.material.tabs.TabLayoutMediator
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class OnboardingFragment : BaseFragment<FragmentOnboardingBinding>() {
|
class OnboardingFragment : BaseFragment<FragmentOnboardingBinding>() {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var updateHelper: UpdateHelper
|
||||||
|
|
||||||
private var lastPosition = 0
|
private var lastPosition = 0
|
||||||
|
|
||||||
internal class PagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
|
internal class PagerAdapter(fragmentManager: FragmentManager, lifecycle: Lifecycle) :
|
||||||
@@ -190,6 +194,6 @@ class OnboardingFragment : BaseFragment<FragmentOnboardingBinding>() {
|
|||||||
else -> 0 // Disable
|
else -> 0 // Disable
|
||||||
}
|
}
|
||||||
save(PREFERENCE_UPDATES_AUTO, updateMode)
|
save(PREFERENCE_UPDATES_AUTO, updateMode)
|
||||||
UpdateWorker.scheduleAutomatedCheck(requireContext())
|
updateHelper.scheduleAutomatedCheck()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,14 +28,18 @@ import androidx.preference.SeekBarPreference
|
|||||||
import com.aurora.extensions.isIgnoringBatteryOptimizations
|
import com.aurora.extensions.isIgnoringBatteryOptimizations
|
||||||
import com.aurora.store.MobileNavigationDirections
|
import com.aurora.store.MobileNavigationDirections
|
||||||
import com.aurora.store.R
|
import com.aurora.store.R
|
||||||
import com.aurora.store.data.work.UpdateWorker
|
import com.aurora.store.data.helper.UpdateHelper
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_AUTO
|
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_AUTO
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_CHECK_INTERVAL
|
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_CHECK_INTERVAL
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class UpdatesPreference : BasePreferenceFragment() {
|
class UpdatesPreference : BasePreferenceFragment() {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var updateHelper: UpdateHelper
|
||||||
|
|
||||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
setPreferencesFromResource(R.xml.preferences_updates, rootKey)
|
setPreferencesFromResource(R.xml.preferences_updates, rootKey)
|
||||||
|
|
||||||
@@ -43,11 +47,11 @@ class UpdatesPreference : BasePreferenceFragment() {
|
|||||||
?.setOnPreferenceChangeListener { _, newValue ->
|
?.setOnPreferenceChangeListener { _, newValue ->
|
||||||
val value = newValue.toString().toInt()
|
val value = newValue.toString().toInt()
|
||||||
when (value) {
|
when (value) {
|
||||||
0 -> UpdateWorker.cancelAutomatedCheck(requireContext())
|
0 -> updateHelper.cancelAutomatedCheck()
|
||||||
1 -> UpdateWorker.scheduleAutomatedCheck(requireContext())
|
1 -> updateHelper.scheduleAutomatedCheck()
|
||||||
else -> {
|
else -> {
|
||||||
if (requireContext().isIgnoringBatteryOptimizations()) {
|
if (requireContext().isIgnoringBatteryOptimizations()) {
|
||||||
UpdateWorker.scheduleAutomatedCheck(requireContext())
|
updateHelper.scheduleAutomatedCheck()
|
||||||
return@setOnPreferenceChangeListener true
|
return@setOnPreferenceChangeListener true
|
||||||
} else {
|
} else {
|
||||||
findNavController().navigate(
|
findNavController().navigate(
|
||||||
@@ -61,7 +65,7 @@ class UpdatesPreference : BasePreferenceFragment() {
|
|||||||
|
|
||||||
findPreference<SeekBarPreference>(PREFERENCE_UPDATES_CHECK_INTERVAL)
|
findPreference<SeekBarPreference>(PREFERENCE_UPDATES_CHECK_INTERVAL)
|
||||||
?.setOnPreferenceChangeListener { _, _ ->
|
?.setOnPreferenceChangeListener { _, _ ->
|
||||||
UpdateWorker.updateAutomatedCheck(requireContext())
|
updateHelper.updateAutomatedCheck()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,14 +7,20 @@ import com.aurora.extensions.isIgnoringBatteryOptimizations
|
|||||||
import com.aurora.extensions.toast
|
import com.aurora.extensions.toast
|
||||||
import com.aurora.store.PermissionType
|
import com.aurora.store.PermissionType
|
||||||
import com.aurora.store.R
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.data.helper.UpdateHelper
|
||||||
import com.aurora.store.data.providers.PermissionProvider
|
import com.aurora.store.data.providers.PermissionProvider
|
||||||
import com.aurora.store.data.work.UpdateWorker
|
|
||||||
import com.aurora.store.databinding.SheetDozeWarningBinding
|
import com.aurora.store.databinding.SheetDozeWarningBinding
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_AUTO
|
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_AUTO
|
||||||
import com.aurora.store.util.save
|
import com.aurora.store.util.save
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
class DozeWarningSheet : BaseDialogSheet<SheetDozeWarningBinding>() {
|
class DozeWarningSheet : BaseDialogSheet<SheetDozeWarningBinding>() {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var updateHelper: UpdateHelper
|
||||||
|
|
||||||
private val args: DozeWarningSheetArgs by navArgs()
|
private val args: DozeWarningSheetArgs by navArgs()
|
||||||
|
|
||||||
private lateinit var permissionProvider: PermissionProvider
|
private lateinit var permissionProvider: PermissionProvider
|
||||||
@@ -26,7 +32,7 @@ class DozeWarningSheet : BaseDialogSheet<SheetDozeWarningBinding>() {
|
|||||||
if (requireContext().isIgnoringBatteryOptimizations()) {
|
if (requireContext().isIgnoringBatteryOptimizations()) {
|
||||||
if (args.enableAutoUpdate) {
|
if (args.enableAutoUpdate) {
|
||||||
requireContext().save(PREFERENCE_UPDATES_AUTO, 2)
|
requireContext().save(PREFERENCE_UPDATES_AUTO, 2)
|
||||||
UpdateWorker.scheduleAutomatedCheck(requireContext())
|
updateHelper.scheduleAutomatedCheck()
|
||||||
}
|
}
|
||||||
toast(R.string.toast_permission_granted)
|
toast(R.string.toast_permission_granted)
|
||||||
activity?.recreate()
|
activity?.recreate()
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ class UpdatesFragment : BaseFragment<FragmentUpdatesBinding>() {
|
|||||||
.update(update)
|
.update(update)
|
||||||
.download(download)
|
.download(download)
|
||||||
.click { _ ->
|
.click { _ ->
|
||||||
if (update.packageName == Constants.APP_ID) {
|
if (update.packageName == requireContext().packageName) {
|
||||||
requireContext().browse(Constants.GITLAB_URL)
|
requireContext().browse(Constants.GITLAB_URL)
|
||||||
} else {
|
} else {
|
||||||
openDetailsFragment(update.packageName)
|
openDetailsFragment(update.packageName)
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class UpdatesViewModel @Inject constructor(
|
|||||||
_fetchingUpdates.value = true
|
_fetchingUpdates.value = true
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
updateHelper.checkUpdates()
|
updateHelper.checkUpdatesNow()
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Log.d(TAG, "Failed to get updates", exception)
|
Log.d(TAG, "Failed to get updates", exception)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -454,6 +454,7 @@
|
|||||||
|
|
||||||
<!-- UpdatesFragment -->
|
<!-- UpdatesFragment -->
|
||||||
<string name="check_updates">Check for updates</string>
|
<string name="check_updates">Check for updates</string>
|
||||||
|
<string name="checking_updates">Checking for updates</string>
|
||||||
|
|
||||||
<!-- ForceRestartDialog -->
|
<!-- ForceRestartDialog -->
|
||||||
<string name="force_restart_title">Restart Aurora Store</string>
|
<string name="force_restart_title">Restart Aurora Store</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user