diff --git a/app/build.gradle b/app/build.gradle
index b178c3a6f..a60ef1f04 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -96,6 +96,8 @@ dependencies {
compile "com.android.support:support-annotations:$support_library_version"
compile "com.android.support:customtabs:$support_library_version"
+ compile 'com.google.android.gms:play-services-gcm:9.4.0'
+
// ReactiveX
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.1.8'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 503af4860..3c8f5400d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -59,6 +59,20 @@
+
+
+
+
+
+
+
+
+
+
@@ -79,10 +93,6 @@
android:name=".data.library.LibraryUpdateService$CancelUpdateReceiver">
-
-
-
@@ -91,15 +101,6 @@
-
-
-
-
-
-
-
-
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt
index 605e927e5..c575c96e9 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt
@@ -78,7 +78,7 @@ class PreferenceKeys(context: Context) {
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)
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
index 0707afdbb..d88f17e0c 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
@@ -130,6 +130,6 @@ class PreferencesHelper(context: Context) {
fun filterUnread() = rxPrefs.getBoolean(keys.filterUnread, false)
- fun automaticUpdateStatus() = prefs.getBoolean(keys.automaticUpdateStatus, false)
+ fun automaticUpdates() = prefs.getBoolean(keys.automaticUpdates, false)
}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubService.kt
index 7bce4082b..42ff97324 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubService.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubService.kt
@@ -6,7 +6,6 @@ import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import rx.Observable
-
/**
* Used to connect with the Github API.
*/
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubUpdateChecker.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubUpdateChecker.kt
index 306fab71b..8d6210845 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubUpdateChecker.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubUpdateChecker.kt
@@ -1,20 +1,25 @@
package eu.kanade.tachiyomi.data.updater
-import android.content.Context
-import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.util.toast
+import eu.kanade.tachiyomi.BuildConfig
import rx.Observable
+class GithubUpdateChecker() {
-class GithubUpdateChecker(private val context: Context) {
-
- val service: GithubService = GithubService.create()
+ private val service: GithubService = GithubService.create()
/**
* Returns observable containing release information
*/
- fun checkForApplicationUpdate(): Observable {
- context.toast(R.string.update_check_look_for_updates)
- return service.getLatestVersion()
+ fun checkForUpdate(): Observable {
+ return service.getLatestVersion().map { release ->
+ 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()
+ }
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubUpdateResult.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubUpdateResult.kt
new file mode 100644
index 000000000..a4a89a1c0
--- /dev/null
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/GithubUpdateResult.kt
@@ -0,0 +1,7 @@
+package eu.kanade.tachiyomi.data.updater
+
+sealed class GithubUpdateResult {
+
+ class NewUpdate(val release: GithubRelease): GithubUpdateResult()
+ class NoNewUpdate(): GithubUpdateResult()
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateCheckerService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateCheckerService.kt
new file mode 100644
index 000000000..7386fc580
--- /dev/null
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateCheckerService.kt
@@ -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)
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloader.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloader.kt
deleted file mode 100644
index 3dad020a7..000000000
--- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloader.kt
+++ /dev/null
@@ -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() {
-
- 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)
- }
- }
-
- }
-}
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloaderAlarm.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloaderAlarm.kt
deleted file mode 100644
index 66e01deb9..000000000
--- a/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloaderAlarm.kt
+++ /dev/null
@@ -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().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()
- })
- }
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloaderService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloaderService.kt
new file mode 100644
index 000000000..3cd50c152
--- /dev/null
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateDownloaderService.kt
@@ -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())
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateNotificationReceiver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateNotificationReceiver.kt
new file mode 100644
index 000000000..cb8716115
--- /dev/null
+++ b/app/src/main/java/eu/kanade/tachiyomi/data/updater/UpdateNotificationReceiver.kt
@@ -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)
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutFragment.kt
index 284995a36..7a7463478 100644
--- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutFragment.kt
+++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAboutFragment.kt
@@ -1,18 +1,21 @@
package eu.kanade.tachiyomi.ui.setting
import android.os.Bundle
-import android.support.v7.preference.SwitchPreferenceCompat
import android.support.v7.preference.XpPreferenceFragment
import android.view.View
import com.afollestad.materialdialogs.MaterialDialog
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R
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 net.xpece.android.support.preference.SwitchPreference
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
+import timber.log.Timber
import java.text.DateFormat
import java.text.ParseException
import java.text.SimpleDateFormat
@@ -22,15 +25,15 @@ class SettingsAboutFragment : SettingsFragment() {
/**
* 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
*/
private var releaseSubscription: Subscription? = null
- val automaticUpdateToggle by lazy {
- findPreference(getString(R.string.pref_enable_automatic_updates_key)) as SwitchPreferenceCompat
+ val automaticUpdates by lazy {
+ findPreference(getString(R.string.pref_enable_automatic_updates_key)) as SwitchPreference
}
companion object {
@@ -59,13 +62,17 @@ class SettingsAboutFragment : SettingsFragment() {
true
}
- //TODO One glorious day enable this and add the magnificent option for auto update checking.
- // automaticUpdateToggle.isEnabled = true
- // automaticUpdateToggle.setOnPreferenceChangeListener { preference, any ->
- // val status = any as Boolean
- // UpdateDownloaderAlarm.startAlarm(activity, 12, status)
- // true
- // }
+ automaticUpdates.setOnPreferenceChangeListener { preference, any ->
+ val checked = any as Boolean
+ if (checked) {
+ UpdateCheckerService.setupTask(context)
+ } else {
+ UpdateCheckerService.cancelTask(context)
+ }
+ true
+ }
+ } else {
+ automaticUpdates.isVisible = false
}
buildTime.summary = getFormattedBuildTime()
@@ -98,36 +105,35 @@ class SettingsAboutFragment : SettingsFragment() {
private fun checkVersion() {
releaseSubscription?.unsubscribe()
- releaseSubscription = updateChecker.checkForApplicationUpdate()
+ context.toast(R.string.update_check_look_for_updates)
+
+ releaseSubscription = updateChecker.checkForUpdate()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
- .subscribe({ release ->
- //Get version of latest release
- var newVersion = release.version
- newVersion = newVersion.replace("[^\\d.]".toRegex(), "")
+ .subscribe({ result ->
+ when (result) {
+ is GithubUpdateResult.NewUpdate -> {
+ 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
- MaterialDialog.Builder(activity)
- .title(R.string.update_check_title)
- .content(body)
- .positiveText(getString(R.string.update_check_confirm))
- .negativeText(getString(R.string.update_check_ignore))
- .onPositive { dialog, which ->
- // User output that download has started
- activity.toast(R.string.update_check_download_started)
- // Start download
- UpdateDownloader(activity.applicationContext).execute(downloadLink)
- }.show()
- } else {
- activity.toast(R.string.update_check_no_new_updates)
+ // Create confirmation window
+ MaterialDialog.Builder(context)
+ .title(R.string.update_check_title)
+ .content(body)
+ .positiveText(getString(R.string.update_check_confirm))
+ .negativeText(getString(R.string.update_check_ignore))
+ .onPositive { dialog, which ->
+ // Start download
+ UpdateDownloaderService.downloadUpdate(context, url)
+ }
+ .show()
+ }
+ is GithubUpdateResult.NoNewUpdate -> {
+ context.toast(R.string.update_check_no_new_updates)
+ }
}
- }, {
- it.printStackTrace()
+ }, { error ->
+ Timber.e(error, error.message)
})
}
diff --git a/app/src/main/res/xml/pref_about.xml b/app/src/main/res/xml/pref_about.xml
index b706570d5..e422ce039 100644
--- a/app/src/main/res/xml/pref_about.xml
+++ b/app/src/main/res/xml/pref_about.xml
@@ -12,12 +12,11 @@
android:summary="@string/pref_acra_summary"
android:title="@string/pref_enable_acra"/>
-
-
-
-
-
-
+