Move backup/restore status strings to resources, show completed state

This commit is contained in:
Moez Bhatti
2018-08-31 17:31:43 -04:00
parent 680c8eb445
commit 0419f4a83a
9 changed files with 92 additions and 39 deletions
@@ -32,13 +32,14 @@ import io.reactivex.subjects.BehaviorSubject
import io.reactivex.subjects.Subject
import io.realm.Realm
import okio.Okio
import timber.log.Timber
import java.io.File
import java.io.FileOutputStream
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.concurrent.schedule
@Singleton
@@ -95,23 +96,15 @@ class BackupRepositoryImpl @Inject constructor(
messageCount = messages.size
// Map the messages to the new format
val startTime = System.currentTimeMillis()
messages.mapIndexed { index, message ->
val progress = index.toDouble() / messageCount * 100
val elapsed = System.currentTimeMillis() - startTime
val remaining = when {
index > 100 -> TimeUnit.MILLISECONDS.toSeconds((elapsed.toDouble() / index * (messageCount - index)).toLong())
else -> 0
}
// Update the progress
backupProgress.onNext(BackupRepository.Progress.Running(progress.toInt(), "$remaining seconds remaining"))
backupProgress.onNext(BackupRepository.Progress.Running(messageCount, index))
messageToBackupMessage(message)
}
}
// Update the status, and set the progress to be indeterminate since we can no longer calculate progress
backupProgress.onNext(BackupRepository.Progress.Running(0, "Saving..."))
backupProgress.onNext(BackupRepository.Progress.Saving())
// Convert the data to json
val adapter = moshi.adapter(Backup::class.java).indent("\t")
@@ -125,9 +118,12 @@ class BackupRepositoryImpl @Inject constructor(
// Write the log to the file
FileOutputStream(file, true).use { fileOutputStream -> fileOutputStream.write(json) }
} catch (e: Exception) {
Timber.w(e)
}
backupProgress.onNext(BackupRepository.Progress.Idle())
// Mark the task finished, and set it as Idle a second later
backupProgress.onNext(BackupRepository.Progress.Finished())
Timer().schedule(1000) { backupProgress.onNext(BackupRepository.Progress.Idle()) }
}
private fun messageToBackupMessage(message: Message): BackupMessage = BackupMessage(
@@ -169,7 +165,7 @@ class BackupRepositoryImpl @Inject constructor(
// If a backupFile or restore is already running, don't do anything
if (isBackupOrRestoreRunning()) return
restoreProgress.onNext(BackupRepository.Progress.Running(0, "Parsing backup"))
restoreProgress.onNext(BackupRepository.Progress.Parsing())
val file = File(filePath)
val backup = Okio.buffer(Okio.source(file)).use { source ->
@@ -180,8 +176,7 @@ class BackupRepositoryImpl @Inject constructor(
backup?.messages?.forEachIndexed { index, message ->
// Update the progress
val progress = Math.ceil(index.toDouble() / messageCount * 100).toInt()
restoreProgress.onNext(BackupRepository.Progress.Running(progress, "$index/$messageCount messages"))
restoreProgress.onNext(BackupRepository.Progress.Running(messageCount, index))
context.contentResolver.insert(Telephony.Sms.CONTENT_URI, contentValuesOf(
Telephony.Sms.TYPE to message.type,
@@ -198,18 +193,19 @@ class BackupRepositoryImpl @Inject constructor(
Telephony.Sms.SUBSCRIPTION_ID to message.subId))
}
restoreProgress.onNext(BackupRepository.Progress.Running(0, "Syncing messages"))
// Sync the messages
restoreProgress.onNext(BackupRepository.Progress.Syncing())
syncRepo.syncMessages()
restoreProgress.onNext(BackupRepository.Progress.Idle())
// Mark the task finished, and set it as Idle a second later
restoreProgress.onNext(BackupRepository.Progress.Finished())
Timer().schedule(1000) { restoreProgress.onNext(BackupRepository.Progress.Idle()) }
}
override fun getRestoreProgress(): Observable<BackupRepository.Progress> = restoreProgress
private fun isBackupOrRestoreRunning(): Boolean {
return backupProgress.blockingFirst() is BackupRepository.Progress.Running
|| restoreProgress.blockingFirst() is BackupRepository.Progress.Running
return backupProgress.blockingFirst().running || restoreProgress.blockingFirst().running
}
}
@@ -1,110 +0,0 @@
/*
* Copyright (C) 2017 Moez Bhatti <moez.bhatti@gmail.com>
*
* This file is part of QKSMS.
*
* QKSMS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* QKSMS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with QKSMS. If not, see <http://www.gnu.org/licenses/>.
*/
package com.moez.QKSMS.service
import android.annotation.SuppressLint
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.IBinder
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import com.moez.QKSMS.manager.NotificationManager
import com.moez.QKSMS.repository.BackupRepository
import dagger.android.AndroidInjection
import io.reactivex.Observable
import io.reactivex.schedulers.Schedulers
import timber.log.Timber
import java.util.concurrent.TimeUnit
import javax.inject.Inject
class RestoreBackupService : Service() {
companion object {
private const val NOTIFICATION_ID = -1
private const val ACTION_START = "com.moez.QKSMS.ACTION_START"
private const val ACTION_STOP = "com.moez.QKSMS.ACTION_STOP"
private const val EXTRA_FILE_PATH = "com.moez.QKSMS.EXTRA_FILE_PATH"
fun start(context: Context, filePath: String) {
val intent = Intent(context, RestoreBackupService::class.java)
.setAction(ACTION_START)
.putExtra(EXTRA_FILE_PATH, filePath)
ContextCompat.startForegroundService(context, intent)
}
}
@Inject lateinit var backupRepo: BackupRepository
@Inject lateinit var notificationManager: NotificationManager
private val notification by lazy { notificationManager.getNotificationForBackup() }
override fun onCreate() = AndroidInjection.inject(this)
override fun onBind(intent: Intent?): IBinder? = null
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
when (intent.action) {
ACTION_START -> start(intent)
ACTION_STOP -> stop()
}
return Service.START_STICKY
}
@SuppressLint("CheckResult")
private fun start(intent: Intent) {
val notificationManager = NotificationManagerCompat.from(this)
startForeground(NOTIFICATION_ID, notification.build())
backupRepo.getRestoreProgress()
.sample(200, TimeUnit.MILLISECONDS, true)
.subscribeOn(Schedulers.io())
.subscribe { progress ->
when (progress) {
is BackupRepository.Progress.Running -> {
notification
.setProgress(100, progress.progress, false)
.setContentText("${progress.progress}%")
notificationManager.notify(NOTIFICATION_ID, notification.build())
}
is BackupRepository.Progress.Idle -> stop()
}
}
// Start the restore
Observable.just(intent)
.map { it.getStringExtra(EXTRA_FILE_PATH) }
.map(backupRepo::performRestore)
.subscribeOn(Schedulers.io())
.subscribe({}, Timber::w)
}
private fun stop() {
stopForeground(true)
stopSelf()
}
}