فهرست منبع

Add callback for isNetworkAndServerAvailable, remove repeated thread handling logic

Signed-off-by: alperozturk <alper_ozturk@proton.me>
alperozturk 9 ماه پیش
والد
کامیت
b2829124eb

+ 2 - 2
app/src/androidTest/java/com/owncloud/android/AbstractIT.java

@@ -377,8 +377,8 @@ public abstract class AbstractIT {
     public void uploadOCUpload(OCUpload ocUpload) {
         ConnectivityService connectivityServiceMock = new ConnectivityService() {
             @Override
-            public boolean isNetworkAndServerAvailable() throws NetworkOnMainThreadException {
-                return false;
+            public void isNetworkAndServerAvailable(@NonNull GenericCallback<Boolean> callback) {
+
             }
 
             @Override

+ 2 - 2
app/src/androidTest/java/com/owncloud/android/AbstractOnServerIT.java

@@ -189,8 +189,8 @@ public abstract class AbstractOnServerIT extends AbstractIT {
     public void uploadOCUpload(OCUpload ocUpload, int localBehaviour) {
         ConnectivityService connectivityServiceMock = new ConnectivityService() {
             @Override
-            public boolean isNetworkAndServerAvailable() throws NetworkOnMainThreadException {
-                return false;
+            public void isNetworkAndServerAvailable(@NonNull GenericCallback<Boolean> callback) {
+
             }
 
             @Override

+ 6 - 6
app/src/androidTest/java/com/owncloud/android/UploadIT.java

@@ -59,8 +59,8 @@ public class UploadIT extends AbstractOnServerIT {
 
     private ConnectivityService connectivityServiceMock = new ConnectivityService() {
         @Override
-        public boolean isNetworkAndServerAvailable() throws NetworkOnMainThreadException {
-            return false;
+        public void isNetworkAndServerAvailable(@NonNull GenericCallback<Boolean> callback) {
+
         }
 
         @Override
@@ -282,8 +282,8 @@ public class UploadIT extends AbstractOnServerIT {
     public void testUploadOnWifiOnlyButNoWifi() {
         ConnectivityService connectivityServiceMock = new ConnectivityService() {
             @Override
-            public boolean isNetworkAndServerAvailable() throws NetworkOnMainThreadException {
-                return false;
+            public void isNetworkAndServerAvailable(@NonNull GenericCallback<Boolean> callback) {
+
             }
 
             @Override
@@ -371,8 +371,8 @@ public class UploadIT extends AbstractOnServerIT {
     public void testUploadOnWifiOnlyButMeteredWifi() {
         ConnectivityService connectivityServiceMock = new ConnectivityService() {
             @Override
-            public boolean isNetworkAndServerAvailable() throws NetworkOnMainThreadException {
-                return false;
+            public void isNetworkAndServerAvailable(@NonNull GenericCallback<Boolean> callback) {
+
             }
 
             @Override

+ 1 - 3
app/src/androidTest/java/com/owncloud/android/files/services/FileUploaderIT.kt

@@ -34,9 +34,7 @@ abstract class FileUploaderIT : AbstractOnServerIT() {
     private var uploadsStorageManager: UploadsStorageManager? = null
 
     private val connectivityServiceMock: ConnectivityService = object : ConnectivityService {
-        override fun isNetworkAndServerAvailable(): Boolean {
-            return false
-        }
+        override fun isNetworkAndServerAvailable(callback: ConnectivityService.GenericCallback<Boolean>) = Unit
 
         override fun isConnected(): Boolean {
             return false

+ 2 - 4
app/src/debug/java/com/nextcloud/test/TestActivity.kt

@@ -42,6 +42,8 @@ class TestActivity :
     private lateinit var binding: TestLayoutBinding
 
     val connectivityServiceMock: ConnectivityService = object : ConnectivityService {
+        override fun isNetworkAndServerAvailable(callback: ConnectivityService.GenericCallback<Boolean>) = Unit
+
         override fun isConnected(): Boolean {
             return false
         }
@@ -53,10 +55,6 @@ class TestActivity :
         override fun getConnectivity(): Connectivity {
             return Connectivity.CONNECTED_WIFI
         }
-
-        override fun isNetworkAndServerAvailable(): Boolean {
-            return false
-        }
     }
 
     override fun onCreate(savedInstanceState: Bundle?) {

+ 9 - 1
app/src/main/java/com/nextcloud/client/jobs/offlineOperations/OfflineOperationsWorker.kt

@@ -29,6 +29,8 @@ import com.owncloud.android.utils.theme.ViewThemeUtils
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.withContext
+import kotlin.coroutines.resume
+import kotlin.coroutines.suspendCoroutine
 
 class OfflineOperationsWorker(
     private val user: User,
@@ -59,7 +61,7 @@ class OfflineOperationsWorker(
                 "\n-----------------------------------"
         )
 
-        if (!connectivityService.isNetworkAndServerAvailable()) {
+        if (!isNetworkAndServerAvailable()) {
             Log_OC.d(TAG, "OfflineOperationsWorker cancelled, no internet connection")
             return@coroutineScope Result.retry()
         }
@@ -101,6 +103,12 @@ class OfflineOperationsWorker(
         }
     }
 
+    private suspend fun isNetworkAndServerAvailable(): Boolean = suspendCoroutine { continuation ->
+        connectivityService.isNetworkAndServerAvailable { result ->
+            continuation.resume(result)
+        }
+    }
+
     @Suppress("Deprecation")
     private suspend fun executeOperation(
         operation: OfflineOperationEntity,

+ 14 - 8
app/src/main/java/com/nextcloud/client/network/ConnectivityService.java

@@ -6,7 +6,8 @@
  */
 package com.nextcloud.client.network;
 
-import android.os.NetworkOnMainThreadException;
+
+import androidx.annotation.NonNull;
 
 /**
  * This service provides information about current network connectivity
@@ -17,16 +18,12 @@ public interface ConnectivityService {
      * Checks the availability of the server and the device's internet connection.
      * <p>
      * This method performs a network request to verify if the server is accessible and
-     * checks if the device has an active internet connection. Due to the network operations involved,
-     * this method should be executed on a background thread to avoid blocking the main thread.
+     * checks if the device has an active internet connection.
      * </p>
      *
-     * @return {@code true} if the server is accessible and the device has an internet connection;
-     *         {@code false} otherwise.
-     *
-     * @throws NetworkOnMainThreadException if this function runs on main thread.
+     * @param callback A callback to handle the result of the network and server availability check.
      */
-    boolean isNetworkAndServerAvailable() throws NetworkOnMainThreadException;
+    void isNetworkAndServerAvailable(@NonNull GenericCallback<Boolean> callback);
 
     boolean isConnected();
 
@@ -45,4 +42,13 @@ public interface ConnectivityService {
      * @return Network connectivity status in platform-agnostic format
      */
     Connectivity getConnectivity();
+
+    /**
+     * Callback interface for asynchronous results.
+     *
+     * @param <T> The type of result returned by the callback.
+     */
+    interface GenericCallback<T> {
+        void onComplete(T result);
+    }
 }

+ 17 - 9
app/src/main/java/com/nextcloud/client/network/ConnectivityServiceImpl.java

@@ -13,7 +13,8 @@ import android.net.ConnectivityManager;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
-import android.os.NetworkOnMainThreadException;
+import android.os.Handler;
+import android.os.Looper;
 
 import com.nextcloud.client.account.Server;
 import com.nextcloud.client.account.UserAccountManager;
@@ -23,6 +24,7 @@ import com.owncloud.android.lib.common.utils.Log_OC;
 
 import org.apache.commons.httpclient.HttpStatus;
 
+import androidx.annotation.NonNull;
 import androidx.core.net.ConnectivityManagerCompat;
 import kotlin.jvm.functions.Function1;
 
@@ -36,6 +38,7 @@ class ConnectivityServiceImpl implements ConnectivityService {
     private final ClientFactory clientFactory;
     private final GetRequestBuilder requestBuilder;
     private final WalledCheckCache walledCheckCache;
+    private final Handler mainThreadHandler = new Handler(Looper.getMainLooper());
 
     static class GetRequestBuilder implements Function1<String, GetMethod> {
         @Override
@@ -57,16 +60,21 @@ class ConnectivityServiceImpl implements ConnectivityService {
     }
 
     @Override
-    public boolean isNetworkAndServerAvailable() throws NetworkOnMainThreadException {
-        Network activeNetwork = platformConnectivityManager.getActiveNetwork();
-        NetworkCapabilities networkCapabilities = platformConnectivityManager.getNetworkCapabilities(activeNetwork);
-        boolean hasInternet = networkCapabilities != null && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+    public void isNetworkAndServerAvailable(@NonNull GenericCallback<Boolean> callback) {
+        new Thread(() -> {
+            Network activeNetwork = platformConnectivityManager.getActiveNetwork();
+            NetworkCapabilities networkCapabilities = platformConnectivityManager.getNetworkCapabilities(activeNetwork);
+            boolean hasInternet = networkCapabilities != null && networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
 
-        if (!hasInternet) {
-            return false;
-        }
+            boolean result;
+            if (hasInternet) {
+                result = !isInternetWalled();
+            } else {
+                result = false;
+            }
 
-        return !isInternetWalled();
+            mainThreadHandler.post(() -> callback.onComplete(result));
+        }).start();
     }
 
     @Override

+ 2 - 11
app/src/main/java/com/nextcloud/receiver/NetworkChangeReceiver.kt

@@ -11,9 +11,6 @@ import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
 import com.nextcloud.client.network.ConnectivityService
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
 
 interface NetworkChangeListener {
     fun networkAndServerConnectionListener(isNetworkAndServerAvailable: Boolean)
@@ -24,15 +21,9 @@ class NetworkChangeReceiver(
     private val connectivityService: ConnectivityService
 ) : BroadcastReceiver() {
 
-    private val scope = CoroutineScope(Dispatchers.IO)
-
     override fun onReceive(context: Context, intent: Intent?) {
-        scope.launch {
-            val isNetworkAndServerAvailable = connectivityService.isNetworkAndServerAvailable()
-
-            launch(Dispatchers.Main) {
-                listener.networkAndServerConnectionListener(isNetworkAndServerAvailable)
-            }
+        connectivityService.isNetworkAndServerAvailable {
+            listener.networkAndServerConnectionListener(it)
         }
     }
 }

+ 16 - 21
app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java

@@ -59,6 +59,7 @@ import com.nextcloud.client.jobs.upload.FileUploadHelper;
 import com.nextcloud.client.jobs.upload.FileUploadWorker;
 import com.nextcloud.client.media.PlayerServiceConnection;
 import com.nextcloud.client.network.ClientFactory;
+import com.nextcloud.client.network.ConnectivityService;
 import com.nextcloud.client.preferences.AppPreferences;
 import com.nextcloud.client.utils.IntentUtil;
 import com.nextcloud.model.WorkerState;
@@ -949,27 +950,21 @@ public class FileDisplayActivity extends FileActivity
                 default -> FileUploadWorker.LOCAL_BEHAVIOUR_FORGET;
             };
 
-            new Thread(() -> {
-                boolean isNetworkAndServerAvailable = connectivityService.isNetworkAndServerAvailable();
-
-                runOnUiThread(() -> {
-                    if (isNetworkAndServerAvailable) {
-                        FileUploadHelper.Companion.instance().uploadNewFiles(getUser().orElseThrow(RuntimeException::new),
-                                                                             filePaths,
-                                                                             decryptedRemotePaths,
-                                                                             behaviour,
-                                                                             true,
-                                                                             UploadFileOperation.CREATED_BY_USER,
-                                                                             false,
-                                                                             false,
-                                                                             NameCollisionPolicy.ASK_USER);
-                    } else {
-                        fileDataStorageManager.addCreateFileOfflineOperation(filePaths, decryptedRemotePaths);
-                    }
-                });
-            }).start();
-
-
+            connectivityService.isNetworkAndServerAvailable(result -> {
+                if (result) {
+                    FileUploadHelper.Companion.instance().uploadNewFiles(getUser().orElseThrow(RuntimeException::new),
+                                                                         filePaths,
+                                                                         decryptedRemotePaths,
+                                                                         behaviour,
+                                                                         true,
+                                                                         UploadFileOperation.CREATED_BY_USER,
+                                                                         false,
+                                                                         false,
+                                                                         NameCollisionPolicy.ASK_USER);
+                } else {
+                    fileDataStorageManager.addCreateFileOfflineOperation(filePaths, decryptedRemotePaths);
+                }
+            });
         } else {
             Log_OC.d(TAG, "User clicked on 'Update' with no selection");
             DisplayUtils.showSnackMessage(this, R.string.filedisplay_no_file_selected);

+ 3 - 8
app/src/main/java/com/owncloud/android/ui/dialog/CreateFolderDialogFragment.kt

@@ -19,7 +19,6 @@ import android.view.View
 import android.widget.TextView
 import androidx.appcompat.app.AlertDialog
 import androidx.fragment.app.DialogFragment
-import androidx.lifecycle.lifecycleScope
 import com.google.android.material.button.MaterialButton
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import com.google.common.collect.Sets
@@ -40,8 +39,6 @@ import com.owncloud.android.ui.activity.FileDisplayActivity
 import com.owncloud.android.utils.DisplayUtils
 import com.owncloud.android.utils.KeyboardUtils
 import com.owncloud.android.utils.theme.ViewThemeUtils
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
 import javax.inject.Inject
 
 /**
@@ -184,8 +181,8 @@ class CreateFolderDialogFragment : DialogFragment(), DialogInterface.OnClickList
             }
 
             val path = parentFolder?.decryptedRemotePath + newFolderName + OCFile.PATH_SEPARATOR
-            lifecycleScope.launch(Dispatchers.IO) {
-                if (connectivityService.isNetworkAndServerAvailable()) {
+            connectivityService.isNetworkAndServerAvailable { result ->
+                if (result) {
                     typedActivity<ComponentsGetter>()?.fileOperationsHelper?.createFolder(path)
                 } else {
                     Log_OC.d(TAG, "Network not available, creating offline operation")
@@ -196,9 +193,7 @@ class CreateFolderDialogFragment : DialogFragment(), DialogInterface.OnClickList
                         parentFolder?.fileId
                     )
 
-                    launch(Dispatchers.Main) {
-                        (requireActivity() as? FileDisplayActivity)?.syncAndUpdateFolder(true)
-                    }
+                    (requireActivity() as? FileDisplayActivity)?.syncAndUpdateFolder(true)
                 }
             }
         }

+ 15 - 26
app/src/main/java/com/owncloud/android/ui/fragment/OCFileListBottomSheetDialog.java

@@ -7,8 +7,6 @@
 package com.owncloud.android.ui.fragment;
 
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
 import android.view.View;
 
 import com.google.android.material.bottomsheet.BottomSheetDialog;
@@ -214,31 +212,22 @@ public class OCFileListBottomSheetDialog extends BottomSheetDialog implements In
     }
 
     private void filterActionsForOfflineOperations() {
-        if (file == null) return;
-
-        if (!file.isOfflineOperation() || file.isRootDirectory()) {
-            return;
-        }
-        // TODO add callback for isNetworkAndServerAvailable
-        new Thread(() -> {
-            boolean isNetworkAndServerAvailable = fileActivity.connectivityService.isNetworkAndServerAvailable();
-            new Handler(Looper.getMainLooper()).post(() -> {
-                if (file.isRootDirectory()) {
-                    return;
-                }
+        fileActivity.connectivityService.isNetworkAndServerAvailable(result -> {
+            if (file.isRootDirectory()) {
+                return;
+            }
 
-                if (!isNetworkAndServerAvailable || file.isOfflineOperation()) {
-                    binding.menuCreateRichWorkspace.setVisibility(View.GONE);
-                    binding.menuUploadFromApp.setVisibility(View.GONE);
-                    binding.menuDirectCameraUpload.setVisibility(View.GONE);
-                    binding.menuScanDocUpload.setVisibility(View.GONE);
-                    binding.menuNewDocument.setVisibility(View.GONE);
-                    binding.menuNewSpreadsheet.setVisibility(View.GONE);
-                    binding.menuNewPresentation.setVisibility(View.GONE);
-                    binding.creatorsContainer.setVisibility(View.GONE);
-                }
-            });
-        }).start();
+            if (!result || file.isOfflineOperation()) {
+                binding.menuCreateRichWorkspace.setVisibility(View.GONE);
+                binding.menuUploadFromApp.setVisibility(View.GONE);
+                binding.menuDirectCameraUpload.setVisibility(View.GONE);
+                binding.menuScanDocUpload.setVisibility(View.GONE);
+                binding.menuNewDocument.setVisibility(View.GONE);
+                binding.menuNewSpreadsheet.setVisibility(View.GONE);
+                binding.menuNewPresentation.setVisibility(View.GONE);
+                binding.creatorsContainer.setVisibility(View.GONE);
+            }
+        });
     }
 
     @Override