mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-02-13 04:56:21 +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 {
|
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) {
|
when (intent.action) {
|
||||||
ACTION_CANCEL -> onCancel(startId)
|
ACTION_CANCEL -> onCancel(startId)
|
||||||
else -> onNewImage(intent, startId)
|
else -> onNewImage(intent, startId)
|
||||||
|
@ -85,15 +101,6 @@ class ImageProcessorService : Service() {
|
||||||
private fun onNewImage(intent: Intent, startId: Int) {
|
private fun onNewImage(intent: Intent, startId: Int) {
|
||||||
assert(intent.hasExtra(EXTRA_METHOD))
|
assert(intent.hasExtra(EXTRA_METHOD))
|
||||||
assert(intent.hasExtra(EXTRA_FILE_URL))
|
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)
|
val method = intent.getStringExtra(EXTRA_METHOD)
|
||||||
when (method) {
|
when (method) {
|
||||||
|
@ -107,7 +114,9 @@ class ImageProcessorService : Service() {
|
||||||
// we can't call stopSelf here as it'll stop the service even if
|
// we can't call stopSelf here as it'll stop the service even if
|
||||||
// there are commands running in the bg
|
// there are commands running in the bg
|
||||||
addCommand(
|
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 maxWidth = extras.getInt(EXTRA_MAX_WIDTH)
|
||||||
val maxHeight = extras.getInt(EXTRA_MAX_HEIGHT)
|
val maxHeight = extras.getInt(EXTRA_MAX_HEIGHT)
|
||||||
addCommand(
|
addCommand(
|
||||||
ImageProcessorCommand(
|
ImageProcessorEnhanceCommand(
|
||||||
startId, method, fileUrl, headers, filename, maxWidth,
|
startId, method, fileUrl, headers, filename, maxWidth,
|
||||||
maxHeight, args = args
|
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) {
|
private fun addCommand(cmd: ImageProcessorCommand) {
|
||||||
cmds.add(cmd)
|
cmds.add(cmd)
|
||||||
if (cmdTask == null) {
|
if (cmdTask == null) {
|
||||||
|
@ -231,9 +258,17 @@ class ImageProcessorService : Service() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("StaticFieldLeak")
|
|
||||||
private fun runCommand() {
|
private fun runCommand() {
|
||||||
val cmd = cmds.first()
|
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(
|
notificationManager.notify(
|
||||||
NOTIFICATION_ID, buildNotification(cmd.filename)
|
NOTIFICATION_ID, buildNotification(cmd.filename)
|
||||||
)
|
)
|
||||||
|
@ -242,11 +277,10 @@ class ImageProcessorService : Service() {
|
||||||
notifyResult(result)
|
notifyResult(result)
|
||||||
cmds.removeFirst()
|
cmds.removeFirst()
|
||||||
stopSelf(cmd.startId)
|
stopSelf(cmd.startId)
|
||||||
|
cmdTask = null
|
||||||
@Suppress("Deprecation")
|
@Suppress("Deprecation")
|
||||||
if (cmds.isNotEmpty() && !isCancelled) {
|
if (cmds.isNotEmpty() && !isCancelled) {
|
||||||
runCommand()
|
runCommand()
|
||||||
} else {
|
|
||||||
cmdTask = null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.apply {
|
}.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) {
|
private fun notifyResult(event: MessageEvent) {
|
||||||
if (event is ImageProcessorCompletedEvent) {
|
if (event is ImageProcessorCompletedEvent) {
|
||||||
notificationManager.notify(
|
notificationManager.notify(
|
||||||
|
@ -281,7 +346,7 @@ class ImageProcessorService : Service() {
|
||||||
|
|
||||||
private var isForeground = false
|
private var isForeground = false
|
||||||
private val cmds = mutableListOf<ImageProcessorCommand>()
|
private val cmds = mutableListOf<ImageProcessorCommand>()
|
||||||
private var cmdTask: ImageProcessorCommandTask? = null
|
private var cmdTask: AsyncTaskCancellable? = null
|
||||||
|
|
||||||
private val notificationManager by lazy {
|
private val notificationManager by lazy {
|
||||||
NotificationManagerCompat.from(this)
|
NotificationManagerCompat.from(this)
|
||||||
|
@ -295,7 +360,9 @@ class ImageProcessorService : Service() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class ImageProcessorCommand(
|
private interface ImageProcessorCommand
|
||||||
|
|
||||||
|
private class ImageProcessorEnhanceCommand(
|
||||||
val startId: Int,
|
val startId: Int,
|
||||||
val method: String,
|
val method: String,
|
||||||
val fileUrl: String,
|
val fileUrl: String,
|
||||||
|
@ -304,11 +371,14 @@ private data class ImageProcessorCommand(
|
||||||
val maxWidth: Int,
|
val maxWidth: Int,
|
||||||
val maxHeight: Int,
|
val maxHeight: Int,
|
||||||
val args: Map<String, Any?> = mapOf(),
|
val args: Map<String, Any?> = mapOf(),
|
||||||
)
|
) : ImageProcessorCommand
|
||||||
|
|
||||||
|
private class ImageProcessorGracePeriodCommand : ImageProcessorCommand
|
||||||
|
|
||||||
@Suppress("Deprecation")
|
@Suppress("Deprecation")
|
||||||
private open class ImageProcessorCommandTask(context: Context) :
|
private open class ImageProcessorCommandTask(context: Context) :
|
||||||
AsyncTask<ImageProcessorCommand, Unit, MessageEvent>() {
|
AsyncTask<ImageProcessorEnhanceCommand, Unit, MessageEvent>(),
|
||||||
|
AsyncTaskCancellable {
|
||||||
companion object {
|
companion object {
|
||||||
private val exifTagOfInterests = listOf(
|
private val exifTagOfInterests = listOf(
|
||||||
ExifInterface.TAG_IMAGE_DESCRIPTION,
|
ExifInterface.TAG_IMAGE_DESCRIPTION,
|
||||||
|
@ -423,7 +493,7 @@ private open class ImageProcessorCommandTask(context: Context) :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun doInBackground(
|
override fun doInBackground(
|
||||||
vararg params: ImageProcessorCommand?
|
vararg params: ImageProcessorEnhanceCommand?
|
||||||
): MessageEvent {
|
): MessageEvent {
|
||||||
val cmd = params[0]!!
|
val cmd = params[0]!!
|
||||||
return try {
|
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)
|
val file = downloadFile(cmd.fileUrl, cmd.headers)
|
||||||
handleCancel()
|
handleCancel()
|
||||||
return try {
|
return try {
|
||||||
|
@ -555,6 +625,10 @@ private open class ImageProcessorCommandTask(context: Context) :
|
||||||
private val context = context
|
private val context = context
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private interface AsyncTaskCancellable {
|
||||||
|
fun cancel(a: Boolean): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
private fun getTempDir(context: Context): File {
|
private fun getTempDir(context: Context): File {
|
||||||
val f = File(context.cacheDir, "imageProcessor")
|
val f = File(context.cacheDir, "imageProcessor")
|
||||||
if (!f.exists()) {
|
if (!f.exists()) {
|
||||||
|
|
Loading…
Reference in a new issue