From e65a855b0220055f7b08b61aafe2f1f7027addda Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Tue, 14 Jul 2020 14:14:33 -0500 Subject: [PATCH] Use non-blocking daos in json importer --- .../org/tasks/backup/TasksBackupAgent.java | 59 ------------ .../java/org/tasks/backup/TasksBackupAgent.kt | 54 +++++++++++ .../org/tasks/backup/TasksJsonImporter.kt | 28 +++--- .../org/tasks/dialogs/ImportTasksDialog.java | 95 ------------------- .../org/tasks/dialogs/ImportTasksDialog.kt | 90 ++++++++++++++++++ 5 files changed, 158 insertions(+), 168 deletions(-) delete mode 100644 app/src/main/java/org/tasks/backup/TasksBackupAgent.java create mode 100644 app/src/main/java/org/tasks/backup/TasksBackupAgent.kt delete mode 100644 app/src/main/java/org/tasks/dialogs/ImportTasksDialog.java create mode 100644 app/src/main/java/org/tasks/dialogs/ImportTasksDialog.kt diff --git a/app/src/main/java/org/tasks/backup/TasksBackupAgent.java b/app/src/main/java/org/tasks/backup/TasksBackupAgent.java deleted file mode 100644 index f5122afb6..000000000 --- a/app/src/main/java/org/tasks/backup/TasksBackupAgent.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.tasks.backup; - -import android.app.backup.BackupAgentHelper; -import android.app.backup.BackupDataInput; -import android.app.backup.FileBackupHelper; -import android.net.Uri; -import android.os.ParcelFileDescriptor; -import com.todoroo.astrid.backup.BackupConstants; -import dagger.hilt.EntryPoint; -import dagger.hilt.InstallIn; -import dagger.hilt.android.EntryPointAccessors; -import dagger.hilt.android.components.ApplicationComponent; -import java.io.File; -import java.io.IOException; -import timber.log.Timber; - -public class TasksBackupAgent extends BackupAgentHelper { - - @EntryPoint - @InstallIn(ApplicationComponent.class) - interface TasksBackupAgentEntryPoint { - TasksJsonImporter getTasksJsonImporter(); - } - - private static final String BACKUP_KEY = "backup"; - - private TasksJsonImporter importer; - - @Override - public void onCreate() { - TasksBackupAgentEntryPoint hilt = - EntryPointAccessors.fromApplication(getApplicationContext(), TasksBackupAgentEntryPoint.class); - importer = hilt.getTasksJsonImporter(); - - addHelper(BACKUP_KEY, new FileBackupHelper(this, BackupConstants.INTERNAL_BACKUP)); - } - - @Override - public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) - throws IOException { - super.onRestore(data, appVersionCode, newState); - - File backup = - new File( - String.format( - "%s/%s", getFilesDir().getAbsolutePath(), BackupConstants.INTERNAL_BACKUP)); - - if (backup.exists()) { - importer.importTasks(this, Uri.fromFile(backup), null); - } else { - Timber.w("%s not found", backup.getAbsolutePath()); - } - } - - @Override - public void onQuotaExceeded(long backupDataBytes, long quotaBytes) { - Timber.e("onQuotaExceeded(%s, %s)", backupDataBytes, quotaBytes); - } -} diff --git a/app/src/main/java/org/tasks/backup/TasksBackupAgent.kt b/app/src/main/java/org/tasks/backup/TasksBackupAgent.kt new file mode 100644 index 000000000..c5b09b16e --- /dev/null +++ b/app/src/main/java/org/tasks/backup/TasksBackupAgent.kt @@ -0,0 +1,54 @@ +package org.tasks.backup + +import android.app.backup.BackupAgentHelper +import android.app.backup.BackupDataInput +import android.app.backup.FileBackupHelper +import android.net.Uri +import android.os.ParcelFileDescriptor +import com.todoroo.astrid.backup.BackupConstants +import dagger.hilt.EntryPoint +import dagger.hilt.InstallIn +import dagger.hilt.android.EntryPointAccessors +import dagger.hilt.android.components.ApplicationComponent +import kotlinx.coroutines.runBlocking +import timber.log.Timber +import java.io.File +import java.io.IOException + +class TasksBackupAgent : BackupAgentHelper() { + @EntryPoint + @InstallIn(ApplicationComponent::class) + internal interface TasksBackupAgentEntryPoint { + val tasksJsonImporter: TasksJsonImporter + } + + private lateinit var importer: TasksJsonImporter + + override fun onCreate() { + val hilt = EntryPointAccessors.fromApplication(applicationContext, TasksBackupAgentEntryPoint::class.java) + importer = hilt.tasksJsonImporter + addHelper(BACKUP_KEY, FileBackupHelper(this, BackupConstants.INTERNAL_BACKUP)) + } + + @Throws(IOException::class) + override fun onRestore(data: BackupDataInput, appVersionCode: Int, newState: ParcelFileDescriptor) { + super.onRestore(data, appVersionCode, newState) + val backup = File(String.format( + "%s/%s", filesDir.absolutePath, BackupConstants.INTERNAL_BACKUP)) + if (backup.exists()) { + runBlocking { + importer.importTasks(this@TasksBackupAgent, Uri.fromFile(backup), null) + } + } else { + Timber.w("%s not found", backup.absolutePath) + } + } + + override fun onQuotaExceeded(backupDataBytes: Long, quotaBytes: Long) { + Timber.e("onQuotaExceeded(%s, %s)", backupDataBytes, quotaBytes) + } + + companion object { + private const val BACKUP_KEY = "backup" + } +} \ No newline at end of file diff --git a/app/src/main/java/org/tasks/backup/TasksJsonImporter.kt b/app/src/main/java/org/tasks/backup/TasksJsonImporter.kt index 78b32cb38..dd991811c 100644 --- a/app/src/main/java/org/tasks/backup/TasksJsonImporter.kt +++ b/app/src/main/java/org/tasks/backup/TasksJsonImporter.kt @@ -6,7 +6,7 @@ import android.net.Uri import android.os.Handler import com.google.gson.Gson import com.google.gson.JsonObject -import com.todoroo.astrid.dao.TaskDaoBlocking +import com.todoroo.astrid.dao.TaskDao import com.todoroo.astrid.service.TaskMover import com.todoroo.astrid.service.Upgrader import com.todoroo.astrid.service.Upgrader.Companion.getAndroidColor @@ -23,21 +23,21 @@ import java.io.InputStreamReader import javax.inject.Inject class TasksJsonImporter @Inject constructor( - private val tagDataDao: TagDataDaoBlocking, - private val userActivityDao: UserActivityDaoBlocking, - private val taskDao: TaskDaoBlocking, - private val locationDao: LocationDaoBlocking, + private val tagDataDao: TagDataDao, + private val userActivityDao: UserActivityDao, + private val taskDao: TaskDao, + private val locationDao: LocationDao, private val localBroadcastManager: LocalBroadcastManager, - private val alarmDao: AlarmDaoBlocking, - private val tagDao: TagDaoBlocking, - private val googleTaskDao: GoogleTaskDaoBlocking, - private val googleTaskListDao: GoogleTaskListDaoBlocking, - private val filterDao: FilterDaoBlocking, - private val taskAttachmentDao: TaskAttachmentDaoBlocking, - private val caldavDao: CaldavDaoBlocking, + private val alarmDao: AlarmDao, + private val tagDao: TagDao, + private val googleTaskDao: GoogleTaskDao, + private val googleTaskListDao: GoogleTaskListDao, + private val filterDao: FilterDao, + private val taskAttachmentDao: TaskAttachmentDao, + private val caldavDao: CaldavDao, private val preferences: Preferences, private val taskMover: TaskMover, - private val taskListMetadataDao: TaskListMetadataDaoBlocking) { + private val taskListMetadataDao: TaskListMetadataDao) { private val result = ImportResult() @@ -49,7 +49,7 @@ class TasksJsonImporter @Inject constructor( handler.post { progressDialog.setMessage(message) } } - fun importTasks(context: Context, backupFile: Uri?, progressDialog: ProgressDialog?): ImportResult { + suspend fun importTasks(context: Context, backupFile: Uri?, progressDialog: ProgressDialog?): ImportResult { val handler = Handler(context.mainLooper) val gson = Gson() val `is`: InputStream? diff --git a/app/src/main/java/org/tasks/dialogs/ImportTasksDialog.java b/app/src/main/java/org/tasks/dialogs/ImportTasksDialog.java deleted file mode 100644 index 1e5fcc8a2..000000000 --- a/app/src/main/java/org/tasks/dialogs/ImportTasksDialog.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.tasks.dialogs; - -import android.app.Activity; -import android.app.Dialog; -import android.app.ProgressDialog; -import android.content.res.Resources; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import androidx.fragment.app.DialogFragment; -import com.todoroo.andlib.utility.DialogUtilities; -import com.todoroo.astrid.backup.TasksXmlImporter; -import dagger.hilt.android.AndroidEntryPoint; -import javax.inject.Inject; -import org.tasks.R; -import org.tasks.backup.TasksJsonImporter; -import org.tasks.backup.TasksJsonImporter.ImportResult; -import org.tasks.ui.Toaster; - -@AndroidEntryPoint -public class ImportTasksDialog extends DialogFragment { - - private static final String EXTRA_URI = "extra_uri"; - private static final String EXTRA_EXTENSION = "extra_extension"; - - @Inject TasksXmlImporter xmlImporter; - @Inject TasksJsonImporter jsonImporter; - @Inject DialogBuilder dialogBuilder; - @Inject Activity context; - @Inject Toaster toaster; - - public static ImportTasksDialog newImportTasksDialog(Uri data, String extension) { - ImportTasksDialog importTasksDialog = new ImportTasksDialog(); - Bundle args = new Bundle(); - args.putParcelable(EXTRA_URI, data); - args.putString(EXTRA_EXTENSION, extension); - importTasksDialog.setArguments(args); - return importTasksDialog; - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - Bundle arguments = getArguments(); - Uri data = arguments.getParcelable(EXTRA_URI); - String extension = arguments.getString(EXTRA_EXTENSION); - ProgressDialog progressDialog = dialogBuilder.newProgressDialog(); - progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); - progressDialog.setCancelable(false); - progressDialog.setIndeterminate(true); - progressDialog.show(); - setCancelable(false); - switch (extension) { - case "json": - Handler handler = new Handler(); - new Thread( - () -> { - ImportResult result = - jsonImporter.importTasks(getActivity(), data, progressDialog); - handler.post(() -> { - if (progressDialog.isShowing()) { - DialogUtilities.dismissDialog((Activity) context, progressDialog); - } - showSummary(result); - }); - }) - .start(); - break; - case "xml": - xmlImporter.importTasks(getActivity(), data, progressDialog); - break; - default: - throw new RuntimeException("Invalid extension: " + extension); - } - return progressDialog; - } - - private void showSummary(ImportResult result) { - Resources r = context.getResources(); - dialogBuilder - .newDialog(R.string.import_summary_title) - .setMessage( - context.getString( - R.string.import_summary_message, - "", - r.getQuantityString(R.plurals.Ntasks, result.getTaskCount(), result.getTaskCount()), - r.getQuantityString( - R.plurals.Ntasks, - result.getImportCount(), - result.getImportCount()), - r.getQuantityString(R.plurals.Ntasks, result.getSkipCount(), result.getSkipCount()), - r.getQuantityString(R.plurals.Ntasks, 0, 0))) - .setPositiveButton(android.R.string.ok, (dialog, id) -> dialog.dismiss()) - .show(); - } -} diff --git a/app/src/main/java/org/tasks/dialogs/ImportTasksDialog.kt b/app/src/main/java/org/tasks/dialogs/ImportTasksDialog.kt new file mode 100644 index 000000000..0dce77597 --- /dev/null +++ b/app/src/main/java/org/tasks/dialogs/ImportTasksDialog.kt @@ -0,0 +1,90 @@ +package org.tasks.dialogs + +import android.app.Activity +import android.app.Dialog +import android.app.ProgressDialog +import android.net.Uri +import android.os.Bundle +import androidx.fragment.app.DialogFragment +import androidx.lifecycle.lifecycleScope +import com.todoroo.astrid.backup.TasksXmlImporter +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.NonCancellable +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.tasks.R +import org.tasks.backup.TasksJsonImporter +import org.tasks.backup.TasksJsonImporter.ImportResult +import org.tasks.ui.Toaster +import javax.inject.Inject + +@AndroidEntryPoint +class ImportTasksDialog : DialogFragment() { + @Inject lateinit var xmlImporter: TasksXmlImporter + @Inject lateinit var jsonImporter: TasksJsonImporter + @Inject lateinit var dialogBuilder: DialogBuilder + @Inject lateinit var context: Activity + @Inject lateinit var toaster: Toaster + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val arguments = requireArguments() + val data = arguments.getParcelable(EXTRA_URI) + val extension = arguments.getString(EXTRA_EXTENSION) + val progressDialog = dialogBuilder.newProgressDialog() + progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER) + progressDialog.setCancelable(false) + progressDialog.isIndeterminate = true + progressDialog.show() + isCancelable = false + when (extension) { + "json" -> { + val activity = requireActivity() + lifecycleScope.launch { + val result = withContext(NonCancellable) { + jsonImporter.importTasks(activity, data, progressDialog) + } + if (progressDialog.isShowing) { + progressDialog.dismiss() + } + showSummary(result) + } + } + "xml" -> xmlImporter.importTasks(activity, data, progressDialog) + else -> throw RuntimeException("Invalid extension: $extension") + } + return progressDialog + } + + private fun showSummary(result: ImportResult) { + val r = requireContext().resources + dialogBuilder + .newDialog(R.string.import_summary_title) + .setMessage( + r.getString( + R.string.import_summary_message, + "", + r.getQuantityString(R.plurals.Ntasks, result.taskCount, result.taskCount), + r.getQuantityString( + R.plurals.Ntasks, + result.importCount, + result.importCount), + r.getQuantityString(R.plurals.Ntasks, result.skipCount, result.skipCount), + r.getQuantityString(R.plurals.Ntasks, 0, 0))) + .setPositiveButton(android.R.string.ok, null) + .show() + } + + companion object { + private const val EXTRA_URI = "extra_uri" + private const val EXTRA_EXTENSION = "extra_extension" + + fun newImportTasksDialog(data: Uri?, extension: String?): ImportTasksDialog { + val importTasksDialog = ImportTasksDialog() + val args = Bundle() + args.putParcelable(EXTRA_URI, data) + args.putString(EXTRA_EXTENSION, extension) + importTasksDialog.arguments = args + return importTasksDialog + } + } +} \ No newline at end of file