mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-02-02 06:46:22 +01:00
Add a grace period after service restart
This commit is contained in:
parent
ecc244f8ba
commit
77b213cf36
1 changed files with 94 additions and 20 deletions
|
@ -69,6 +69,22 @@ class ImageProcessorService : Service() {
|
|||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||
if (!isForeground) {
|
||||
try {
|
||||
startForeground(NOTIFICATION_ID, buildNotification())
|
||||
isForeground = true
|
||||
} catch (e: Throwable) {
|
||||
// ???
|
||||
logE(TAG, "[onStartCommand] Failed while startForeground", e)
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags and START_FLAG_REDELIVERY) != 0) {
|
||||
logW(TAG, "[onStartCommand] Redelivered intent, service crashed?")
|
||||
// add a short grace period to let user cancel the queue
|
||||
addCommand(ImageProcessorGracePeriodCommand())
|
||||
}
|
||||
|
||||
when (intent.action) {
|
||||
ACTION_CANCEL -> onCancel(startId)
|
||||
else -> onNewImage(intent, startId)
|
||||
|
@ -85,15 +101,6 @@ class ImageProcessorService : Service() {
|
|||
private fun onNewImage(intent: Intent, startId: Int) {
|
||||
assert(intent.hasExtra(EXTRA_METHOD))
|
||||
assert(intent.hasExtra(EXTRA_FILE_URL))
|
||||
if (!isForeground) {
|
||||
try {
|
||||
startForeground(NOTIFICATION_ID, buildNotification())
|
||||
isForeground = true
|
||||
} catch (e: Throwable) {
|
||||
// ???
|
||||
logE(TAG, "[onStartCommand] Failed while startForeground", e)
|
||||
}
|
||||
}
|
||||
|
||||
val method = intent.getStringExtra(EXTRA_METHOD)
|
||||
when (method) {
|
||||
|
@ -107,7 +114,9 @@ class ImageProcessorService : Service() {
|
|||
// we can't call stopSelf here as it'll stop the service even if
|
||||
// there are commands running in the bg
|
||||
addCommand(
|
||||
ImageProcessorCommand(startId, "null", "", null, "", 0, 0)
|
||||
ImageProcessorEnhanceCommand(
|
||||
startId, "null", "", null, "", 0, 0
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -153,7 +162,7 @@ class ImageProcessorService : Service() {
|
|||
val maxWidth = extras.getInt(EXTRA_MAX_WIDTH)
|
||||
val maxHeight = extras.getInt(EXTRA_MAX_HEIGHT)
|
||||
addCommand(
|
||||
ImageProcessorCommand(
|
||||
ImageProcessorEnhanceCommand(
|
||||
startId, method, fileUrl, headers, filename, maxWidth,
|
||||
maxHeight, args = args
|
||||
)
|
||||
|
@ -224,6 +233,24 @@ class ImageProcessorService : Service() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun buildGracePeriodNotification(): Notification {
|
||||
val cancelIntent =
|
||||
Intent(this, ImageProcessorService::class.java).apply {
|
||||
action = ACTION_CANCEL
|
||||
}
|
||||
val cancelPendingIntent = PendingIntent.getService(
|
||||
this, 0, cancelIntent, getPendingIntentFlagImmutable()
|
||||
)
|
||||
return NotificationCompat.Builder(this, CHANNEL_ID).run {
|
||||
setSmallIcon(R.drawable.outline_auto_fix_high_white_24)
|
||||
setContentTitle("Preparing to restart photo enhancement")
|
||||
addAction(
|
||||
0, getString(android.R.string.cancel), cancelPendingIntent
|
||||
)
|
||||
build()
|
||||
}
|
||||
}
|
||||
|
||||
private fun addCommand(cmd: ImageProcessorCommand) {
|
||||
cmds.add(cmd)
|
||||
if (cmdTask == null) {
|
||||
|
@ -231,9 +258,17 @@ class ImageProcessorService : Service() {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private fun runCommand() {
|
||||
val cmd = cmds.first()
|
||||
if (cmd is ImageProcessorEnhanceCommand) {
|
||||
runCommand(cmd)
|
||||
} else if (cmd is ImageProcessorGracePeriodCommand) {
|
||||
runCommand(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private fun runCommand(cmd: ImageProcessorEnhanceCommand) {
|
||||
notificationManager.notify(
|
||||
NOTIFICATION_ID, buildNotification(cmd.filename)
|
||||
)
|
||||
|
@ -242,11 +277,10 @@ class ImageProcessorService : Service() {
|
|||
notifyResult(result)
|
||||
cmds.removeFirst()
|
||||
stopSelf(cmd.startId)
|
||||
cmdTask = null
|
||||
@Suppress("Deprecation")
|
||||
if (cmds.isNotEmpty() && !isCancelled) {
|
||||
runCommand()
|
||||
} else {
|
||||
cmdTask = null
|
||||
}
|
||||
}
|
||||
}.apply {
|
||||
|
@ -255,6 +289,37 @@ class ImageProcessorService : Service() {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private fun runCommand(
|
||||
@Suppress("UNUSED_PARAMETER") cmd: ImageProcessorGracePeriodCommand
|
||||
) {
|
||||
notificationManager.notify(
|
||||
NOTIFICATION_ID, buildGracePeriodNotification()
|
||||
)
|
||||
@Suppress("Deprecation")
|
||||
cmdTask = object : AsyncTask<Unit, Unit, Unit>(), AsyncTaskCancellable {
|
||||
override fun doInBackground(vararg params: Unit?) {
|
||||
// 10 seconds
|
||||
for (i in 0 until 20) {
|
||||
if (isCancelled) {
|
||||
return
|
||||
}
|
||||
Thread.sleep(500)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPostExecute(result: Unit?) {
|
||||
cmdTask = null
|
||||
cmds.removeFirst()
|
||||
if (cmds.isNotEmpty() && !isCancelled) {
|
||||
runCommand()
|
||||
}
|
||||
}
|
||||
}.apply {
|
||||
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyResult(event: MessageEvent) {
|
||||
if (event is ImageProcessorCompletedEvent) {
|
||||
notificationManager.notify(
|
||||
|
@ -281,7 +346,7 @@ class ImageProcessorService : Service() {
|
|||
|
||||
private var isForeground = false
|
||||
private val cmds = mutableListOf<ImageProcessorCommand>()
|
||||
private var cmdTask: ImageProcessorCommandTask? = null
|
||||
private var cmdTask: AsyncTaskCancellable? = null
|
||||
|
||||
private val notificationManager by lazy {
|
||||
NotificationManagerCompat.from(this)
|
||||
|
@ -295,7 +360,9 @@ class ImageProcessorService : Service() {
|
|||
}
|
||||
}
|
||||
|
||||
private data class ImageProcessorCommand(
|
||||
private interface ImageProcessorCommand
|
||||
|
||||
private class ImageProcessorEnhanceCommand(
|
||||
val startId: Int,
|
||||
val method: String,
|
||||
val fileUrl: String,
|
||||
|
@ -304,11 +371,14 @@ private data class ImageProcessorCommand(
|
|||
val maxWidth: Int,
|
||||
val maxHeight: Int,
|
||||
val args: Map<String, Any?> = mapOf(),
|
||||
)
|
||||
) : ImageProcessorCommand
|
||||
|
||||
private class ImageProcessorGracePeriodCommand : ImageProcessorCommand
|
||||
|
||||
@Suppress("Deprecation")
|
||||
private open class ImageProcessorCommandTask(context: Context) :
|
||||
AsyncTask<ImageProcessorCommand, Unit, MessageEvent>() {
|
||||
AsyncTask<ImageProcessorEnhanceCommand, Unit, MessageEvent>(),
|
||||
AsyncTaskCancellable {
|
||||
companion object {
|
||||
private val exifTagOfInterests = listOf(
|
||||
ExifInterface.TAG_IMAGE_DESCRIPTION,
|
||||
|
@ -423,7 +493,7 @@ private open class ImageProcessorCommandTask(context: Context) :
|
|||
}
|
||||
|
||||
override fun doInBackground(
|
||||
vararg params: ImageProcessorCommand?
|
||||
vararg params: ImageProcessorEnhanceCommand?
|
||||
): MessageEvent {
|
||||
val cmd = params[0]!!
|
||||
return try {
|
||||
|
@ -436,7 +506,7 @@ private open class ImageProcessorCommandTask(context: Context) :
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleCommand(cmd: ImageProcessorCommand): Uri {
|
||||
private fun handleCommand(cmd: ImageProcessorEnhanceCommand): Uri {
|
||||
val file = downloadFile(cmd.fileUrl, cmd.headers)
|
||||
handleCancel()
|
||||
return try {
|
||||
|
@ -555,6 +625,10 @@ private open class ImageProcessorCommandTask(context: Context) :
|
|||
private val context = context
|
||||
}
|
||||
|
||||
private interface AsyncTaskCancellable {
|
||||
fun cancel(a: Boolean): Boolean
|
||||
}
|
||||
|
||||
private fun getTempDir(context: Context): File {
|
||||
val f = File(context.cacheDir, "imageProcessor")
|
||||
if (!f.exists()) {
|
||||
|
|
Loading…
Reference in a new issue