Implement automated updates check
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -181,6 +181,9 @@ dependencies {
|
|||||||
testImplementation 'junit:junit:4.13.2'
|
testImplementation 'junit:junit:4.13.2'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
||||||
|
|
||||||
|
//WorkManager
|
||||||
|
implementation "androidx.work:work-runtime-ktx:2.8.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
Properties props = new Properties()
|
Properties props = new Properties()
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ object Constants {
|
|||||||
|
|
||||||
const val NOTIFICATION_CHANNEL_ALERT = "NOTIFICATION_CHANNEL_ALERT"
|
const val NOTIFICATION_CHANNEL_ALERT = "NOTIFICATION_CHANNEL_ALERT"
|
||||||
const val NOTIFICATION_CHANNEL_GENERAL = "NOTIFICATION_CHANNEL_GENERAL"
|
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 NOTIFICATION_CHANNEL_UPDATER_SERVICE = "NOTIFICATION_CHANNEL_UPDATER_SERVICE"
|
||||||
|
|
||||||
const val URL_DISPENSER = "https://auroraoss.com/api/auth"
|
const val URL_DISPENSER = "https://auroraoss.com/api/auth"
|
||||||
@@ -53,4 +54,7 @@ object Constants {
|
|||||||
const val PAGE_TYPE = "PAGE_TYPE"
|
const val PAGE_TYPE = "PAGE_TYPE"
|
||||||
const val TOP_CHART_TYPE = "TOP_CHART_TYPE"
|
const val TOP_CHART_TYPE = "TOP_CHART_TYPE"
|
||||||
const val TOP_CHART_CATEGORY = "TOP_CHART_CATEGORY"
|
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
|
NotificationManager.IMPORTANCE_MIN
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
channels.add(
|
||||||
|
NotificationChannel(
|
||||||
|
Constants.NOTIFICATION_CHANNEL_UPDATES,
|
||||||
|
getString(R.string.notification_channel_updates),
|
||||||
|
NotificationManager.IMPORTANCE_DEFAULT
|
||||||
|
)
|
||||||
|
)
|
||||||
notificationManager.createNotificationChannels(channels)
|
notificationManager.createNotificationChannels(channels)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,6 +165,12 @@ class MainActivity : BaseActivity() {
|
|||||||
B.drawerLayout.close()
|
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() {
|
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_INSECURE_ANONYMOUS = "PREFERENCE_INSECURE_ANONYMOUS"
|
||||||
|
|
||||||
const val PREFERENCE_UPDATES_EXTENDED = "PREFERENCE_UPDATES_EXTENDED"
|
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"
|
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.isSAndAbove
|
||||||
import com.aurora.extensions.open
|
import com.aurora.extensions.open
|
||||||
import com.aurora.store.R
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.data.work.UpdateWorker
|
||||||
import com.aurora.store.databinding.ActivityOnboardingBinding
|
import com.aurora.store.databinding.ActivityOnboardingBinding
|
||||||
import com.aurora.store.util.Preferences
|
import com.aurora.store.util.Preferences
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_AUTO_DELETE
|
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_SIMILAR
|
||||||
import com.aurora.store.util.Preferences.PREFERENCE_THEME_ACCENT
|
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_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.Preferences.PREFERENCE_UPDATES_EXTENDED
|
||||||
import com.aurora.store.util.save
|
import com.aurora.store.util.save
|
||||||
import com.aurora.store.view.ui.commons.BaseActivity
|
import com.aurora.store.view.ui.commons.BaseActivity
|
||||||
@@ -152,6 +154,7 @@ class OnboardingActivity : BaseActivity() {
|
|||||||
B.btnForward.isEnabled = true
|
B.btnForward.isEnabled = true
|
||||||
B.btnForward.setOnClickListener {
|
B.btnForward.setOnClickListener {
|
||||||
save(PREFERENCE_INTRO, true)
|
save(PREFERENCE_INTRO, true)
|
||||||
|
UpdateWorker.scheduleAutomatedCheck(this)
|
||||||
open(SplashActivity::class.java, true)
|
open(SplashActivity::class.java, true)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -191,6 +194,7 @@ class OnboardingActivity : BaseActivity() {
|
|||||||
|
|
||||||
/*Updates*/
|
/*Updates*/
|
||||||
save(PREFERENCE_UPDATES_EXTENDED, false)
|
save(PREFERENCE_UPDATES_EXTENDED, false)
|
||||||
|
save(PREFERENCE_UPDATES_CHECK, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class PagerAdapter(fragmentActivity: FragmentActivity) :
|
internal class PagerAdapter(fragmentActivity: FragmentActivity) :
|
||||||
|
|||||||
@@ -20,16 +20,25 @@
|
|||||||
package com.aurora.store.view.ui.preferences
|
package com.aurora.store.view.ui.preferences
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.preference.Preference
|
|
||||||
import androidx.preference.PreferenceFragmentCompat
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
import com.aurora.extensions.runOnUiThread
|
import androidx.preference.SwitchPreferenceCompat
|
||||||
import com.aurora.extensions.toast
|
|
||||||
import com.aurora.store.R
|
import com.aurora.store.R
|
||||||
import com.aurora.store.util.CommonUtil
|
import com.aurora.store.data.work.UpdateWorker
|
||||||
import com.aurora.store.util.Preferences
|
import com.aurora.store.util.Log
|
||||||
|
import com.aurora.store.util.Preferences.PREFERENCE_UPDATES_CHECK
|
||||||
|
|
||||||
class UpdatesPreference : PreferenceFragmentCompat() {
|
class UpdatesPreference : PreferenceFragmentCompat() {
|
||||||
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)
|
||||||
|
|
||||||
|
findPreference<SwitchPreferenceCompat>(PREFERENCE_UPDATES_CHECK)
|
||||||
|
?.setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
if (newValue.toString().toBoolean()) {
|
||||||
|
UpdateWorker.scheduleAutomatedCheck(requireContext())
|
||||||
|
} else {
|
||||||
|
UpdateWorker.cancelAutomatedCheck(requireContext())
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -355,4 +355,13 @@
|
|||||||
<string name="requesting_new_session">Requesting new session</string>
|
<string name="requesting_new_session">Requesting new session</string>
|
||||||
<string name="server_maintenance">Server down for maintenance</string>
|
<string name="server_maintenance">Server down for maintenance</string>
|
||||||
<string name="downloading_dep">Downloading additional files for <xliff:g id="app">%1$s</xliff:g></string>
|
<string name="downloading_dep">Downloading additional files for <xliff:g id="app">%1$s</xliff:g></string>
|
||||||
|
<string name="notification_channel_updates">Updates notifications</string>
|
||||||
|
<string name="notification_updates_available"><xliff:g id="apps_count">%1$d</xliff:g> updates available</string>
|
||||||
|
<string name="notification_updates_available_desc_1">A new version of <xliff:g id="app_one_name">%1$s</xliff:g> is available</string>
|
||||||
|
<string name="notification_updates_available_desc_2"><xliff:g id="app_one_name">%1$s</xliff:g> and <xliff:g id="app_two_name">%2$s</xliff:g></string>
|
||||||
|
<string name="notification_updates_available_desc_3"><xliff:g id="app_one_name">%1$s</xliff:g>, <xliff:g id="app_two_name">%2$s</xliff:g> and <xliff:g id="app_three_name">%3$s</xliff:g></string>
|
||||||
|
<string name="notification_updates_available_desc_4"><xliff:g id="app_one_name">%1$s</xliff:g>, <xliff:g id="app_two_name">%2$s</xliff:g>, <xliff:g id="app_three_name">%3$s</xliff:g> and <xliff:g id="apps_count">%4$d</xliff:g> more</string>
|
||||||
|
<string name="checking_for_updates">Checking for updates</string>
|
||||||
|
<string name="pref_updates_check">Automated updates check</string>
|
||||||
|
<string name="pref_updates_check_desc">Automatically check & notify for new app updates periodically</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -27,4 +27,11 @@
|
|||||||
app:summary="@string/pref_updates_extended_desc"
|
app:summary="@string/pref_updates_extended_desc"
|
||||||
app:title="@string/pref_updates_extended" />
|
app:title="@string/pref_updates_extended" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
app:defaultValue="true"
|
||||||
|
app:iconSpaceReserved="false"
|
||||||
|
app:key="PREFERENCE_UPDATES_CHECK"
|
||||||
|
app:summary="@string/pref_updates_check_desc"
|
||||||
|
app:title="@string/pref_updates_check" />
|
||||||
|
|
||||||
</androidx.preference.PreferenceScreen>
|
</androidx.preference.PreferenceScreen>
|
||||||
|
|||||||
Reference in New Issue
Block a user