Complete auto updates checker (#449)

* Complete auto updates checker

* Use GcmTaskService for the periodical updates checker

* Persist task across reinstalls

* Hide setting instead of disabling

* Minor refactor
This commit is contained in:
inorichi 2016-09-07 19:44:55 +02:00 committed by GitHub
parent a4b71f4d11
commit ccdc336112
14 changed files with 384 additions and 381 deletions

View File

@ -96,6 +96,8 @@ dependencies {
compile "com.android.support:support-annotations:$support_library_version" compile "com.android.support:support-annotations:$support_library_version"
compile "com.android.support:customtabs:$support_library_version" compile "com.android.support:customtabs:$support_library_version"
compile 'com.google.android.gms:play-services-gcm:9.4.0'
// ReactiveX // ReactiveX
compile 'io.reactivex:rxandroid:1.2.1' compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.1.8' compile 'io.reactivex:rxjava:1.1.8'

View File

@ -59,6 +59,20 @@
<service android:name=".data.mangasync.UpdateMangaSyncService" <service android:name=".data.mangasync.UpdateMangaSyncService"
android:exported="false"/> android:exported="false"/>
<service
android:name=".data.updater.UpdateCheckerService"
android:exported="true"
android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE">
<intent-filter>
<action android:name="com.google.android.gms.gcm.ACTION_TASK_READY" />
</intent-filter>
</service>
<service android:name=".data.updater.UpdateDownloaderService"
android:exported="false"/>
<receiver android:name=".data.updater.UpdateNotificationReceiver"/>
<receiver <receiver
android:name=".data.library.LibraryUpdateService$SyncOnConnectionAvailable" android:name=".data.library.LibraryUpdateService$SyncOnConnectionAvailable"
android:enabled="false"> android:enabled="false">
@ -79,10 +93,6 @@
android:name=".data.library.LibraryUpdateService$CancelUpdateReceiver"> android:name=".data.library.LibraryUpdateService$CancelUpdateReceiver">
</receiver> </receiver>
<receiver
android:name=".data.updater.UpdateDownloader$InstallOnReceived">
</receiver>
<receiver <receiver
android:name=".data.library.LibraryUpdateAlarm"> android:name=".data.library.LibraryUpdateAlarm">
<intent-filter> <intent-filter>
@ -91,15 +101,6 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<receiver
android:name=".data.updater.UpdateDownloaderAlarm">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="eu.kanade.CHECK_UPDATE"/>
</intent-filter>
</receiver>
<meta-data <meta-data
android:name="eu.kanade.tachiyomi.data.glide.AppGlideModule" android:name="eu.kanade.tachiyomi.data.glide.AppGlideModule"
android:value="GlideModule" /> android:value="GlideModule" />

View File

@ -78,7 +78,7 @@ class PreferenceKeys(context: Context) {
val filterUnread = context.getString(R.string.pref_filter_unread_key) val filterUnread = context.getString(R.string.pref_filter_unread_key)
val automaticUpdateStatus = context.getString(R.string.pref_enable_automatic_updates_key) val automaticUpdates = context.getString(R.string.pref_enable_automatic_updates_key)
val startScreen = context.getString(R.string.pref_start_screen_key) val startScreen = context.getString(R.string.pref_start_screen_key)

View File

@ -130,6 +130,6 @@ class PreferencesHelper(context: Context) {
fun filterUnread() = rxPrefs.getBoolean(keys.filterUnread, false) fun filterUnread() = rxPrefs.getBoolean(keys.filterUnread, false)
fun automaticUpdateStatus() = prefs.getBoolean(keys.automaticUpdateStatus, false) fun automaticUpdates() = prefs.getBoolean(keys.automaticUpdates, false)
} }

View File

@ -6,7 +6,6 @@ import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET import retrofit2.http.GET
import rx.Observable import rx.Observable
/** /**
* Used to connect with the Github API. * Used to connect with the Github API.
*/ */

View File

@ -1,20 +1,25 @@
package eu.kanade.tachiyomi.data.updater package eu.kanade.tachiyomi.data.updater
import android.content.Context import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.toast
import rx.Observable import rx.Observable
class GithubUpdateChecker() {
class GithubUpdateChecker(private val context: Context) { private val service: GithubService = GithubService.create()
val service: GithubService = GithubService.create()
/** /**
* Returns observable containing release information * Returns observable containing release information
*/ */
fun checkForApplicationUpdate(): Observable<GithubRelease> { fun checkForUpdate(): Observable<GithubUpdateResult> {
context.toast(R.string.update_check_look_for_updates) return service.getLatestVersion().map { release ->
return service.getLatestVersion() val newVersion = release.version.replace("[^\\d.]".toRegex(), "")
// Check if latest version is different from current version
if (newVersion != BuildConfig.VERSION_NAME) {
GithubUpdateResult.NewUpdate(release)
} else {
GithubUpdateResult.NoNewUpdate()
}
}
} }
} }

View File

@ -0,0 +1,7 @@
package eu.kanade.tachiyomi.data.updater
sealed class GithubUpdateResult {
class NewUpdate(val release: GithubRelease): GithubUpdateResult()
class NoNewUpdate(): GithubUpdateResult()
}

View File

@ -0,0 +1,80 @@
package eu.kanade.tachiyomi.data.updater
import android.content.Context
import android.support.v4.app.NotificationCompat
import com.google.android.gms.gcm.*
import eu.kanade.tachiyomi.Constants.NOTIFICATION_UPDATER_ID
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.util.notificationManager
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class UpdateCheckerService : GcmTaskService() {
override fun onInitializeTasks() {
val preferences: PreferencesHelper = Injekt.get()
if (preferences.automaticUpdates()) {
setupTask(this)
}
}
override fun onRunTask(params: TaskParams): Int {
return checkVersion()
}
fun checkVersion(): Int {
return GithubUpdateChecker()
.checkForUpdate()
.map { result ->
if (result is GithubUpdateResult.NewUpdate) {
val url = result.release.downloadLink
NotificationCompat.Builder(this).update {
setContentTitle(getString(R.string.app_name))
setContentText(getString(R.string.update_check_notification_update_available))
setSmallIcon(android.R.drawable.stat_sys_download_done)
// Download action
addAction(android.R.drawable.stat_sys_download_done,
getString(R.string.action_download),
UpdateNotificationReceiver.downloadApkIntent(
this@UpdateCheckerService, url))
}
}
GcmNetworkManager.RESULT_SUCCESS
}
.onErrorReturn { GcmNetworkManager.RESULT_FAILURE }
// Sadly, the task needs to be synchronous.
.toBlocking()
.single()
}
fun NotificationCompat.Builder.update(block: NotificationCompat.Builder.() -> Unit) {
block()
notificationManager.notify(NOTIFICATION_UPDATER_ID, build())
}
companion object {
fun setupTask(context: Context) {
val task = PeriodicTask.Builder()
.setService(UpdateCheckerService::class.java)
.setTag("Updater")
// 24 hours
.setPeriod(24 * 60 * 60)
// Run between the last two hours
.setFlex(2 * 60 * 60)
.setRequiredNetwork(Task.NETWORK_STATE_CONNECTED)
.setPersisted(true)
.setUpdateCurrent(true)
.build()
GcmNetworkManager.getInstance(context).schedule(task)
}
fun cancelTask(context: Context) {
GcmNetworkManager.getInstance(context).cancelAllTasks(UpdateCheckerService::class.java)
}
}
}

View File

@ -1,202 +0,0 @@
package eu.kanade.tachiyomi.data.updater
import android.app.Notification
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.AsyncTask
import android.support.v4.app.NotificationCompat
import eu.kanade.tachiyomi.Constants
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.network.GET
import eu.kanade.tachiyomi.data.network.NetworkHelper
import eu.kanade.tachiyomi.data.network.ProgressListener
import eu.kanade.tachiyomi.data.network.newCallWithProgress
import eu.kanade.tachiyomi.util.notificationManager
import eu.kanade.tachiyomi.util.saveTo
import timber.log.Timber
import uy.kohesive.injekt.injectLazy
import java.io.File
class UpdateDownloader(private val context: Context) :
AsyncTask<String, Int, UpdateDownloader.DownloadResult>() {
companion object {
/**
* Prompt user with apk install intent
* @param context context
* @param file file of apk that is installed
*/
fun installAPK(context: Context, file: File) {
// Prompt install interface
val intent = Intent(Intent.ACTION_VIEW)
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive")
// Without this flag android returned a intent error!
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
context.startActivity(intent)
}
}
val network: NetworkHelper by injectLazy()
/**
* Default download dir
*/
private val apkFile = File(context.externalCacheDir, "update.apk")
/**
* Notification builder
*/
private val notificationBuilder = NotificationCompat.Builder(context)
/**
* Id of the notification
*/
private val notificationId: Int
get() = Constants.NOTIFICATION_UPDATER_ID
/**
* Class containing download result
* @param url url of file
* @param successful status of download
*/
class DownloadResult(var url: String, var successful: Boolean)
/**
* Called before downloading
*/
override fun onPreExecute() {
// Create download notification
with(notificationBuilder) {
setContentTitle(context.getString(R.string.update_check_notification_file_download))
setContentText(context.getString(R.string.update_check_notification_download_in_progress))
setSmallIcon(android.R.drawable.stat_sys_download)
}
}
override fun doInBackground(vararg params: String?): DownloadResult {
// Initialize information array containing path and url to file.
val result = DownloadResult(params[0]!!, false)
// Progress of the download
var savedProgress = 0
val progressListener = object : ProgressListener {
override fun update(bytesRead: Long, contentLength: Long, done: Boolean) {
val progress = (100 * bytesRead / contentLength).toInt()
if (progress > savedProgress) {
savedProgress = progress
publishProgress(progress)
}
}
}
try {
// Make the request and download the file
val response = network.client.newCallWithProgress(GET(result.url), progressListener).execute()
if (response.isSuccessful) {
response.body().source().saveTo(apkFile)
// Set download successful
result.successful = true
} else {
response.close()
}
} catch (e: Exception) {
Timber.e(e, e.message)
}
return result
}
/**
* Called when progress is updated
* @param values values containing progress
*/
override fun onProgressUpdate(vararg values: Int?) {
// Notify notification manager to update notification
values.getOrNull(0)?.let {
notificationBuilder.setProgress(100, it, false)
// Displays the progress bar on notification
context.notificationManager.notify(notificationId, notificationBuilder.build())
}
}
/**
* Called when download done
* @param result string containing download information
*/
override fun onPostExecute(result: DownloadResult) {
with(notificationBuilder) {
if (result.successful) {
setContentTitle(context.getString(R.string.app_name))
setContentText(context.getString(R.string.update_check_notification_download_complete))
addAction(R.drawable.ic_system_update_grey_24dp_img, context.getString(R.string.action_install),
getInstallOnReceivedIntent(InstallOnReceived.INSTALL_APK, apkFile.absolutePath))
addAction(R.drawable.ic_clear_grey_24dp_img, context.getString(R.string.action_cancel),
getInstallOnReceivedIntent(InstallOnReceived.CANCEL_NOTIFICATION))
} else {
setContentText(context.getString(R.string.update_check_notification_download_error))
addAction(R.drawable.ic_refresh_grey_24dp_img, context.getString(R.string.action_retry),
getInstallOnReceivedIntent(InstallOnReceived.RETRY_DOWNLOAD, result.url))
addAction(R.drawable.ic_clear_grey_24dp_img, context.getString(R.string.action_cancel),
getInstallOnReceivedIntent(InstallOnReceived.CANCEL_NOTIFICATION))
}
setSmallIcon(android.R.drawable.stat_sys_download_done)
setProgress(0, 0, false)
}
val notification = notificationBuilder.build()
notification.flags = Notification.FLAG_NO_CLEAR
context.notificationManager.notify(notificationId, notification)
}
/**
* Returns broadcast intent
* @param action action name of broadcast intent
* @param path path of file | url of file
* @return broadcast intent
*/
fun getInstallOnReceivedIntent(action: String, path: String = ""): PendingIntent {
val intent = Intent(context, InstallOnReceived::class.java).apply {
this.action = action
putExtra(InstallOnReceived.FILE_LOCATION, path)
}
return PendingIntent.getBroadcast(context, 0, intent, 0)
}
/**
* BroadcastEvent used to install apk or retry download
*/
class InstallOnReceived : BroadcastReceiver() {
companion object {
// Install apk action
const val INSTALL_APK = "eu.kanade.INSTALL_APK"
// Retry download action
const val RETRY_DOWNLOAD = "eu.kanade.RETRY_DOWNLOAD"
// Retry download action
const val CANCEL_NOTIFICATION = "eu.kanade.CANCEL_NOTIFICATION"
// Absolute path of file || URL of file
const val FILE_LOCATION = "file_location"
}
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
// Install apk.
INSTALL_APK -> UpdateDownloader.installAPK(context, File(intent.getStringExtra(FILE_LOCATION)))
// Retry download.
RETRY_DOWNLOAD -> UpdateDownloader(context).execute(intent.getStringExtra(FILE_LOCATION))
CANCEL_NOTIFICATION -> context.notificationManager.cancel(Constants.NOTIFICATION_UPDATER_ID)
}
}
}
}

View File

@ -1,110 +0,0 @@
package eu.kanade.tachiyomi.data.updater
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.SystemClock
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.util.DeviceUtil
import eu.kanade.tachiyomi.util.alarmManager
import eu.kanade.tachiyomi.util.notification
import eu.kanade.tachiyomi.util.notificationManager
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
class UpdateDownloaderAlarm : BroadcastReceiver() {
companion object {
const val CHECK_UPDATE_ACTION = "eu.kanade.CHECK_UPDATE"
/**
* Sets the alarm to run the intent that checks for update
* @param context the application context.
* @param intervalInHours the time in hours when it will be executed.
*/
fun startAlarm(context: Context, intervalInHours: Int = 12,
isEnabled: Boolean = Injekt.get<PreferencesHelper>().automaticUpdateStatus()) {
// Stop previous running alarms if needed, and do not restart it if the interval is 0.
UpdateDownloaderAlarm.stopAlarm(context)
if (intervalInHours == 0 || !isEnabled)
return
// Get the time the alarm should fire the event to update.
val intervalInMillis = intervalInHours * 60 * 60 * 1000
val nextRun = SystemClock.elapsedRealtime() + intervalInMillis
// Start the alarm.
val pendingIntent = getPendingIntent(context)
context.alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
nextRun, intervalInMillis.toLong(), pendingIntent)
}
/**
* Stops the alarm if it's running.
* @param context the application context.
*/
fun stopAlarm(context: Context) {
val pendingIntent = getPendingIntent(context)
context.alarmManager.cancel(pendingIntent)
}
/**
* Returns broadcast intent
* @param context the application context.
* @return broadcast intent
*/
fun getPendingIntent(context: Context): PendingIntent {
return PendingIntent.getBroadcast(context, 0,
Intent(context, UpdateDownloaderAlarm::class.java).apply {
this.action = CHECK_UPDATE_ACTION
}, PendingIntent.FLAG_UPDATE_CURRENT)
}
}
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
// Start the alarm when the system is booted.
Intent.ACTION_BOOT_COMPLETED -> startAlarm(context)
// Update the library when the alarm fires an event.
CHECK_UPDATE_ACTION -> checkVersion(context)
}
}
fun checkVersion(context: Context) {
if (DeviceUtil.isNetworkConnected(context)) {
val updateChecker = GithubUpdateChecker(context)
updateChecker.checkForApplicationUpdate()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ release ->
//Get version of latest release
var newVersion = release.version
newVersion = newVersion.replace("[^\\d.]".toRegex(), "")
//Check if latest version is different from current version
if (newVersion != BuildConfig.VERSION_NAME) {
val downloadLink = release.downloadLink
val n = context.notification() {
setContentTitle(context.getString(R.string.update_check_notification_update_available))
addAction(android.R.drawable.stat_sys_download_done, context.getString(eu.kanade.tachiyomi.R.string.action_download),
UpdateDownloader(context).getInstallOnReceivedIntent(UpdateDownloader.InstallOnReceived.RETRY_DOWNLOAD, downloadLink))
setSmallIcon(android.R.drawable.stat_sys_download_done)
}
// Displays the progress bar on notification
context.notificationManager.notify(0, n);
}
}, {
it.printStackTrace()
})
}
}
}

View File

@ -0,0 +1,149 @@
package eu.kanade.tachiyomi.data.updater
import android.app.IntentService
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.support.v4.app.NotificationCompat
import eu.kanade.tachiyomi.Constants.NOTIFICATION_UPDATER_ID
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.network.GET
import eu.kanade.tachiyomi.data.network.NetworkHelper
import eu.kanade.tachiyomi.data.network.ProgressListener
import eu.kanade.tachiyomi.data.network.newCallWithProgress
import eu.kanade.tachiyomi.util.notificationManager
import eu.kanade.tachiyomi.util.saveTo
import timber.log.Timber
import uy.kohesive.injekt.injectLazy
import java.io.File
class UpdateDownloaderService : IntentService(UpdateDownloaderService::class.java.name) {
companion object {
/**
* Download url.
*/
const val EXTRA_DOWNLOAD_URL = "eu.kanade.APP_DOWNLOAD_URL"
/**
* Downloads a new update and let the user install the new version from a notification.
* @param context the application context.
* @param url the url to the new update.
*/
fun downloadUpdate(context: Context, url: String) {
val intent = Intent(context, UpdateDownloaderService::class.java).apply {
putExtra(EXTRA_DOWNLOAD_URL, url)
}
context.startService(intent)
}
/**
* Prompt user with apk install intent
* @param context context
* @param file file of apk that is installed
*/
fun installAPK(context: Context, file: File) {
// Prompt install interface
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive")
// Without this flag android returned a intent error!
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
context.startActivity(intent)
}
}
/**
* Network helper
*/
private val network: NetworkHelper by injectLazy()
override fun onHandleIntent(intent: Intent?) {
if (intent == null) return
val url = intent.getStringExtra(EXTRA_DOWNLOAD_URL) ?: return
downloadApk(url)
}
fun downloadApk(url: String) {
val progressNotification = NotificationCompat.Builder(this)
progressNotification.update {
setContentTitle(getString(R.string.app_name))
setContentText(getString(R.string.update_check_notification_download_in_progress))
setSmallIcon(android.R.drawable.stat_sys_download)
setOngoing(true)
}
// Progress of the download
var savedProgress = 0
val progressListener = object : ProgressListener {
override fun update(bytesRead: Long, contentLength: Long, done: Boolean) {
val progress = (100 * bytesRead / contentLength).toInt()
if (progress > savedProgress) {
savedProgress = progress
progressNotification.update { setProgress(100, progress, false) }
}
}
}
// Reference the context for later usage inside apply blocks.
val ctx = this
try {
// Download the new update.
val response = network.client.newCallWithProgress(GET(url), progressListener).execute()
// File where the apk will be saved
val apkFile = File(externalCacheDir, "update.apk")
if (response.isSuccessful) {
response.body().source().saveTo(apkFile)
} else {
response.close()
throw Exception("Unsuccessful response")
}
// Prompt the user to install the new update.
NotificationCompat.Builder(this).update {
setContentTitle(getString(R.string.app_name))
setContentText(getString(R.string.update_check_notification_download_complete))
setSmallIcon(android.R.drawable.stat_sys_download_done)
// Install action
addAction(R.drawable.ic_system_update_grey_24dp_img,
getString(R.string.action_install),
UpdateNotificationReceiver.installApkIntent(ctx, apkFile.absolutePath))
// Cancel action
addAction(R.drawable.ic_clear_grey_24dp_img,
getString(R.string.action_cancel),
UpdateNotificationReceiver.cancelNotificationIntent(ctx))
}
} catch (e: Exception) {
Timber.e(e, e.message)
// Prompt the user to retry the download.
NotificationCompat.Builder(this).update {
setContentTitle(getString(R.string.app_name))
setContentText(getString(R.string.update_check_notification_download_error))
setSmallIcon(android.R.drawable.stat_sys_download_done)
// Retry action
addAction(R.drawable.ic_refresh_grey_24dp_img,
getString(R.string.action_retry),
UpdateNotificationReceiver.downloadApkIntent(ctx, url))
// Cancel action
addAction(R.drawable.ic_clear_grey_24dp_img,
getString(R.string.action_cancel),
UpdateNotificationReceiver.cancelNotificationIntent(ctx))
}
}
}
fun NotificationCompat.Builder.update(block: NotificationCompat.Builder.() -> Unit) {
block()
notificationManager.notify(NOTIFICATION_UPDATER_ID, build())
}
}

View File

@ -0,0 +1,67 @@
package eu.kanade.tachiyomi.data.updater
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import eu.kanade.tachiyomi.Constants.NOTIFICATION_UPDATER_ID
import eu.kanade.tachiyomi.util.notificationManager
import java.io.File
class UpdateNotificationReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
ACTION_INSTALL_APK -> {
UpdateDownloaderService.installAPK(context,
File(intent.getStringExtra(EXTRA_FILE_LOCATION)))
cancelNotification(context)
}
ACTION_DOWNLOAD_UPDATE -> UpdateDownloaderService.downloadUpdate(context,
intent.getStringExtra(UpdateDownloaderService.EXTRA_DOWNLOAD_URL))
ACTION_CANCEL_NOTIFICATION -> cancelNotification(context)
}
}
fun cancelNotification(context: Context) {
context.notificationManager.cancel(NOTIFICATION_UPDATER_ID)
}
companion object {
// Install apk action
const val ACTION_INSTALL_APK = "eu.kanade.INSTALL_APK"
// Download apk action
const val ACTION_DOWNLOAD_UPDATE = "eu.kanade.RETRY_DOWNLOAD"
// Cancel notification action
const val ACTION_CANCEL_NOTIFICATION = "eu.kanade.CANCEL_NOTIFICATION"
// Absolute path of apk file
const val EXTRA_FILE_LOCATION = "file_location"
fun cancelNotificationIntent(context: Context): PendingIntent {
val intent = Intent(context, UpdateNotificationReceiver::class.java).apply {
action = ACTION_CANCEL_NOTIFICATION
}
return PendingIntent.getBroadcast(context, 0, intent, 0)
}
fun installApkIntent(context: Context, path: String): PendingIntent {
val intent = Intent(context, UpdateNotificationReceiver::class.java).apply {
action = ACTION_INSTALL_APK
putExtra(EXTRA_FILE_LOCATION, path)
}
return PendingIntent.getBroadcast(context, 0, intent, 0)
}
fun downloadApkIntent(context: Context, url: String): PendingIntent {
val intent = Intent(context, UpdateNotificationReceiver::class.java).apply {
action = ACTION_DOWNLOAD_UPDATE
putExtra(UpdateDownloaderService.EXTRA_DOWNLOAD_URL, url)
}
return PendingIntent.getBroadcast(context, 0, intent, 0)
}
}
}

View File

@ -1,18 +1,21 @@
package eu.kanade.tachiyomi.ui.setting package eu.kanade.tachiyomi.ui.setting
import android.os.Bundle import android.os.Bundle
import android.support.v7.preference.SwitchPreferenceCompat
import android.support.v7.preference.XpPreferenceFragment import android.support.v7.preference.XpPreferenceFragment
import android.view.View import android.view.View
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.updater.GithubUpdateChecker import eu.kanade.tachiyomi.data.updater.GithubUpdateChecker
import eu.kanade.tachiyomi.data.updater.UpdateDownloader import eu.kanade.tachiyomi.data.updater.GithubUpdateResult
import eu.kanade.tachiyomi.data.updater.UpdateCheckerService
import eu.kanade.tachiyomi.data.updater.UpdateDownloaderService
import eu.kanade.tachiyomi.util.toast import eu.kanade.tachiyomi.util.toast
import net.xpece.android.support.preference.SwitchPreference
import rx.Subscription import rx.Subscription
import rx.android.schedulers.AndroidSchedulers import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers import rx.schedulers.Schedulers
import timber.log.Timber
import java.text.DateFormat import java.text.DateFormat
import java.text.ParseException import java.text.ParseException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
@ -22,15 +25,15 @@ class SettingsAboutFragment : SettingsFragment() {
/** /**
* Checks for new releases * Checks for new releases
*/ */
private val updateChecker by lazy { GithubUpdateChecker(activity) } private val updateChecker by lazy { GithubUpdateChecker() }
/** /**
* The subscribtion service of the obtained release object * The subscribtion service of the obtained release object
*/ */
private var releaseSubscription: Subscription? = null private var releaseSubscription: Subscription? = null
val automaticUpdateToggle by lazy { val automaticUpdates by lazy {
findPreference(getString(R.string.pref_enable_automatic_updates_key)) as SwitchPreferenceCompat findPreference(getString(R.string.pref_enable_automatic_updates_key)) as SwitchPreference
} }
companion object { companion object {
@ -59,13 +62,17 @@ class SettingsAboutFragment : SettingsFragment() {
true true
} }
//TODO One glorious day enable this and add the magnificent option for auto update checking. automaticUpdates.setOnPreferenceChangeListener { preference, any ->
// automaticUpdateToggle.isEnabled = true val checked = any as Boolean
// automaticUpdateToggle.setOnPreferenceChangeListener { preference, any -> if (checked) {
// val status = any as Boolean UpdateCheckerService.setupTask(context)
// UpdateDownloaderAlarm.startAlarm(activity, 12, status) } else {
// true UpdateCheckerService.cancelTask(context)
// } }
true
}
} else {
automaticUpdates.isVisible = false
} }
buildTime.summary = getFormattedBuildTime() buildTime.summary = getFormattedBuildTime()
@ -98,36 +105,35 @@ class SettingsAboutFragment : SettingsFragment() {
private fun checkVersion() { private fun checkVersion() {
releaseSubscription?.unsubscribe() releaseSubscription?.unsubscribe()
releaseSubscription = updateChecker.checkForApplicationUpdate() context.toast(R.string.update_check_look_for_updates)
releaseSubscription = updateChecker.checkForUpdate()
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ release -> .subscribe({ result ->
//Get version of latest release when (result) {
var newVersion = release.version is GithubUpdateResult.NewUpdate -> {
newVersion = newVersion.replace("[^\\d.]".toRegex(), "") val body = result.release.changeLog
val url = result.release.downloadLink
//Check if latest version is different from current version
if (newVersion != BuildConfig.VERSION_NAME) {
val downloadLink = release.downloadLink
val body = release.changeLog
// Create confirmation window // Create confirmation window
MaterialDialog.Builder(activity) MaterialDialog.Builder(context)
.title(R.string.update_check_title) .title(R.string.update_check_title)
.content(body) .content(body)
.positiveText(getString(R.string.update_check_confirm)) .positiveText(getString(R.string.update_check_confirm))
.negativeText(getString(R.string.update_check_ignore)) .negativeText(getString(R.string.update_check_ignore))
.onPositive { dialog, which -> .onPositive { dialog, which ->
// User output that download has started
activity.toast(R.string.update_check_download_started)
// Start download // Start download
UpdateDownloader(activity.applicationContext).execute(downloadLink) UpdateDownloaderService.downloadUpdate(context, url)
}.show()
} else {
activity.toast(R.string.update_check_no_new_updates)
} }
}, { .show()
it.printStackTrace() }
is GithubUpdateResult.NoNewUpdate -> {
context.toast(R.string.update_check_no_new_updates)
}
}
}, { error ->
Timber.e(error, error.message)
}) })
} }

View File

@ -12,12 +12,11 @@
android:summary="@string/pref_acra_summary" android:summary="@string/pref_acra_summary"
android:title="@string/pref_enable_acra"/> android:title="@string/pref_enable_acra"/>
<!--<SwitchPreferenceCompat--> <SwitchPreference
<!--android:defaultValue="false"--> android:defaultValue="false"
<!--android:enabled="false"--> android:key="@string/pref_enable_automatic_updates_key"
<!--android:key="@string/pref_enable_automatic_updates_key"--> android:summary="@string/pref_enable_automatic_updates_summary"
<!--android:summary="@string/pref_enable_automatic_updates_summary"--> android:title="@string/pref_enable_automatic_updates"/>
<!--android:title="@string/pref_enable_automatic_updates"/>-->
<Preference <Preference
android:key="@string/pref_version" android:key="@string/pref_version"