mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 06:17:57 +01:00 
			
		
		
		
	Remove local broadcast receiver to prevent race conditions (#1123)
* Remove local broadcast receiver to prevent run exceptions. Added option to set tile for extension update.
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							6a63ce992a
						
					
				
				
					commit
					8994b42760
				
			| @@ -8,7 +8,7 @@ import com.evernote.android.job.JobManager | ||||
| import eu.kanade.tachiyomi.data.backup.BackupCreatorJob | ||||
| import eu.kanade.tachiyomi.data.library.LibraryUpdateJob | ||||
| import eu.kanade.tachiyomi.data.notification.Notifications | ||||
| import eu.kanade.tachiyomi.data.updater.UpdateCheckerJob | ||||
| import eu.kanade.tachiyomi.data.updater.UpdaterJob | ||||
| import eu.kanade.tachiyomi.util.LocaleHelper | ||||
| import org.acra.ACRA | ||||
| import org.acra.annotation.ReportsCrashes | ||||
| @@ -60,7 +60,7 @@ open class App : Application() { | ||||
|         JobManager.create(this).addJobCreator { tag -> | ||||
|             when (tag) { | ||||
|                 LibraryUpdateJob.TAG -> LibraryUpdateJob() | ||||
|                 UpdateCheckerJob.TAG -> UpdateCheckerJob() | ||||
|                 UpdaterJob.TAG -> UpdaterJob() | ||||
|                 BackupCreatorJob.TAG -> BackupCreatorJob() | ||||
|                 else -> null | ||||
|             } | ||||
|   | ||||
| @@ -3,7 +3,7 @@ package eu.kanade.tachiyomi | ||||
| import eu.kanade.tachiyomi.data.library.LibraryUpdateJob | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.data.preference.getOrDefault | ||||
| import eu.kanade.tachiyomi.data.updater.UpdateCheckerJob | ||||
| import eu.kanade.tachiyomi.data.updater.UpdaterJob | ||||
| import java.io.File | ||||
|  | ||||
| object Migrations { | ||||
| @@ -25,7 +25,7 @@ object Migrations { | ||||
|             if (oldVersion < 14) { | ||||
|                 // Restore jobs after upgrading to evernote's job scheduler. | ||||
|                 if (BuildConfig.INCLUDE_UPDATER && preferences.automaticUpdates()) { | ||||
|                     UpdateCheckerJob.setupTask() | ||||
|                     UpdaterJob.setupTask() | ||||
|                 } | ||||
|                 LibraryUpdateJob.setupTask() | ||||
|             } | ||||
|   | ||||
| @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.data.notification | ||||
| import android.app.PendingIntent | ||||
| import android.content.Context | ||||
| import android.content.Intent | ||||
| import android.net.Uri | ||||
| import eu.kanade.tachiyomi.ui.main.MainActivity | ||||
| import eu.kanade.tachiyomi.util.getUriCompat | ||||
| import java.io.File | ||||
| @@ -43,11 +44,10 @@ object NotificationHandler { | ||||
|      * Returns [PendingIntent] that prompts user with apk install intent | ||||
|      * | ||||
|      * @param context context | ||||
|      * @param file file of apk that is installed | ||||
|      * @param uri uri of apk that is installed | ||||
|      */ | ||||
|     fun installApkPendingActivity(context: Context, file: File): PendingIntent { | ||||
|     fun installApkPendingActivity(context: Context, uri: Uri): PendingIntent { | ||||
|         val intent = Intent(Intent.ACTION_VIEW).apply { | ||||
|             val uri = file.getUriCompat(context) | ||||
|             setDataAndType(uri, "application/vnd.android.package-archive") | ||||
|             flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_GRANT_READ_URI_PERMISSION | ||||
|         } | ||||
|   | ||||
| @@ -11,8 +11,8 @@ import com.google.gson.annotations.SerializedName | ||||
|  * @param assets assets of latest release. | ||||
|  */ | ||||
| class GithubRelease(@SerializedName("tag_name") val version: String, | ||||
|         @SerializedName("body") val changeLog: String, | ||||
|         @SerializedName("assets") val assets: List<Assets>) { | ||||
|                     @SerializedName("body") val changeLog: String, | ||||
|                     @SerializedName("assets") private val assets: List<Assets>) { | ||||
|  | ||||
|     /** | ||||
|      * Get download link of latest release from the assets. | ||||
|   | ||||
| @@ -3,7 +3,7 @@ package eu.kanade.tachiyomi.data.updater | ||||
| import eu.kanade.tachiyomi.BuildConfig | ||||
| import rx.Observable | ||||
|  | ||||
| class GithubUpdateChecker() { | ||||
| class GithubUpdateChecker { | ||||
|  | ||||
|     private val service: GithubService = GithubService.create() | ||||
|  | ||||
|   | ||||
| @@ -3,5 +3,5 @@ package eu.kanade.tachiyomi.data.updater | ||||
| sealed class GithubUpdateResult { | ||||
|  | ||||
|     class NewUpdate(val release: GithubRelease): GithubUpdateResult() | ||||
|     class NoNewUpdate(): GithubUpdateResult() | ||||
|     class NoNewUpdate : GithubUpdateResult() | ||||
| } | ||||
| @@ -1,147 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.data.updater | ||||
|  | ||||
| import android.content.BroadcastReceiver | ||||
| import android.content.Context | ||||
| import android.content.Intent | ||||
| import android.support.v4.app.NotificationCompat | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.notification.NotificationHandler | ||||
| import eu.kanade.tachiyomi.data.notification.NotificationReceiver | ||||
| import eu.kanade.tachiyomi.data.notification.Notifications | ||||
| import eu.kanade.tachiyomi.util.notificationManager | ||||
| import java.io.File | ||||
| import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID | ||||
|  | ||||
| /** | ||||
|  * Local [BroadcastReceiver] that runs on UI thread | ||||
|  * Notification calls from [UpdateDownloaderService] should be made from here. | ||||
|  */ | ||||
| internal class UpdateDownloaderReceiver(val context: Context) : BroadcastReceiver() { | ||||
|  | ||||
|     companion object { | ||||
|         private const val NAME = "UpdateDownloaderReceiver" | ||||
|  | ||||
|         // Called to show initial notification. | ||||
|         internal const val NOTIFICATION_UPDATER_INITIAL = "$ID.$NAME.UPDATER_INITIAL" | ||||
|  | ||||
|         // Called to show progress notification. | ||||
|         internal const val NOTIFICATION_UPDATER_PROGRESS = "$ID.$NAME.UPDATER_PROGRESS" | ||||
|  | ||||
|         // Called to show install notification. | ||||
|         internal const val NOTIFICATION_UPDATER_INSTALL = "$ID.$NAME.UPDATER_INSTALL" | ||||
|  | ||||
|         // Called to show error notification | ||||
|         internal const val NOTIFICATION_UPDATER_ERROR = "$ID.$NAME.UPDATER_ERROR" | ||||
|  | ||||
|         // Value containing action of BroadcastReceiver | ||||
|         internal const val EXTRA_ACTION = "$ID.$NAME.ACTION" | ||||
|  | ||||
|         // Value containing progress | ||||
|         internal const val EXTRA_PROGRESS = "$ID.$NAME.PROGRESS" | ||||
|  | ||||
|         // Value containing apk path | ||||
|         internal const val EXTRA_APK_PATH = "$ID.$NAME.APK_PATH" | ||||
|  | ||||
|         // Value containing apk url | ||||
|         internal const val EXTRA_APK_URL = "$ID.$NAME.APK_URL" | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Notification shown to user | ||||
|      */ | ||||
|     private val notification = NotificationCompat.Builder(context, Notifications.CHANNEL_COMMON) | ||||
|  | ||||
|     override fun onReceive(context: Context, intent: Intent) { | ||||
|         when (intent.getStringExtra(EXTRA_ACTION)) { | ||||
|             NOTIFICATION_UPDATER_INITIAL -> basicNotification() | ||||
|             NOTIFICATION_UPDATER_PROGRESS -> updateProgress(intent.getIntExtra(EXTRA_PROGRESS, 0)) | ||||
|             NOTIFICATION_UPDATER_INSTALL -> installNotification(intent.getStringExtra(EXTRA_APK_PATH)) | ||||
|             NOTIFICATION_UPDATER_ERROR -> errorNotification(intent.getStringExtra(EXTRA_APK_URL)) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Called to show basic notification | ||||
|      */ | ||||
|     private fun basicNotification() { | ||||
|         // Create notification | ||||
|         with(notification) { | ||||
|             setContentTitle(context.getString(R.string.app_name)) | ||||
|             setContentText(context.getString(R.string.update_check_notification_download_in_progress)) | ||||
|             setSmallIcon(android.R.drawable.stat_sys_download) | ||||
|             setOngoing(true) | ||||
|         } | ||||
|         notification.show() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Called to show progress notification | ||||
|      * | ||||
|      * @param progress progress of download | ||||
|      */ | ||||
|     private fun updateProgress(progress: Int) { | ||||
|         with(notification) { | ||||
|             setProgress(100, progress, false) | ||||
|             setOnlyAlertOnce(true) | ||||
|         } | ||||
|         notification.show() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Called to show install notification | ||||
|      * | ||||
|      * @param path path of file | ||||
|      */ | ||||
|     private fun installNotification(path: String) { | ||||
|         // Prompt the user to install the new update. | ||||
|         with(notification) { | ||||
|             setContentText(context.getString(R.string.update_check_notification_download_complete)) | ||||
|             setSmallIcon(android.R.drawable.stat_sys_download_done) | ||||
|             setOnlyAlertOnce(false) | ||||
|             setProgress(0, 0, false) | ||||
|             // Install action | ||||
|             setContentIntent(NotificationHandler.installApkPendingActivity(context, File(path))) | ||||
|             addAction(R.drawable.ic_system_update_grey_24dp_img, | ||||
|                     context.getString(R.string.action_install), | ||||
|                     NotificationHandler.installApkPendingActivity(context, File(path))) | ||||
|             // Cancel action | ||||
|             addAction(R.drawable.ic_clear_grey_24dp_img, | ||||
|                     context.getString(R.string.action_cancel), | ||||
|                     NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER)) | ||||
|         } | ||||
|         notification.show() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Called to show error notification | ||||
|      * | ||||
|      * @param url url of apk | ||||
|      */ | ||||
|     private fun errorNotification(url: String) { | ||||
|         // Prompt the user to retry the download. | ||||
|         with(notification) { | ||||
|             setContentText(context.getString(R.string.update_check_notification_download_error)) | ||||
|             setSmallIcon(android.R.drawable.stat_sys_warning) | ||||
|             setOnlyAlertOnce(false) | ||||
|             setProgress(0, 0, false) | ||||
|             // Retry action | ||||
|             addAction(R.drawable.ic_refresh_grey_24dp_img, | ||||
|                     context.getString(R.string.action_retry), | ||||
|                     UpdateDownloaderService.downloadApkPendingService(context, url)) | ||||
|             // Cancel action | ||||
|             addAction(R.drawable.ic_clear_grey_24dp_img, | ||||
|                     context.getString(R.string.action_cancel), | ||||
|                     NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER)) | ||||
|         } | ||||
|         notification.show() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Shows a notification from this builder. | ||||
|      * | ||||
|      * @param id the id of the notification. | ||||
|      */ | ||||
|     private fun NotificationCompat.Builder.show(id: Int = Notifications.ID_UPDATER) { | ||||
|         context.notificationManager.notify(id, build()) | ||||
|     } | ||||
| } | ||||
| @@ -1,67 +1,67 @@ | ||||
| package eu.kanade.tachiyomi.data.updater | ||||
| 
 | ||||
| import android.app.PendingIntent | ||||
| import android.content.Intent | ||||
| import android.support.v4.app.NotificationCompat | ||||
| import com.evernote.android.job.Job | ||||
| import com.evernote.android.job.JobManager | ||||
| import com.evernote.android.job.JobRequest | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.notification.Notifications | ||||
| import eu.kanade.tachiyomi.util.notificationManager | ||||
| 
 | ||||
| class UpdateCheckerJob : Job() { | ||||
| 
 | ||||
|     override fun onRunJob(params: Params): Result { | ||||
|         return GithubUpdateChecker() | ||||
|                 .checkForUpdate() | ||||
|                 .map { result -> | ||||
|                     if (result is GithubUpdateResult.NewUpdate) { | ||||
|                         val url = result.release.downloadLink | ||||
| 
 | ||||
|                         val intent = Intent(context, UpdateDownloaderService::class.java).apply { | ||||
|                             putExtra(UpdateDownloaderService.EXTRA_DOWNLOAD_URL, url) | ||||
|                         } | ||||
| 
 | ||||
|                         NotificationCompat.Builder(context, Notifications.CHANNEL_COMMON).update { | ||||
|                             setContentTitle(context.getString(R.string.app_name)) | ||||
|                             setContentText(context.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, | ||||
|                                     context.getString(R.string.action_download), | ||||
|                                     PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)) | ||||
|                         } | ||||
|                     } | ||||
|                     Job.Result.SUCCESS | ||||
|                 } | ||||
|                 .onErrorReturn { Job.Result.FAILURE } | ||||
|                 // Sadly, the task needs to be synchronous. | ||||
|                 .toBlocking() | ||||
|                 .single() | ||||
|     } | ||||
| 
 | ||||
|     fun NotificationCompat.Builder.update(block: NotificationCompat.Builder.() -> Unit) { | ||||
|         block() | ||||
|         context.notificationManager.notify(Notifications.ID_UPDATER, build()) | ||||
|     } | ||||
| 
 | ||||
|     companion object { | ||||
|         const val TAG = "UpdateChecker" | ||||
| 
 | ||||
|         fun setupTask() { | ||||
|             JobRequest.Builder(TAG) | ||||
|                     .setPeriodic(24 * 60 * 60 * 1000, 60 * 60 * 1000) | ||||
|                     .setRequiredNetworkType(JobRequest.NetworkType.CONNECTED) | ||||
|                     .setRequirementsEnforced(true) | ||||
|                     .setUpdateCurrent(true) | ||||
|                     .build() | ||||
|                     .schedule() | ||||
|         } | ||||
| 
 | ||||
|         fun cancelTask() { | ||||
|             JobManager.instance().cancelAllForTag(TAG) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| package eu.kanade.tachiyomi.data.updater | ||||
| 
 | ||||
| import android.app.PendingIntent | ||||
| import android.content.Intent | ||||
| import android.support.v4.app.NotificationCompat | ||||
| import com.evernote.android.job.Job | ||||
| import com.evernote.android.job.JobManager | ||||
| import com.evernote.android.job.JobRequest | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.notification.Notifications | ||||
| import eu.kanade.tachiyomi.util.notificationManager | ||||
| 
 | ||||
| class UpdaterJob : Job() { | ||||
| 
 | ||||
|     override fun onRunJob(params: Params): Result { | ||||
|         return GithubUpdateChecker() | ||||
|                 .checkForUpdate() | ||||
|                 .map { result -> | ||||
|                     if (result is GithubUpdateResult.NewUpdate) { | ||||
|                         val url = result.release.downloadLink | ||||
| 
 | ||||
|                         val intent = Intent(context, UpdaterService::class.java).apply { | ||||
|                             putExtra(UpdaterService.EXTRA_DOWNLOAD_URL, url) | ||||
|                         } | ||||
| 
 | ||||
|                         NotificationCompat.Builder(context, Notifications.CHANNEL_COMMON).update { | ||||
|                             setContentTitle(context.getString(R.string.app_name)) | ||||
|                             setContentText(context.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, | ||||
|                                     context.getString(R.string.action_download), | ||||
|                                     PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)) | ||||
|                         } | ||||
|                     } | ||||
|                     Job.Result.SUCCESS | ||||
|                 } | ||||
|                 .onErrorReturn { Job.Result.FAILURE } | ||||
|                 // Sadly, the task needs to be synchronous. | ||||
|                 .toBlocking() | ||||
|                 .single() | ||||
|     } | ||||
| 
 | ||||
|     fun NotificationCompat.Builder.update(block: NotificationCompat.Builder.() -> Unit) { | ||||
|         block() | ||||
|         context.notificationManager.notify(Notifications.ID_UPDATER, build()) | ||||
|     } | ||||
| 
 | ||||
|     companion object { | ||||
|         const val TAG = "UpdateChecker" | ||||
| 
 | ||||
|         fun setupTask() { | ||||
|             JobRequest.Builder(TAG) | ||||
|                     .setPeriodic(24 * 60 * 60 * 1000, 60 * 60 * 1000) | ||||
|                     .setRequiredNetworkType(JobRequest.NetworkType.CONNECTED) | ||||
|                     .setRequirementsEnforced(true) | ||||
|                     .setUpdateCurrent(true) | ||||
|                     .build() | ||||
|                     .schedule() | ||||
|         } | ||||
| 
 | ||||
|         fun cancelTask() { | ||||
|             JobManager.instance().cancelAllForTag(TAG) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @@ -0,0 +1,109 @@ | ||||
| package eu.kanade.tachiyomi.data.updater | ||||
|  | ||||
| import android.content.Context | ||||
| import android.net.Uri | ||||
| import android.support.v4.app.NotificationCompat | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.notification.NotificationHandler | ||||
| import eu.kanade.tachiyomi.data.notification.NotificationReceiver | ||||
| import eu.kanade.tachiyomi.data.notification.Notifications | ||||
| import eu.kanade.tachiyomi.util.notificationManager | ||||
|  | ||||
| /** | ||||
|  * DownloadNotifier is used to show notifications when downloading and update. | ||||
|  * | ||||
|  * @param context context of application. | ||||
|  */ | ||||
| internal class UpdaterNotifier(private val context: Context) { | ||||
|  | ||||
|     /** | ||||
|      * Builder to manage notifications. | ||||
|      */ | ||||
|     private val notification by lazy { | ||||
|         NotificationCompat.Builder(context, Notifications.CHANNEL_COMMON) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Call to show notification. | ||||
|      * | ||||
|      * @param id id of the notification channel. | ||||
|      */ | ||||
|     private fun NotificationCompat.Builder.show(id: Int = Notifications.ID_UPDATER) { | ||||
|         context.notificationManager.notify(id, build()) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Call when apk download starts. | ||||
|      * | ||||
|      * @param title tile of notification. | ||||
|      */ | ||||
|     fun onDownloadStarted(title: String) { | ||||
|         with(notification) { | ||||
|             setContentTitle(title) | ||||
|             setContentText(context.getString(R.string.update_check_notification_download_in_progress)) | ||||
|             setSmallIcon(android.R.drawable.stat_sys_download) | ||||
|             setOngoing(true) | ||||
|         } | ||||
|         notification.show() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Call when apk download progress changes. | ||||
|      * | ||||
|      * @param progress progress of download (xx%/100). | ||||
|      */ | ||||
|     fun onProgressChange(progress: Int) { | ||||
|         with(notification) { | ||||
|             setProgress(100, progress, false) | ||||
|             setOnlyAlertOnce(true) | ||||
|         } | ||||
|         notification.show() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Call when apk download is finished. | ||||
|      * | ||||
|      * @param uri path location of apk. | ||||
|      */ | ||||
|     fun onDownloadFinished(uri: Uri) { | ||||
|         with(notification) { | ||||
|             setContentText(context.getString(R.string.update_check_notification_download_complete)) | ||||
|             setSmallIcon(android.R.drawable.stat_sys_download_done) | ||||
|             setOnlyAlertOnce(false) | ||||
|             setProgress(0, 0, false) | ||||
|             // Install action | ||||
|             setContentIntent(NotificationHandler.installApkPendingActivity(context, uri)) | ||||
|             addAction(R.drawable.ic_system_update_grey_24dp_img, | ||||
|                     context.getString(R.string.action_install), | ||||
|                     NotificationHandler.installApkPendingActivity(context, uri)) | ||||
|             // Cancel action | ||||
|             addAction(R.drawable.ic_clear_grey_24dp_img, | ||||
|                     context.getString(R.string.action_cancel), | ||||
|                     NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER)) | ||||
|         } | ||||
|         notification.show() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Call when apk download throws a error | ||||
|      * | ||||
|      * @param url web location of apk to download. | ||||
|      */ | ||||
|     fun onDownloadError(url: String) { | ||||
|         with(notification) { | ||||
|             setContentText(context.getString(R.string.update_check_notification_download_error)) | ||||
|             setSmallIcon(android.R.drawable.stat_sys_warning) | ||||
|             setOnlyAlertOnce(false) | ||||
|             setProgress(0, 0, false) | ||||
|             // Retry action | ||||
|             addAction(R.drawable.ic_refresh_grey_24dp_img, | ||||
|                     context.getString(R.string.action_retry), | ||||
|                     UpdaterService.downloadApkPendingService(context, url)) | ||||
|             // Cancel action | ||||
|             addAction(R.drawable.ic_clear_grey_24dp_img, | ||||
|                     context.getString(R.string.action_cancel), | ||||
|                     NotificationReceiver.dismissNotificationPendingBroadcast(context, Notifications.ID_UPDATER)) | ||||
|         } | ||||
|         notification.show(Notifications.ID_UPDATER) | ||||
|     } | ||||
| } | ||||
| @@ -2,52 +2,37 @@ package eu.kanade.tachiyomi.data.updater | ||||
| 
 | ||||
| import android.app.IntentService | ||||
| import android.app.PendingIntent | ||||
| import android.content.BroadcastReceiver | ||||
| import android.content.Context | ||||
| import android.content.Intent | ||||
| import android.content.IntentFilter | ||||
| import eu.kanade.tachiyomi.BuildConfig | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.network.GET | ||||
| import eu.kanade.tachiyomi.network.NetworkHelper | ||||
| import eu.kanade.tachiyomi.network.ProgressListener | ||||
| import eu.kanade.tachiyomi.network.newCallWithProgress | ||||
| import eu.kanade.tachiyomi.util.registerLocalReceiver | ||||
| import eu.kanade.tachiyomi.util.getUriCompat | ||||
| import eu.kanade.tachiyomi.util.saveTo | ||||
| import eu.kanade.tachiyomi.util.sendLocalBroadcastSync | ||||
| import eu.kanade.tachiyomi.util.unregisterLocalReceiver | ||||
| import timber.log.Timber | ||||
| import uy.kohesive.injekt.injectLazy | ||||
| import java.io.File | ||||
| 
 | ||||
| class UpdateDownloaderService : IntentService(UpdateDownloaderService::class.java.name) { | ||||
| class UpdaterService : IntentService(UpdaterService::class.java.name) { | ||||
|     /** | ||||
|      * Network helper | ||||
|      */ | ||||
|     private val network: NetworkHelper by injectLazy() | ||||
| 
 | ||||
|     /** | ||||
|      * Local [BroadcastReceiver] that runs on UI thread | ||||
|      * Notifier for the updater state and progress. | ||||
|      */ | ||||
|     private val updaterNotificationReceiver = UpdateDownloaderReceiver(this) | ||||
| 
 | ||||
| 
 | ||||
|     override fun onCreate() { | ||||
|         super.onCreate() | ||||
|         // Register receiver | ||||
|         registerLocalReceiver(updaterNotificationReceiver, IntentFilter(INTENT_FILTER_NAME)) | ||||
|     } | ||||
| 
 | ||||
|     override fun onDestroy() { | ||||
|         // Unregister receiver | ||||
|         unregisterLocalReceiver(updaterNotificationReceiver) | ||||
|         super.onDestroy() | ||||
|     } | ||||
|     private val notifier by lazy { UpdaterNotifier(this) } | ||||
| 
 | ||||
|     override fun onHandleIntent(intent: Intent?) { | ||||
|         if (intent == null) return | ||||
| 
 | ||||
|         val title = intent.getStringExtra(EXTRA_DOWNLOAD_TITLE) ?: getString(R.string.app_name) | ||||
|         val url = intent.getStringExtra(EXTRA_DOWNLOAD_URL) ?: return | ||||
|         downloadApk(url) | ||||
|         downloadApk(title, url) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @@ -55,9 +40,9 @@ class UpdateDownloaderService : IntentService(UpdateDownloaderService::class.jav | ||||
|      * | ||||
|      * @param url url location of file | ||||
|      */ | ||||
|     fun downloadApk(url: String) { | ||||
|     private fun downloadApk(title: String, url: String) { | ||||
|         // Show notification download starting. | ||||
|         sendInitialBroadcast() | ||||
|         notifier.onDownloadStarted(title) | ||||
| 
 | ||||
|         val progressListener = object : ProgressListener { | ||||
| 
 | ||||
| @@ -73,7 +58,7 @@ class UpdateDownloaderService : IntentService(UpdateDownloaderService::class.jav | ||||
|                 if (progress > savedProgress && currentTime - 200 > lastTick) { | ||||
|                     savedProgress = progress | ||||
|                     lastTick = currentTime | ||||
|                     sendProgressBroadcast(progress) | ||||
|                     notifier.onProgressChange(progress) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| @@ -91,80 +76,32 @@ class UpdateDownloaderService : IntentService(UpdateDownloaderService::class.jav | ||||
|                 response.close() | ||||
|                 throw Exception("Unsuccessful response") | ||||
|             } | ||||
|             sendInstallBroadcast(apkFile.absolutePath) | ||||
|             notifier.onDownloadFinished(apkFile.getUriCompat(this)) | ||||
|         } catch (error: Exception) { | ||||
|             Timber.e(error) | ||||
|             sendErrorBroadcast(url) | ||||
|             notifier.onDownloadError(url) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Show notification download starting. | ||||
|      */ | ||||
|     private fun sendInitialBroadcast() { | ||||
|         val intent = Intent(INTENT_FILTER_NAME).apply { | ||||
|             putExtra(UpdateDownloaderReceiver.EXTRA_ACTION, UpdateDownloaderReceiver.NOTIFICATION_UPDATER_INITIAL) | ||||
|         } | ||||
|         sendLocalBroadcastSync(intent) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Show notification progress changed | ||||
|      * | ||||
|      * @param progress progress of download | ||||
|      */ | ||||
|     private fun sendProgressBroadcast(progress: Int) { | ||||
|         val intent = Intent(INTENT_FILTER_NAME).apply { | ||||
|             putExtra(UpdateDownloaderReceiver.EXTRA_ACTION, UpdateDownloaderReceiver.NOTIFICATION_UPDATER_PROGRESS) | ||||
|             putExtra(UpdateDownloaderReceiver.EXTRA_PROGRESS, progress) | ||||
|         } | ||||
|         sendLocalBroadcastSync(intent) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Show install notification. | ||||
|      * | ||||
|      * @param path location of file | ||||
|      */ | ||||
|     private fun sendInstallBroadcast(path: String){ | ||||
|         val intent = Intent(INTENT_FILTER_NAME).apply { | ||||
|             putExtra(UpdateDownloaderReceiver.EXTRA_ACTION, UpdateDownloaderReceiver.NOTIFICATION_UPDATER_INSTALL) | ||||
|             putExtra(UpdateDownloaderReceiver.EXTRA_APK_PATH, path) | ||||
|         } | ||||
|         sendLocalBroadcastSync(intent) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Show error notification. | ||||
|      * | ||||
|      * @param url url of file | ||||
|      */ | ||||
|     private fun sendErrorBroadcast(url: String){ | ||||
|         val intent = Intent(INTENT_FILTER_NAME).apply { | ||||
|             putExtra(UpdateDownloaderReceiver.EXTRA_ACTION, UpdateDownloaderReceiver.NOTIFICATION_UPDATER_ERROR) | ||||
|             putExtra(UpdateDownloaderReceiver.EXTRA_APK_URL, url) | ||||
|         } | ||||
|         sendLocalBroadcastSync(intent) | ||||
|     } | ||||
| 
 | ||||
|     companion object { | ||||
|         /** | ||||
|          * Name of Local BroadCastReceiver. | ||||
|          */ | ||||
|         private val INTENT_FILTER_NAME = UpdateDownloaderService::class.java.name | ||||
| 
 | ||||
|         /** | ||||
|          * Download url. | ||||
|          */ | ||||
|         internal const val EXTRA_DOWNLOAD_URL = "${BuildConfig.APPLICATION_ID}.UpdateDownloaderService.DOWNLOAD_URL" | ||||
|         internal const val EXTRA_DOWNLOAD_URL = "${BuildConfig.APPLICATION_ID}.UpdaterService.DOWNLOAD_URL" | ||||
| 
 | ||||
|         /** | ||||
|          * Download title | ||||
|          */ | ||||
|         internal const val EXTRA_DOWNLOAD_TITLE = "${BuildConfig.APPLICATION_ID}.UpdaterService.DOWNLOAD_TITLE" | ||||
| 
 | ||||
|         /** | ||||
|          * 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 { | ||||
|         fun downloadUpdate(context: Context, url: String, title: String = context.getString(R.string.app_name)) { | ||||
|             val intent = Intent(context, UpdaterService::class.java).apply { | ||||
|                 putExtra(EXTRA_DOWNLOAD_TITLE, title) | ||||
|                 putExtra(EXTRA_DOWNLOAD_URL, url) | ||||
|             } | ||||
|             context.startService(intent) | ||||
| @@ -177,7 +114,7 @@ class UpdateDownloaderService : IntentService(UpdateDownloaderService::class.jav | ||||
|          * @return [PendingIntent] | ||||
|          */ | ||||
|         internal fun downloadApkPendingService(context: Context, url: String): PendingIntent { | ||||
|             val intent = Intent(context, UpdateDownloaderService::class.java).apply { | ||||
|             val intent = Intent(context, UpdaterService::class.java).apply { | ||||
|                 putExtra(EXTRA_DOWNLOAD_URL, url) | ||||
|             } | ||||
|             return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) | ||||
| @@ -11,8 +11,8 @@ import eu.kanade.tachiyomi.BuildConfig | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.updater.GithubUpdateChecker | ||||
| import eu.kanade.tachiyomi.data.updater.GithubUpdateResult | ||||
| import eu.kanade.tachiyomi.data.updater.UpdateCheckerJob | ||||
| import eu.kanade.tachiyomi.data.updater.UpdateDownloaderService | ||||
| import eu.kanade.tachiyomi.data.updater.UpdaterJob | ||||
| import eu.kanade.tachiyomi.data.updater.UpdaterService | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
| import eu.kanade.tachiyomi.util.toast | ||||
| import rx.Subscription | ||||
| @@ -59,9 +59,9 @@ class SettingsAboutController : SettingsController() { | ||||
|                 onChange { newValue -> | ||||
|                     val checked = newValue as Boolean | ||||
|                     if (checked) { | ||||
|                         UpdateCheckerJob.setupTask() | ||||
|                         UpdaterJob.setupTask() | ||||
|                     } else { | ||||
|                         UpdateCheckerJob.cancelTask() | ||||
|                         UpdaterJob.cancelTask() | ||||
|                     } | ||||
|                     true | ||||
|                 } | ||||
| @@ -148,7 +148,7 @@ class SettingsAboutController : SettingsController() { | ||||
|                         if (appContext != null) { | ||||
|                             // Start download | ||||
|                             val url = args.getString(URL_KEY) | ||||
|                             UpdateDownloaderService.downloadUpdate(appContext, url) | ||||
|                             UpdaterService.downloadUpdate(appContext, url) | ||||
|                         } | ||||
|                     } | ||||
|                     .build() | ||||
|   | ||||
| @@ -13,9 +13,8 @@ import java.io.File | ||||
|  * @param context context of application | ||||
|  */ | ||||
| fun File.getUriCompat(context: Context): Uri { | ||||
|     val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) | ||||
|     return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) | ||||
|         FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", this) | ||||
|     else Uri.fromFile(this) | ||||
|     return uri | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user