diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index edc1336552..f656c6fe05 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -181,10 +181,6 @@ android:name=".data.updater.AppUpdateService" android:exported="false" /> - - diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupManager.kt index de637c6e52..d23ce07309 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupManager.kt @@ -21,7 +21,7 @@ abstract class AbstractBackupManager(protected val context: Context) { internal val trackManager: TrackManager by injectLazy() protected val preferences: PreferencesHelper by injectLazy() - abstract fun createBackup(uri: Uri, flags: Int, isJob: Boolean): String + abstract fun createBackup(uri: Uri, flags: Int, isAutoBackup: Boolean): String /** * Returns manga diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt index d168e2c3d9..e185508d1d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt @@ -11,4 +11,15 @@ object BackupConst { const val BACKUP_TYPE_LEGACY = 0 const val BACKUP_TYPE_FULL = 1 + + // Filter options + internal const val BACKUP_CATEGORY = 0x1 + internal const val BACKUP_CATEGORY_MASK = 0x1 + internal const val BACKUP_CHAPTER = 0x2 + internal const val BACKUP_CHAPTER_MASK = 0x2 + internal const val BACKUP_HISTORY = 0x4 + internal const val BACKUP_HISTORY_MASK = 0x4 + internal const val BACKUP_TRACK = 0x8 + internal const val BACKUP_TRACK_MASK = 0x8 + internal const val BACKUP_ALL = 0xF } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateService.kt deleted file mode 100644 index 9a7dffcae1..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateService.kt +++ /dev/null @@ -1,114 +0,0 @@ -package eu.kanade.tachiyomi.data.backup - -import android.app.Service -import android.content.Context -import android.content.Intent -import android.net.Uri -import android.os.IBinder -import android.os.PowerManager -import androidx.core.content.ContextCompat -import androidx.core.net.toUri -import com.hippo.unifile.UniFile -import eu.kanade.tachiyomi.data.backup.full.FullBackupManager -import eu.kanade.tachiyomi.data.notification.Notifications -import eu.kanade.tachiyomi.util.system.acquireWakeLock -import eu.kanade.tachiyomi.util.system.isServiceRunning - -/** - * Service for backing up library information to a JSON file. - */ -class BackupCreateService : Service() { - - companion object { - // Filter options - internal const val BACKUP_CATEGORY = 0x1 - internal const val BACKUP_CATEGORY_MASK = 0x1 - internal const val BACKUP_CHAPTER = 0x2 - internal const val BACKUP_CHAPTER_MASK = 0x2 - internal const val BACKUP_HISTORY = 0x4 - internal const val BACKUP_HISTORY_MASK = 0x4 - internal const val BACKUP_TRACK = 0x8 - internal const val BACKUP_TRACK_MASK = 0x8 - internal const val BACKUP_ALL = 0xF - - /** - * Returns the status of the service. - * - * @param context the application context. - * @return true if the service is running, false otherwise. - */ - fun isRunning(context: Context): Boolean = - context.isServiceRunning(BackupCreateService::class.java) - - /** - * Make a backup from library - * - * @param context context of application - * @param uri path of Uri - * @param flags determines what to backup - */ - fun start(context: Context, uri: Uri, flags: Int) { - if (!isRunning(context)) { - val intent = Intent(context, BackupCreateService::class.java).apply { - putExtra(BackupConst.EXTRA_URI, uri) - putExtra(BackupConst.EXTRA_FLAGS, flags) - } - ContextCompat.startForegroundService(context, intent) - } - } - } - - /** - * Wake lock that will be held until the service is destroyed. - */ - private lateinit var wakeLock: PowerManager.WakeLock - - private lateinit var notifier: BackupNotifier - - override fun onCreate() { - super.onCreate() - - notifier = BackupNotifier(this) - wakeLock = acquireWakeLock(javaClass.name) - - startForeground(Notifications.ID_BACKUP_PROGRESS, notifier.showBackupProgress().build()) - } - - override fun stopService(name: Intent?): Boolean { - destroyJob() - return super.stopService(name) - } - - override fun onDestroy() { - destroyJob() - super.onDestroy() - } - - private fun destroyJob() { - if (wakeLock.isHeld) { - wakeLock.release() - } - } - - /** - * This method needs to be implemented, but it's not used/needed. - */ - override fun onBind(intent: Intent): IBinder? = null - - override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - if (intent == null) return START_NOT_STICKY - - try { - val uri = intent.getParcelableExtra(BackupConst.EXTRA_URI)!! - val backupFlags = intent.getIntExtra(BackupConst.EXTRA_FLAGS, 0) - val backupFileUri = FullBackupManager(this).createBackup(uri, backupFlags, false)?.toUri() - val unifile = UniFile.fromUri(this, backupFileUri) - notifier.showBackupComplete(unifile) - } catch (e: Exception) { - notifier.showBackupError(e.message) - } - - stopSelf(startId) - return START_NOT_STICKY - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt index bfaa407aad..6d6300df1a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt @@ -1,15 +1,23 @@ package eu.kanade.tachiyomi.data.backup import android.content.Context +import android.net.Uri import androidx.core.net.toUri import androidx.work.ExistingPeriodicWorkPolicy +import androidx.work.ExistingWorkPolicy +import androidx.work.OneTimeWorkRequestBuilder import androidx.work.PeriodicWorkRequestBuilder +import androidx.work.WorkInfo import androidx.work.WorkManager import androidx.work.Worker import androidx.work.WorkerParameters +import androidx.work.workDataOf +import com.hippo.unifile.UniFile import eu.kanade.tachiyomi.data.backup.full.FullBackupManager +import eu.kanade.tachiyomi.data.notification.Notifications import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.util.system.logcat +import eu.kanade.tachiyomi.util.system.notificationManager import logcat.LogPriority import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get @@ -20,23 +28,42 @@ class BackupCreatorJob(private val context: Context, workerParams: WorkerParamet override fun doWork(): Result { val preferences = Injekt.get() - val uri = preferences.backupsDirectory().get().toUri() - val flags = BackupCreateService.BACKUP_ALL + val notifier = BackupNotifier(context) + val uri = inputData.getString(LOCATION_URI_KEY)?.let { Uri.parse(it) } + ?: preferences.backupsDirectory().get().toUri() + val flags = inputData.getInt(BACKUP_FLAGS_KEY, BackupConst.BACKUP_ALL) + val isAutoBackup = inputData.getBoolean(IS_AUTO_BACKUP_KEY, false) + + context.notificationManager.notify(Notifications.ID_BACKUP_PROGRESS, notifier.showBackupProgress().build()) return try { - FullBackupManager(context).createBackup(uri, flags, true) + val location = FullBackupManager(context).createBackup(uri, flags, isAutoBackup) + if (!isAutoBackup) notifier.showBackupComplete(UniFile.fromUri(context, location.toUri())) Result.success() } catch (e: Exception) { logcat(LogPriority.ERROR, e) + if (!isAutoBackup) notifier.showBackupError(e.message) Result.failure() + } finally { + context.notificationManager.cancel(Notifications.ID_BACKUP_PROGRESS) } } companion object { private const val TAG = "BackupCreator" + private const val IS_AUTO_BACKUP_KEY = "is_auto_backup" // Boolean + private const val LOCATION_URI_KEY = "location_uri" // String + private const val BACKUP_FLAGS_KEY = "backup_flags" // Int + + fun isManualJobRunning(context: Context): Boolean { + val list = WorkManager.getInstance(context).getWorkInfosByTag(TAG).get() + return list.find { it.state == WorkInfo.State.RUNNING } != null + } + fun setupTask(context: Context, prefInterval: Int? = null) { val preferences = Injekt.get() val interval = prefInterval ?: preferences.backupInterval().get() + val workManager = WorkManager.getInstance(context) if (interval > 0) { val request = PeriodicWorkRequestBuilder( interval.toLong(), @@ -45,12 +72,26 @@ class BackupCreatorJob(private val context: Context, workerParams: WorkerParamet TimeUnit.MINUTES ) .addTag(TAG) + .setInputData(workDataOf(IS_AUTO_BACKUP_KEY to true)) .build() - WorkManager.getInstance(context).enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.REPLACE, request) + workManager.enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.REPLACE, request) } else { - WorkManager.getInstance(context).cancelAllWorkByTag(TAG) + workManager.cancelUniqueWork(TAG) } } + + fun startNow(context: Context, uri: Uri, flags: Int) { + val inputData = workDataOf( + IS_AUTO_BACKUP_KEY to false, + LOCATION_URI_KEY to uri.toString(), + BACKUP_FLAGS_KEY to flags + ) + val request = OneTimeWorkRequestBuilder() + .addTag(TAG) + .setInputData(inputData) + .build() + WorkManager.getInstance(context).enqueueUniqueWork("$TAG:manual", ExistingWorkPolicy.KEEP, request) + } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt index 652471c331..134c034ff0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt @@ -4,14 +4,14 @@ import android.content.Context import android.net.Uri import com.hippo.unifile.UniFile import eu.kanade.tachiyomi.data.backup.AbstractBackupManager -import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CATEGORY -import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CATEGORY_MASK -import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CHAPTER -import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CHAPTER_MASK -import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_HISTORY -import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_HISTORY_MASK -import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_TRACK -import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_TRACK_MASK +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CATEGORY_MASK +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CHAPTER +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_CHAPTER_MASK +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_HISTORY +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_HISTORY_MASK +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_TRACK +import eu.kanade.tachiyomi.data.backup.BackupConst.BACKUP_TRACK_MASK import eu.kanade.tachiyomi.data.backup.full.models.Backup import eu.kanade.tachiyomi.data.backup.full.models.BackupCategory import eu.kanade.tachiyomi.data.backup.full.models.BackupChapter @@ -43,9 +43,9 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) { * Create backup Json file from database * * @param uri path of Uri - * @param isJob backup called from job + * @param isAutoBackup backup called from scheduled backup job */ - override fun createBackup(uri: Uri, flags: Int, isJob: Boolean): String { + override fun createBackup(uri: Uri, flags: Int, isAutoBackup: Boolean): String { // Create root object var backup: Backup? = null @@ -63,7 +63,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) { var file: UniFile? = null try { file = ( - if (isJob) { + if (isAutoBackup) { // Get dir of file and create var dir = UniFile.fromUri(context, uri) dir = dir.createDirectory("automatic") diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupManager.kt index d03e91a7af..4984b242ce 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupManager.kt @@ -55,9 +55,9 @@ class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : Ab * Create backup Json file from database * * @param uri path of Uri - * @param isJob backup called from job + * @param isAutoBackup backup called from scheduled backup job */ - override fun createBackup(uri: Uri, flags: Int, isJob: Boolean) = + override fun createBackup(uri: Uri, flags: Int, isAutoBackup: Boolean) = throw IllegalStateException("Legacy backup creation is not supported") fun restoreMangaNoFetch(manga: Manga, dbManga: Manga) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt index a6d1353605..e1fde8e417 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt @@ -20,7 +20,6 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.hippo.unifile.UniFile import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.backup.BackupConst -import eu.kanade.tachiyomi.data.backup.BackupCreateService import eu.kanade.tachiyomi.data.backup.BackupCreatorJob import eu.kanade.tachiyomi.data.backup.BackupRestoreService import eu.kanade.tachiyomi.data.backup.ValidatorParseException @@ -70,7 +69,7 @@ class SettingsBackupController : SettingsController() { context.toast(R.string.restore_miui_warning, Toast.LENGTH_LONG) } - if (!BackupCreateService.isRunning(context)) { + if (!BackupCreatorJob.isManualJobRunning(context)) { val ctrl = CreateBackupDialog() ctrl.targetController = this@SettingsBackupController ctrl.showDialog(router) @@ -197,11 +196,7 @@ class SettingsBackupController : SettingsController() { Intent.FLAG_GRANT_WRITE_URI_PERMISSION activity.contentResolver.takePersistableUriPermission(uri, flags) - BackupCreateService.start( - activity, - uri, - backupFlags, - ) + BackupCreatorJob.startNow(activity, uri, backupFlags) } CODE_BACKUP_RESTORE -> { RestoreBackupDialog(uri).showDialog(router) @@ -252,10 +247,10 @@ class SettingsBackupController : SettingsController() { selected.forEachIndexed { i, checked -> if (checked) { when (i) { - 1 -> flags = flags or BackupCreateService.BACKUP_CATEGORY - 2 -> flags = flags or BackupCreateService.BACKUP_CHAPTER - 3 -> flags = flags or BackupCreateService.BACKUP_TRACK - 4 -> flags = flags or BackupCreateService.BACKUP_HISTORY + 1 -> flags = flags or BackupConst.BACKUP_CATEGORY + 2 -> flags = flags or BackupConst.BACKUP_CHAPTER + 3 -> flags = flags or BackupConst.BACKUP_TRACK + 4 -> flags = flags or BackupConst.BACKUP_HISTORY } } }