Implement automated updates check
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -37,6 +37,7 @@ object Constants {
|
||||
|
||||
const val NOTIFICATION_CHANNEL_ALERT = "NOTIFICATION_CHANNEL_ALERT"
|
||||
const val NOTIFICATION_CHANNEL_GENERAL = "NOTIFICATION_CHANNEL_GENERAL"
|
||||
const val NOTIFICATION_CHANNEL_UPDATES = "NOTIFICATION_CHANNEL_UPDATES"
|
||||
const val NOTIFICATION_CHANNEL_UPDATER_SERVICE = "NOTIFICATION_CHANNEL_UPDATER_SERVICE"
|
||||
|
||||
const val URL_DISPENSER = "https://auroraoss.com/api/auth"
|
||||
@@ -53,4 +54,7 @@ object Constants {
|
||||
const val PAGE_TYPE = "PAGE_TYPE"
|
||||
const val TOP_CHART_TYPE = "TOP_CHART_TYPE"
|
||||
const val TOP_CHART_CATEGORY = "TOP_CHART_CATEGORY"
|
||||
|
||||
//NAVIGATION
|
||||
const val NAVIGATION_UPDATES = "NAVIGATION_UPDATES"
|
||||
}
|
||||
|
||||
@@ -113,6 +113,13 @@ class AuroraApplication : MultiDexApplication() {
|
||||
NotificationManager.IMPORTANCE_MIN
|
||||
)
|
||||
)
|
||||
channels.add(
|
||||
NotificationChannel(
|
||||
Constants.NOTIFICATION_CHANNEL_UPDATES,
|
||||
getString(R.string.notification_channel_updates),
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
)
|
||||
)
|
||||
notificationManager.createNotificationChannels(channels)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,6 +165,12 @@ class MainActivity : BaseActivity() {
|
||||
B.drawerLayout.close()
|
||||
}
|
||||
}
|
||||
|
||||
// Handle intents
|
||||
when (intent?.action) {
|
||||
Constants.NAVIGATION_UPDATES -> B.navView.selectedItemId = R.id.navigation_updates
|
||||
else -> Log.i("Unhandled intent action: ${intent.action}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun attachToolbar() {
|
||||
|
||||
239
app/src/main/java/com/aurora/store/data/work/UpdateWorker.kt
Normal file
239
app/src/main/java/com/aurora/store/data/work/UpdateWorker.kt
Normal file
@@ -0,0 +1,239 @@
|
||||
package com.aurora.store.data.work
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE
|
||||
import androidx.core.content.pm.PackageInfoCompat
|
||||
import androidx.work.Constraints
|
||||
import androidx.work.CoroutineWorker
|
||||
import androidx.work.ExistingPeriodicWorkPolicy.KEEP
|
||||
import androidx.work.ForegroundInfo
|
||||
import androidx.work.NetworkType
|
||||
import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import androidx.work.WorkerParameters
|
||||
import com.aurora.Constants
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.gplayapi.data.models.AuthData
|
||||
import com.aurora.gplayapi.helpers.AppDetailsHelper
|
||||
import com.aurora.gplayapi.helpers.AuthValidator
|
||||
import com.aurora.store.MainActivity
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.network.HttpClient
|
||||
import com.aurora.store.data.providers.AuthProvider
|
||||
import com.aurora.store.data.providers.BlacklistProvider
|
||||
import com.aurora.store.util.Log
|
||||
import com.aurora.store.util.PackageUtil
|
||||
import com.aurora.store.util.Preferences
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.concurrent.TimeUnit.HOURS
|
||||
import java.util.concurrent.TimeUnit.MINUTES
|
||||
|
||||
class UpdateWorker(private val appContext: Context, workerParams: WorkerParameters) :
|
||||
CoroutineWorker(appContext, workerParams) {
|
||||
|
||||
companion object {
|
||||
private const val WORK_NAME_CHECK = "WORK_NAME_CHECK"
|
||||
|
||||
fun cancelAutomatedCheck(context: Context) {
|
||||
Log.i("Cancelling periodic app updates check!")
|
||||
WorkManager.getInstance(context)
|
||||
.cancelUniqueWork(WORK_NAME_CHECK)
|
||||
}
|
||||
|
||||
fun scheduleAutomatedCheck(context: Context) {
|
||||
Log.i("Scheduling periodic app updates check!")
|
||||
|
||||
val constraints = Constraints.Builder()
|
||||
.setRequiredNetworkType(NetworkType.UNMETERED)
|
||||
.setRequiresDeviceIdle(true)
|
||||
.setRequiresBatteryNotLow(true)
|
||||
.build()
|
||||
val workRequest = PeriodicWorkRequestBuilder<UpdateWorker>(
|
||||
repeatInterval = 3,
|
||||
repeatIntervalTimeUnit = HOURS,
|
||||
flexTimeInterval = 30,
|
||||
flexTimeIntervalUnit = MINUTES
|
||||
).setConstraints(constraints).build()
|
||||
|
||||
val workManager = WorkManager.getInstance(context)
|
||||
workManager.enqueueUniquePeriodicWork(WORK_NAME_CHECK, KEEP, workRequest)
|
||||
}
|
||||
}
|
||||
|
||||
private val notificationID = 100
|
||||
private val workerID = 101
|
||||
private val gapps: MutableSet<String> = hashSetOf(
|
||||
"com.chrome.beta",
|
||||
"com.chrome.canary",
|
||||
"com.chrome.dev",
|
||||
"com.android.chrome",
|
||||
"com.niksoftware.snapseed",
|
||||
"com.google.toontastic"
|
||||
)
|
||||
|
||||
private val authData = AuthProvider.with(appContext)
|
||||
.getAuthData()
|
||||
private val blackList = BlacklistProvider.with(appContext)
|
||||
.getBlackList()
|
||||
|
||||
override suspend fun getForegroundInfo(): ForegroundInfo {
|
||||
return ForegroundInfo(workerID, getOngoingNotification())
|
||||
}
|
||||
|
||||
override suspend fun doWork(): Result {
|
||||
withContext(Dispatchers.IO) {
|
||||
|
||||
if (!isValid(authData)) {
|
||||
Log.i("AuthData is not valid, retrying later!")
|
||||
return@withContext Result.retry()
|
||||
}
|
||||
|
||||
Log.i("Checking for app updates")
|
||||
|
||||
val appDetailsHelper = AppDetailsHelper(authData)
|
||||
.using(HttpClient.getPreferredClient())
|
||||
|
||||
val isGoogleFilterEnabled = Preferences.getBoolean(
|
||||
appContext,
|
||||
Preferences.PREFERENCE_FILTER_GOOGLE
|
||||
)
|
||||
val packageInfoMap = PackageUtil.getPackageInfoMap(appContext)
|
||||
|
||||
packageInfoMap.keys.let { packages ->
|
||||
/*Filter black list*/
|
||||
var filtersPackages = packages.filter { !blackList.contains(it) }
|
||||
|
||||
/*Filter google apps*/
|
||||
if (isGoogleFilterEnabled) {
|
||||
filtersPackages = filtersPackages
|
||||
.filter { !it.startsWith("com.google") }
|
||||
.filter { !gapps.contains(it) }
|
||||
}
|
||||
|
||||
val appList = appDetailsHelper.getAppByPackageName(filtersPackages)
|
||||
.filter { it.displayName.isNotEmpty() }
|
||||
|
||||
val updatesList = appList.filter {
|
||||
val packageInfo = packageInfoMap[it.packageName]
|
||||
if (packageInfo != null) {
|
||||
it.versionCode.toLong() > PackageInfoCompat.getLongVersionCode(packageInfo)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
if (updatesList.isNotEmpty()) {
|
||||
Log.i("Found updates, notifying!")
|
||||
val notifyManager = appContext.getSystemService(Context.NOTIFICATION_SERVICE)
|
||||
as NotificationManager
|
||||
notifyManager.notify(notificationID, getUpdateNotification(updatesList))
|
||||
return@withContext Result.success()
|
||||
}
|
||||
|
||||
Log.i("No updates found!")
|
||||
return@withContext Result.success()
|
||||
}
|
||||
}
|
||||
return Result.failure()
|
||||
}
|
||||
|
||||
private fun isValid(authData: AuthData): Boolean {
|
||||
return try {
|
||||
AuthValidator(authData)
|
||||
.using(HttpClient.getPreferredClient())
|
||||
.isValid()
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun getUpdateNotification(updatesList: List<App>): Notification {
|
||||
val contentIntent = PendingIntent.getActivity(
|
||||
appContext,
|
||||
0,
|
||||
Intent(appContext, MainActivity::class.java).apply {
|
||||
action = Constants.NAVIGATION_UPDATES
|
||||
},
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
return NotificationCompat.Builder(appContext, Constants.NOTIFICATION_CHANNEL_UPDATES)
|
||||
.setSmallIcon(R.drawable.ic_logo)
|
||||
.setContentTitle(
|
||||
appContext.getString(
|
||||
R.string.notification_updates_available,
|
||||
updatesList.size
|
||||
)
|
||||
)
|
||||
.setContentText(
|
||||
when (updatesList.size) {
|
||||
1 -> {
|
||||
appContext.getString(
|
||||
R.string.notification_updates_available_desc_1,
|
||||
updatesList[0].displayName
|
||||
)
|
||||
}
|
||||
|
||||
2 -> {
|
||||
appContext.getString(
|
||||
R.string.notification_updates_available_desc_2,
|
||||
updatesList[0].displayName,
|
||||
updatesList[1].displayName
|
||||
)
|
||||
}
|
||||
|
||||
3 -> {
|
||||
appContext.getString(
|
||||
R.string.notification_updates_available_desc_3,
|
||||
updatesList[0].displayName,
|
||||
updatesList[1].displayName,
|
||||
updatesList[2].displayName
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
appContext.getString(
|
||||
R.string.notification_updates_available_desc_4,
|
||||
updatesList[0].displayName,
|
||||
updatesList[1].displayName,
|
||||
updatesList[2].displayName,
|
||||
updatesList.size - 3
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
.setContentIntent(contentIntent)
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
.setCategory(NotificationCompat.CATEGORY_RECOMMENDATION)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setAutoCancel(true)
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun getOngoingNotification(): Notification {
|
||||
val contentIntent = PendingIntent.getActivity(
|
||||
appContext,
|
||||
0,
|
||||
Intent(appContext, MainActivity::class.java),
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
return NotificationCompat.Builder(appContext, Constants.NOTIFICATION_CHANNEL_UPDATES)
|
||||
.setSmallIcon(R.drawable.ic_logo)
|
||||
.setContentTitle(appContext.getString(R.string.checking_for_updates))
|
||||
.setContentIntent(contentIntent)
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
.setCategory(NotificationCompat.CATEGORY_SERVICE)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setForegroundServiceBehavior(FOREGROUND_SERVICE_IMMEDIATE)
|
||||
.setProgress(100, 0, true)
|
||||
.setOngoing(true)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
@@ -58,6 +58,7 @@ object Preferences {
|
||||
const val PREFERENCE_INSECURE_ANONYMOUS = "PREFERENCE_INSECURE_ANONYMOUS"
|
||||
|
||||
const val PREFERENCE_UPDATES_EXTENDED = "PREFERENCE_UPDATES_EXTENDED"
|
||||
const val PREFERENCE_UPDATES_CHECK = "PREFERENCE_UPDATES_CHECK"
|
||||
|
||||
const val PREFERENCE_ADVANCED_SEARCH_IN_CTT = "PREFERENCE_ADVANCED_SEARCH_IN_CTT"
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.aurora.Constants
|
||||
import com.aurora.extensions.isSAndAbove
|
||||
import com.aurora.extensions.open
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.work.UpdateWorker
|
||||
import com.aurora.store.databinding.ActivityOnboardingBinding
|
||||
import com.aurora.store.util.Preferences
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_AUTO_DELETE
|
||||
@@ -48,6 +49,7 @@ import com.aurora.store.util.Preferences.PREFERENCE_QUICK_EXIT
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_SIMILAR
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_THEME_ACCENT
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_THEME_TYPE
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_CHECK
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_EXTENDED
|
||||
import com.aurora.store.util.save
|
||||
import com.aurora.store.view.ui.commons.BaseActivity
|
||||
@@ -152,6 +154,7 @@ class OnboardingActivity : BaseActivity() {
|
||||
B.btnForward.isEnabled = true
|
||||
B.btnForward.setOnClickListener {
|
||||
save(PREFERENCE_INTRO, true)
|
||||
UpdateWorker.scheduleAutomatedCheck(this)
|
||||
open(SplashActivity::class.java, true)
|
||||
}
|
||||
} else {
|
||||
@@ -191,6 +194,7 @@ class OnboardingActivity : BaseActivity() {
|
||||
|
||||
/*Updates*/
|
||||
save(PREFERENCE_UPDATES_EXTENDED, false)
|
||||
save(PREFERENCE_UPDATES_CHECK, true)
|
||||
}
|
||||
|
||||
internal class PagerAdapter(fragmentActivity: FragmentActivity) :
|
||||
|
||||
@@ -20,16 +20,25 @@
|
||||
package com.aurora.store.view.ui.preferences
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import com.aurora.extensions.runOnUiThread
|
||||
import com.aurora.extensions.toast
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.util.CommonUtil
|
||||
import com.aurora.store.util.Preferences
|
||||
import com.aurora.store.data.work.UpdateWorker
|
||||
import com.aurora.store.util.Log
|
||||
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_CHECK
|
||||
|
||||
class UpdatesPreference : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.preferences_updates, rootKey)
|
||||
|
||||
findPreference<SwitchPreferenceCompat>(PREFERENCE_UPDATES_CHECK)
|
||||
?.setOnPreferenceChangeListener { _, newValue ->
|
||||
if (newValue.toString().toBoolean()) {
|
||||
UpdateWorker.scheduleAutomatedCheck(requireContext())
|
||||
} else {
|
||||
UpdateWorker.cancelAutomatedCheck(requireContext())
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user