From 692a971dc0577f9fcbc3d0e89536c8fcc52adb73 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Sat, 4 Jul 2020 15:45:07 +0200 Subject: [PATCH] Fix issue #615 and #612, action loading --- app/build.gradle | 3 + .../DatabaseTaskNotificationService.kt | 108 ++++++++++-------- 2 files changed, 63 insertions(+), 48 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 45da980bf..ece83fba9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -102,6 +102,9 @@ dependencies { implementation 'androidx.documentfile:documentfile:1.0.1' implementation 'androidx.biometric:biometric:1.0.1' implementation 'androidx.core:core-ktx:1.2.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3' + // TODO #538 implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.2.0" // To upgrade with style implementation 'com.google.android.material:material:1.0.0' // Database diff --git a/app/src/main/java/com/kunzisoft/keepass/notifications/DatabaseTaskNotificationService.kt b/app/src/main/java/com/kunzisoft/keepass/notifications/DatabaseTaskNotificationService.kt index 219af8cc6..f10d00340 100644 --- a/app/src/main/java/com/kunzisoft/keepass/notifications/DatabaseTaskNotificationService.kt +++ b/app/src/main/java/com/kunzisoft/keepass/notifications/DatabaseTaskNotificationService.kt @@ -21,7 +21,6 @@ package com.kunzisoft.keepass.notifications import android.content.Intent import android.net.Uri -import android.os.AsyncTask import android.os.Binder import android.os.Bundle import android.os.IBinder @@ -42,17 +41,20 @@ import com.kunzisoft.keepass.tasks.ActionRunnable import com.kunzisoft.keepass.tasks.ProgressTaskUpdater import com.kunzisoft.keepass.utils.DATABASE_START_TASK_ACTION import com.kunzisoft.keepass.utils.DATABASE_STOP_TASK_ACTION +import kotlinx.coroutines.* import java.util.* +import java.util.concurrent.atomic.AtomicBoolean import kotlin.collections.ArrayList class DatabaseTaskNotificationService : NotificationService(), ProgressTaskUpdater { override val notificationId: Int = 575 - private var actionRunnableAsyncTask: ActionRunnableAsyncTask? = null + private val mainScope = CoroutineScope(Dispatchers.Main) private var mActionTaskBinder = ActionTaskBinder() private var mActionTaskListeners = LinkedList() + private var mAllowFinishAction = AtomicBoolean() private var mTitleId: Int? = null private var mMessageId: Int? = null @@ -84,6 +86,7 @@ class DatabaseTaskNotificationService : NotificationService(), ProgressTaskUpdat } override fun onBind(intent: Intent): IBinder? { + mAllowFinishAction.set(true) return mActionTaskBinder } @@ -159,34 +162,70 @@ class DatabaseTaskNotificationService : NotificationService(), ProgressTaskUpdat newNotification(intent.getIntExtra(DATABASE_TASK_TITLE_KEY, titleId)) // Build and launch the action - actionRunnableAsyncTask = ActionRunnableAsyncTask(this, - { - sendBroadcast(Intent(DATABASE_START_TASK_ACTION).apply { - putExtra(DATABASE_TASK_TITLE_KEY, titleId) - putExtra(DATABASE_TASK_MESSAGE_KEY, messageId) - putExtra(DATABASE_TASK_WARNING_KEY, warningId) - }) + mainScope.launch { + executeAction(this@DatabaseTaskNotificationService, + { + sendBroadcast(Intent(DATABASE_START_TASK_ACTION).apply { + putExtra(DATABASE_TASK_TITLE_KEY, titleId) + putExtra(DATABASE_TASK_MESSAGE_KEY, messageId) + putExtra(DATABASE_TASK_WARNING_KEY, warningId) + }) - mActionTaskListeners.forEach { actionTaskListener -> - actionTaskListener.onStartAction(titleId, messageId, warningId) - } + mActionTaskListeners.forEach { actionTaskListener -> + actionTaskListener.onStartAction(titleId, messageId, warningId) + } - }, { result -> - mActionTaskListeners.forEach { actionTaskListener -> - actionTaskListener.onStopAction(intentAction!!, result) - } + }, + { + actionRunnableNotNull + }, + { result -> + mActionTaskListeners.forEach { actionTaskListener -> + actionTaskListener.onStopAction(intentAction!!, result) + } - sendBroadcast(Intent(DATABASE_STOP_TASK_ACTION)) + sendBroadcast(Intent(DATABASE_STOP_TASK_ACTION)) - stopSelf() - } - ) - actionRunnableAsyncTask?.execute({ actionRunnableNotNull }) + stopSelf() + } + ) + } } return START_REDELIVER_INTENT } + /** + * Execute action with a coroutine + */ + private suspend fun executeAction(progressTaskUpdater: ProgressTaskUpdater, + onPreExecute: () -> Unit, + onExecute: (ProgressTaskUpdater?) -> ActionRunnable?, + onPostExecute: (result: ActionRunnable.Result) -> Unit) { + mAllowFinishAction.set(false) + onPreExecute.invoke() + withContext(Dispatchers.IO) { + onExecute.invoke(progressTaskUpdater)?.apply { + val asyncResult: Deferred = async { + val startTime = System.currentTimeMillis() + var timeIsUp = false + // Run the actionRunnable + run() + // Wait onBind or 4 seconds max + while (!mAllowFinishAction.get() && !timeIsUp) { + delay(100) + if (startTime + 4000 < System.currentTimeMillis()) + timeIsUp = true + } + result + } + withContext(Dispatchers.Main) { + onPostExecute.invoke(asyncResult.await()) + } + } + } + } + private fun newNotification(title: Int) { val builder = buildNewNotification() @@ -567,33 +606,6 @@ class DatabaseTaskNotificationService : NotificationService(), ProgressTaskUpdat } } - private class ActionRunnableAsyncTask(private val progressTaskUpdater: ProgressTaskUpdater, - private val onPreExecute: () -> Unit, - private val onPostExecute: (result: ActionRunnable.Result) -> Unit) - : AsyncTask<((ProgressTaskUpdater?) -> ActionRunnable), Void, ActionRunnable.Result>() { - - override fun onPreExecute() { - super.onPreExecute() - onPreExecute.invoke() - } - - override fun doInBackground(vararg actionRunnables: ((ProgressTaskUpdater?)-> ActionRunnable)?): ActionRunnable.Result { - var resultTask = ActionRunnable.Result(false) - actionRunnables.forEach { - it?.invoke(progressTaskUpdater)?.apply { - run() - resultTask = result - } - } - return resultTask - } - - override fun onPostExecute(result: ActionRunnable.Result) { - super.onPostExecute(result) - onPostExecute.invoke(result) - } - } - companion object { private val TAG = DatabaseTaskNotificationService::class.java.name