Browse Source

Add OfflineOperationsWorker

Signed-off-by: alperozturk <alper_ozturk@proton.me>
alperozturk 9 months ago
parent
commit
016b0fd4d6

+ 4 - 0
app/src/main/java/com/nextcloud/client/di/ComponentsModule.java

@@ -24,6 +24,7 @@ import com.nextcloud.client.onboarding.WhatsNewActivity;
 import com.nextcloud.client.widget.DashboardWidgetConfigurationActivity;
 import com.nextcloud.client.widget.DashboardWidgetConfigurationActivity;
 import com.nextcloud.client.widget.DashboardWidgetProvider;
 import com.nextcloud.client.widget.DashboardWidgetProvider;
 import com.nextcloud.client.widget.DashboardWidgetService;
 import com.nextcloud.client.widget.DashboardWidgetService;
+import com.nextcloud.receiver.NetworkChangeReceiver;
 import com.nextcloud.ui.ChooseAccountDialogFragment;
 import com.nextcloud.ui.ChooseAccountDialogFragment;
 import com.nextcloud.ui.ImageDetailFragment;
 import com.nextcloud.ui.ImageDetailFragment;
 import com.nextcloud.ui.SetStatusDialogFragment;
 import com.nextcloud.ui.SetStatusDialogFragment;
@@ -313,6 +314,9 @@ abstract class ComponentsModule {
     @ContributesAndroidInjector
     @ContributesAndroidInjector
     abstract BootupBroadcastReceiver bootupBroadcastReceiver();
     abstract BootupBroadcastReceiver bootupBroadcastReceiver();
 
 
+    @ContributesAndroidInjector
+    abstract NetworkChangeReceiver networkChangeReceiver();
+
     @ContributesAndroidInjector
     @ContributesAndroidInjector
     abstract NotificationWork.NotificationReceiver notificationWorkBroadcastReceiver();
     abstract NotificationWork.NotificationReceiver notificationWorkBroadcastReceiver();
 
 

+ 6 - 0
app/src/main/java/com/nextcloud/client/jobs/BackgroundJobFactory.kt

@@ -23,6 +23,7 @@ import com.nextcloud.client.documentscan.GeneratePDFUseCase
 import com.nextcloud.client.documentscan.GeneratePdfFromImagesWork
 import com.nextcloud.client.documentscan.GeneratePdfFromImagesWork
 import com.nextcloud.client.integrations.deck.DeckApi
 import com.nextcloud.client.integrations.deck.DeckApi
 import com.nextcloud.client.jobs.download.FileDownloadWorker
 import com.nextcloud.client.jobs.download.FileDownloadWorker
+import com.nextcloud.client.jobs.offlineOperations.OfflineOperationsWorker
 import com.nextcloud.client.jobs.upload.FileUploadWorker
 import com.nextcloud.client.jobs.upload.FileUploadWorker
 import com.nextcloud.client.logger.Logger
 import com.nextcloud.client.logger.Logger
 import com.nextcloud.client.network.ConnectivityService
 import com.nextcloud.client.network.ConnectivityService
@@ -95,12 +96,17 @@ class BackgroundJobFactory @Inject constructor(
                 GeneratePdfFromImagesWork::class -> createPDFGenerateWork(context, workerParameters)
                 GeneratePdfFromImagesWork::class -> createPDFGenerateWork(context, workerParameters)
                 HealthStatusWork::class -> createHealthStatusWork(context, workerParameters)
                 HealthStatusWork::class -> createHealthStatusWork(context, workerParameters)
                 TestJob::class -> createTestJob(context, workerParameters)
                 TestJob::class -> createTestJob(context, workerParameters)
+                OfflineOperationsWorker::class -> createOfflineOperationsWorker(context, workerParameters)
                 InternalTwoWaySyncWork::class -> createInternalTwoWaySyncWork(context, workerParameters)
                 InternalTwoWaySyncWork::class -> createInternalTwoWaySyncWork(context, workerParameters)
                 else -> null // caller falls back to default factory
                 else -> null // caller falls back to default factory
             }
             }
         }
         }
     }
     }
 
 
+    private fun createOfflineOperationsWorker(context: Context, params: WorkerParameters): ListenableWorker {
+        return OfflineOperationsWorker(accountManager.user, context, connectivityService, viewThemeUtils.get(), params)
+    }
+
     private fun createFilesExportWork(context: Context, params: WorkerParameters): ListenableWorker {
     private fun createFilesExportWork(context: Context, params: WorkerParameters): ListenableWorker {
         return FilesExportWork(
         return FilesExportWork(
             context,
             context,

+ 2 - 0
app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManager.kt

@@ -168,5 +168,7 @@ interface BackgroundJobManager {
     fun schedulePeriodicHealthStatus()
     fun schedulePeriodicHealthStatus()
     fun startHealthStatus()
     fun startHealthStatus()
     fun bothFilesSyncJobsRunning(syncedFolderID: Long): Boolean
     fun bothFilesSyncJobsRunning(syncedFolderID: Long): Boolean
+    fun startOfflineOperations()
+    fun startPeriodicallyOfflineOperation()
     fun scheduleInternal2WaySync()
     fun scheduleInternal2WaySync()
 }
 }

+ 13 - 1
app/src/main/java/com/nextcloud/client/jobs/BackgroundJobManagerImpl.kt

@@ -26,6 +26,7 @@ import com.nextcloud.client.core.Clock
 import com.nextcloud.client.di.Injectable
 import com.nextcloud.client.di.Injectable
 import com.nextcloud.client.documentscan.GeneratePdfFromImagesWork
 import com.nextcloud.client.documentscan.GeneratePdfFromImagesWork
 import com.nextcloud.client.jobs.download.FileDownloadWorker
 import com.nextcloud.client.jobs.download.FileDownloadWorker
+import com.nextcloud.client.jobs.offlineOperations.OfflineOperationsWorker
 import com.nextcloud.client.jobs.upload.FileUploadWorker
 import com.nextcloud.client.jobs.upload.FileUploadWorker
 import com.nextcloud.client.preferences.AppPreferences
 import com.nextcloud.client.preferences.AppPreferences
 import com.nextcloud.utils.extensions.isWorkRunning
 import com.nextcloud.utils.extensions.isWorkRunning
@@ -80,7 +81,7 @@ internal class BackgroundJobManagerImpl(
         const val JOB_PDF_GENERATION = "pdf_generation"
         const val JOB_PDF_GENERATION = "pdf_generation"
         const val JOB_IMMEDIATE_CALENDAR_BACKUP = "immediate_calendar_backup"
         const val JOB_IMMEDIATE_CALENDAR_BACKUP = "immediate_calendar_backup"
         const val JOB_IMMEDIATE_FILES_EXPORT = "immediate_files_export"
         const val JOB_IMMEDIATE_FILES_EXPORT = "immediate_files_export"
-
+        const val JOB_OFFLINE_OPERATIONS = "offline_operations"
         const val JOB_PERIODIC_HEALTH_STATUS = "periodic_health_status"
         const val JOB_PERIODIC_HEALTH_STATUS = "periodic_health_status"
         const val JOB_IMMEDIATE_HEALTH_STATUS = "immediate_health_status"
         const val JOB_IMMEDIATE_HEALTH_STATUS = "immediate_health_status"
 
 
@@ -411,6 +412,17 @@ internal class BackgroundJobManagerImpl(
             workManager.isWorkRunning(JOB_IMMEDIATE_FILES_SYNC + "_" + syncedFolderID)
             workManager.isWorkRunning(JOB_IMMEDIATE_FILES_SYNC + "_" + syncedFolderID)
     }
     }
 
 
+    override fun startOfflineOperations() {
+        val request = oneTimeRequestBuilder(OfflineOperationsWorker::class, JOB_OFFLINE_OPERATIONS)
+            .build()
+
+        workManager.enqueueUniqueWork(
+            JOB_OFFLINE_OPERATIONS,
+            ExistingWorkPolicy.REPLACE,
+            request
+        )
+    }
+
     override fun schedulePeriodicFilesSyncJob(syncedFolderID: Long) {
     override fun schedulePeriodicFilesSyncJob(syncedFolderID: Long) {
         val arguments = Data.Builder()
         val arguments = Data.Builder()
             .putLong(FilesSyncWork.SYNCED_FOLDER_ID, syncedFolderID)
             .putLong(FilesSyncWork.SYNCED_FOLDER_ID, syncedFolderID)

+ 78 - 0
app/src/main/java/com/nextcloud/client/jobs/offlineOperations/OfflineOperationsWorker.kt

@@ -0,0 +1,78 @@
+/*
+ * Nextcloud - Android Client
+ *
+ * SPDX-FileCopyrightText: 2024 Your Name <your@email.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+package com.nextcloud.client.jobs.offlineOperations
+
+import android.content.Context
+import androidx.work.CoroutineWorker
+import androidx.work.WorkerParameters
+import com.nextcloud.client.account.User
+import com.nextcloud.client.network.ClientFactoryImpl
+import com.nextcloud.model.OfflineOperationType
+import com.owncloud.android.datamodel.FileDataStorageManager
+import com.owncloud.android.lib.common.OwnCloudClient
+import com.owncloud.android.lib.common.utils.Log_OC
+import com.owncloud.android.operations.CreateFolderOperation
+
+class OfflineOperationsWorker(
+    private val user: User,
+    private val context: Context,
+    params: WorkerParameters
+) : CoroutineWorker(context, params) {
+
+    companion object {
+        private val TAG = OfflineOperationsWorker::class.java.simpleName
+    }
+
+    private val fileDataStorageManager = FileDataStorageManager(user, context.contentResolver)
+    private val clientFactory = ClientFactoryImpl(context)
+
+    override suspend fun doWork(): Result {
+        val client = clientFactory.create(user)
+
+        val offlineOperations = fileDataStorageManager.offlineOperationDao.getAll()
+        offlineOperations.forEach { operation ->
+            when (operation.type) {
+                is OfflineOperationType.CreateFolder -> {
+                    val createFolderOperation = (operation.type as OfflineOperationType.CreateFolder)
+                    createFolder(createFolderOperation, client, onCompleted = {
+                        fileDataStorageManager.offlineOperationDao.delete(operation)
+                    })
+                }
+
+                null -> {
+                    Log_OC.d(TAG, "OfflineOperationsWorker terminated, unsupported operation type")
+                    return Result.failure()
+                }
+            }
+        }
+
+        Log_OC.d(TAG, "OfflineOperationsWorker successfully completed")
+        return Result.success()
+    }
+
+    @Suppress("TooGenericExceptionCaught", "Deprecation")
+    private fun createFolder(
+        operation: OfflineOperationType.CreateFolder,
+        client: OwnCloudClient,
+        onCompleted: () -> Unit
+    ) {
+        val createFolderOperation = CreateFolderOperation(operation.path, user, context, fileDataStorageManager)
+
+        try {
+            val result = createFolderOperation.execute(client)
+            if (result.isSuccess) {
+                Log_OC.d(TAG, "Create folder operation completed, folder path: ${operation.path}")
+                onCompleted()
+            } else {
+                Log_OC.d(TAG, "Create folder operation terminated, result: $result")
+            }
+        } catch (e: Exception) {
+            Log_OC.d(TAG, "Error caught at createFolder: $e")
+        }
+    }
+}

+ 7 - 1
app/src/main/java/com/nextcloud/receiver/NetworkChangeReceiver.kt

@@ -12,11 +12,17 @@ import android.content.Context
 import android.content.Intent
 import android.content.Intent
 import android.net.ConnectivityManager
 import android.net.ConnectivityManager
 import android.net.NetworkCapabilities
 import android.net.NetworkCapabilities
+import com.nextcloud.client.jobs.BackgroundJobManager
 import com.owncloud.android.MainApp
 import com.owncloud.android.MainApp
+import javax.inject.Inject
 
 
 class NetworkChangeReceiver : BroadcastReceiver() {
 class NetworkChangeReceiver : BroadcastReceiver() {
+
+    @Inject
+    lateinit var backgroundJobManager: BackgroundJobManager
+
     override fun onReceive(context: Context, intent: Intent?) {
     override fun onReceive(context: Context, intent: Intent?) {
-        MainApp.setIsNetworkAvailable(isNetworkAvailable(context))
+        MainApp.setIsNetworkAvailable(isNetworkAvailable(context), backgroundJobManager)
     }
     }
 
 
     private fun isNetworkAvailable(context: Context): Boolean {
     private fun isNetworkAvailable(context: Context): Boolean {

+ 4 - 2
app/src/main/java/com/owncloud/android/MainApp.java

@@ -237,9 +237,11 @@ public class MainApp extends Application implements HasAndroidInjector {
         registerReceiver(networkChangeReceiver, filter);
         registerReceiver(networkChangeReceiver, filter);
     }
     }
 
 
-    public static void setIsNetworkAvailable(boolean value) {
-        // TODO start pending operations if isNetworkAvailable
+    public static void setIsNetworkAvailable(boolean value, BackgroundJobManager backgroundJobManager) {
         isNetworkAvailable = value;
         isNetworkAvailable = value;
+        if (isNetworkAvailable) {
+            backgroundJobManager.startOfflineOperations();
+        }
     }
     }
 
 
     public static boolean isNetworkAvailable() {
     public static boolean isNetworkAvailable() {

+ 1 - 1
app/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java

@@ -97,7 +97,7 @@ public class FileDataStorageManager {
     private final ContentProviderClient contentProviderClient;
     private final ContentProviderClient contentProviderClient;
     private final User user;
     private final User user;
 
 
-    private final OfflineOperationDao offlineOperationDao = NextcloudDatabase.getInstance(MainApp.getAppContext()).offlineOperationDao();
+    public final OfflineOperationDao offlineOperationDao = NextcloudDatabase.getInstance(MainApp.getAppContext()).offlineOperationDao();
     private final FileDao fileDao = NextcloudDatabase.getInstance(MainApp.getAppContext()).fileDao();
     private final FileDao fileDao = NextcloudDatabase.getInstance(MainApp.getAppContext()).fileDao();
     private final Gson gson = new Gson();
     private final Gson gson = new Gson();