From d2bce5529f79cc36e3e83c8fa20a722182a25a63 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Nov 2026 15:58:38 +0100 Subject: [PATCH 01/16] remove unused functions, variables Signed-off-by: alperozturk96 --- .../main/java/com/owncloud/android/MainApp.kt | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/MainApp.kt b/app/src/main/java/com/owncloud/android/MainApp.kt index 0b20104cda47..c82d557e16ab 100644 --- a/app/src/main/java/com/owncloud/android/MainApp.kt +++ b/app/src/main/java/com/owncloud/android/MainApp.kt @@ -72,7 +72,6 @@ import dagger.android.DispatchingAndroidInjector import dagger.android.HasAndroidInjector import edu.umd.cs.findbugs.annotations.SuppressFBWarnings import org.conscrypt.Conscrypt -import org.greenrobot.eventbus.EventBus import java.lang.ref.WeakReference import java.security.NoSuchAlgorithmException import java.security.Security @@ -121,9 +120,6 @@ open class MainApp : @Inject lateinit var clock: Clock - @Inject - lateinit var eventBus: EventBus - @Inject lateinit var migrationsManager: MigrationsManager @@ -535,11 +531,6 @@ open class MainApp : @JvmStatic fun getAppContext(): Context = appContext!!.get()!! - @JvmStatic - fun setAppContext(context: Context?) { - appContext = WeakReference(context) - } - @JvmStatic fun getStoragePath(): String? = storagePath @@ -559,14 +550,6 @@ open class MainApp : val authTokenType: String get() = string(R.string.authority) - @JvmStatic - val dbFile: String - get() = string(R.string.db_file) - - @JvmStatic - val dbName: String - get() = string(R.string.db_name) - @JvmStatic val dataFolder: String get() = string(R.string.data_folder) From d1897a7f7a88bdc8421c04d308a5d78846e2a6a1 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Nov 2026 16:07:42 +0100 Subject: [PATCH 02/16] make context non-nullable, use injections instead construction Signed-off-by: alperozturk96 --- .../main/java/com/owncloud/android/MainApp.kt | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/MainApp.kt b/app/src/main/java/com/owncloud/android/MainApp.kt index c82d557e16ab..5aa081f415a1 100644 --- a/app/src/main/java/com/owncloud/android/MainApp.kt +++ b/app/src/main/java/com/owncloud/android/MainApp.kt @@ -50,7 +50,7 @@ import com.nextcloud.utils.extensions.showToast import com.nextcloud.utils.mdm.MDMConfig import com.owncloud.android.authentication.GlobalPassCodeProtectionCallbacks import com.owncloud.android.authentication.PassCodeManager -import com.owncloud.android.datamodel.ArbitraryDataProviderImpl +import com.owncloud.android.datamodel.ArbitraryDataProvider import com.owncloud.android.datamodel.ReceiverFlag import com.owncloud.android.datamodel.SyncedFolderProvider import com.owncloud.android.datamodel.ThumbnailsCacheManager @@ -72,7 +72,6 @@ import dagger.android.DispatchingAndroidInjector import dagger.android.HasAndroidInjector import edu.umd.cs.findbugs.annotations.SuppressFBWarnings import org.conscrypt.Conscrypt -import java.lang.ref.WeakReference import java.security.NoSuchAlgorithmException import java.security.Security import javax.inject.Inject @@ -138,6 +137,9 @@ open class MainApp : @Inject lateinit var viewThemeUtilsProvider: Provider + @Inject + lateinit var arbitraryDataProvider: ArbitraryDataProvider + private val restrictionsFilter = IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED) private val restrictionsReceiver = object : BroadcastReceiver() { @@ -185,7 +187,6 @@ open class MainApp : @SuppressFBWarnings("ST") override fun onCreate() { enableStrictMode() - val viewThemeUtils = viewThemeUtilsProvider.get() setAppTheme(preferences.getDarkThemeMode()) super.onCreate() @@ -217,10 +218,9 @@ open class MainApp : powerManagementService, backgroundJobManager, clock, - viewThemeUtils, walledCheckCache ) - initContactsBackup(accountManager, backgroundJobManager) + initContactsBackup(arbitraryDataProvider,accountManager, backgroundJobManager) AppNotificationChannels.create(getAppContext()) scheduleBackgroundJobs() registerActivityLifecycleCallbacks(GlobalPassCodeProtectionCallbacks(onboarding, passCodeManager)) @@ -308,7 +308,7 @@ open class MainApp : OwnCloudClientManagerFactory.setProxyPort(port) Log_OC.d(TAG, "Proxy configuration successfully set") } catch (e: Resources.NotFoundException) { - Log_OC.e(TAG, "Proxy config cannot able to set due to: \$e") + Log_OC.e(TAG, "Proxy config cannot able to set due to: $e") } } @@ -362,7 +362,7 @@ open class MainApp : private fun disableDeathOnFileUriExposure() { try { StrictMode::class.java.getMethod("disableDeathOnFileUriExposure").invoke(null) - } catch (e: Exception) { + } catch (_: Exception) { Log_OC.d(DEBUG_TAG, "Failed to disable uri exposure") } } @@ -420,7 +420,7 @@ open class MainApp : private const val HIGHEST_SECURITY_PROVIDER_POSITION = 1 private const val NO_PACKAGE_INFO_FLAGS = 0 - private var appContext: WeakReference? = null + private lateinit var appContext: Context private var storagePath: String? = null private var appComponent: AppComponent? = null @@ -433,7 +433,7 @@ open class MainApp : private set private fun initGlobalContext(context: Context) { - appContext = WeakReference(context) + appContext = context } @JvmStatic @@ -448,12 +448,11 @@ open class MainApp : get() = getAppContext().resources.getBoolean(R.bool.is_branded_plus_client) @JvmStatic - fun initContactsBackup(accountManager: UserAccountManager?, backgroundJobManager: BackgroundJobManager?) { - if (accountManager == null || backgroundJobManager == null) { - return - } - - val arbitraryDataProvider = ArbitraryDataProviderImpl(getAppContext()) + fun initContactsBackup( + arbitraryDataProvider: ArbitraryDataProvider, + accountManager: UserAccountManager, + backgroundJobManager: BackgroundJobManager + ) { accountManager.allUsers .filter { arbitraryDataProvider.getBooleanValue( @@ -474,7 +473,6 @@ open class MainApp : powerManagementService: PowerManagementService, backgroundJobManager: BackgroundJobManager, clock: Clock, - viewThemeUtils: ViewThemeUtils?, walledCheckCache: WalledCheckCache? ) { val appContext = getAppContext() @@ -529,7 +527,7 @@ open class MainApp : fun string(@StringRes id: Int, args: Any?): String = getAppContext().getString(id, args) @JvmStatic - fun getAppContext(): Context = appContext!!.get()!! + fun getAppContext(): Context = appContext @JvmStatic fun getStoragePath(): String? = storagePath From ae9d59869f5a314898214a26c2ed37696d50f8f4 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Nov 2026 16:07:49 +0100 Subject: [PATCH 03/16] pass ArbitraryDataProvider Signed-off-by: alperozturk96 --- .../owncloud/android/files/BootupBroadcastReceiver.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java b/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java index 22cae6e42047..bc9feabdf164 100644 --- a/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java +++ b/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java @@ -23,9 +23,9 @@ import com.nextcloud.client.network.WalledCheckCache; import com.nextcloud.client.preferences.AppPreferences; import com.owncloud.android.MainApp; +import com.owncloud.android.datamodel.ArbitraryDataProvider; import com.owncloud.android.datamodel.UploadsStorageManager; import com.owncloud.android.lib.common.utils.Log_OC; -import com.owncloud.android.utils.theme.ViewThemeUtils; import javax.inject.Inject; @@ -39,6 +39,7 @@ public class BootupBroadcastReceiver extends BroadcastReceiver { private static final String TAG = BootupBroadcastReceiver.class.getSimpleName(); + @Inject ArbitraryDataProvider arbitraryDataProvider; @Inject AppPreferences preferences; @Inject UserAccountManager accountManager; @Inject UploadsStorageManager uploadsStorageManager; @@ -46,7 +47,6 @@ public class BootupBroadcastReceiver extends BroadcastReceiver { @Inject PowerManagementService powerManagementService; @Inject BackgroundJobManager backgroundJobManager; @Inject Clock clock; - @Inject ViewThemeUtils viewThemeUtils; @Inject WalledCheckCache walledCheckCache; /** @@ -68,12 +68,11 @@ public void onReceive(Context context, Intent intent) { powerManagementService, backgroundJobManager, clock, - viewThemeUtils, walledCheckCache); Log_OC.d(TAG, "scheduleContentObserverJob, called"); backgroundJobManager.scheduleContentObserverJob(); backgroundJobManager.schedulePeriodicAutoUpload(); - MainApp.initContactsBackup(accountManager, backgroundJobManager); + MainApp.initContactsBackup(arbitraryDataProvider, accountManager, backgroundJobManager); } else { Log_OC.d(TAG, "Getting wrong intent: " + intent.getAction()); } From 05785d87d57c28f509d33b985c8f9713af90ddf5 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Nov 2026 16:09:31 +0100 Subject: [PATCH 04/16] Rename .java to .kt Signed-off-by: alperozturk96 --- .../{BootupBroadcastReceiver.java => BootupBroadcastReceiver.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/src/main/java/com/owncloud/android/files/{BootupBroadcastReceiver.java => BootupBroadcastReceiver.kt} (100%) diff --git a/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java b/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.kt similarity index 100% rename from app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.java rename to app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.kt From 518a16207ffe35d11d5243a8e03a6f2954c94159 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Nov 2026 16:09:31 +0100 Subject: [PATCH 05/16] convert BootupBroadcastReceiver to kotlin Signed-off-by: alperozturk96 --- .../android/files/BootupBroadcastReceiver.kt | 157 ++++++++++-------- 1 file changed, 84 insertions(+), 73 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.kt b/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.kt index bc9feabdf164..41b5194de6d6 100644 --- a/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.kt +++ b/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.kt @@ -1,80 +1,91 @@ /* * Nextcloud - Android Client * - * SPDX-FileCopyrightText: 2022 Tobias Kaminsky - * SPDX-FileCopyrightText: 2020 Chris Narkiewicz - * SPDX-FileCopyrightText: 2017 Mario Danic - * SPDX-FileCopyrightText: 2015 ownCloud Inc. - * SPDX-FileCopyrightText: 2014 David A. Velasco - * SPDX-FileCopyrightText: 2012 Bartosz Przybylski - * SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only) + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later */ -package com.owncloud.android.files; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; - -import com.nextcloud.client.account.UserAccountManager; -import com.nextcloud.client.core.Clock; -import com.nextcloud.client.device.PowerManagementService; -import com.nextcloud.client.jobs.BackgroundJobManager; -import com.nextcloud.client.network.ConnectivityService; -import com.nextcloud.client.network.WalledCheckCache; -import com.nextcloud.client.preferences.AppPreferences; -import com.owncloud.android.MainApp; -import com.owncloud.android.datamodel.ArbitraryDataProvider; -import com.owncloud.android.datamodel.UploadsStorageManager; -import com.owncloud.android.lib.common.utils.Log_OC; - -import javax.inject.Inject; - -import dagger.android.AndroidInjection; - -/** - * App-registered receiver catching the broadcast intent reporting that the system was - * just boot up. - */ -public class BootupBroadcastReceiver extends BroadcastReceiver { - - private static final String TAG = BootupBroadcastReceiver.class.getSimpleName(); - - @Inject ArbitraryDataProvider arbitraryDataProvider; - @Inject AppPreferences preferences; - @Inject UserAccountManager accountManager; - @Inject UploadsStorageManager uploadsStorageManager; - @Inject ConnectivityService connectivityService; - @Inject PowerManagementService powerManagementService; - @Inject BackgroundJobManager backgroundJobManager; - @Inject Clock clock; - @Inject WalledCheckCache walledCheckCache; - - /** - * Receives broadcast intent reporting that the system was just boot up. * - * - * @param context The context where the receiver is running. - * @param intent The intent received. - */ - @Override - public void onReceive(Context context, Intent intent) { - AndroidInjection.inject(this, context); - - if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) { - MainApp.initSyncOperations(context, - preferences, - uploadsStorageManager, - accountManager, - connectivityService, - powerManagementService, - backgroundJobManager, - clock, - walledCheckCache); - Log_OC.d(TAG, "scheduleContentObserverJob, called"); - backgroundJobManager.scheduleContentObserverJob(); - backgroundJobManager.schedulePeriodicAutoUpload(); - MainApp.initContactsBackup(arbitraryDataProvider, accountManager, backgroundJobManager); - } else { - Log_OC.d(TAG, "Getting wrong intent: " + intent.getAction()); +package com.owncloud.android.files + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.client.core.Clock +import com.nextcloud.client.device.PowerManagementService +import com.nextcloud.client.jobs.BackgroundJobManager +import com.nextcloud.client.network.ConnectivityService +import com.nextcloud.client.network.WalledCheckCache +import com.nextcloud.client.preferences.AppPreferences +import com.owncloud.android.MainApp +import com.owncloud.android.datamodel.ArbitraryDataProvider +import com.owncloud.android.datamodel.UploadsStorageManager +import com.owncloud.android.lib.common.utils.Log_OC +import dagger.android.AndroidInjection +import javax.inject.Inject + +class BootupBroadcastReceiver : BroadcastReceiver() { + + @Inject + lateinit var arbitraryDataProvider: ArbitraryDataProvider + + @Inject + lateinit var preferences: AppPreferences + + @Inject + lateinit var accountManager: UserAccountManager + + @Inject + lateinit var uploadsStorageManager: UploadsStorageManager + + @Inject + lateinit var connectivityService: ConnectivityService + + @Inject + lateinit var powerManagementService: PowerManagementService + + @Inject + lateinit var backgroundJobManager: BackgroundJobManager + + @Inject + lateinit var clock: Clock + + @Inject + lateinit var walledCheckCache: WalledCheckCache + + override fun onReceive(context: Context, intent: Intent) { + AndroidInjection.inject(this, context) + + if (intent.action != Intent.ACTION_BOOT_COMPLETED) { + Log_OC.d(TAG, "Getting wrong intent: ${intent.action}") + return } + + initSyncOperations(context) + scheduleAutoUploadJobs() + MainApp.initContactsBackup(arbitraryDataProvider, accountManager, backgroundJobManager) + } + + private fun initSyncOperations(context: Context) { + MainApp.initSyncOperations( + context, + preferences, + uploadsStorageManager, + accountManager, + connectivityService, + powerManagementService, + backgroundJobManager, + clock, + walledCheckCache + ) + } + + private fun scheduleAutoUploadJobs() { + Log_OC.d(TAG, "scheduleContentObserverJob, called") + backgroundJobManager.scheduleContentObserverJob() + backgroundJobManager.schedulePeriodicAutoUpload() + } + + companion object { + private val TAG: String = BootupBroadcastReceiver::class.java.simpleName } } From 0a40939332dd9d772bef46f4fca6dff609b311de Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Nov 2026 16:17:13 +0100 Subject: [PATCH 06/16] Rename .java to .kt Signed-off-by: alperozturk96 --- .../android/utils/{ReceiversHelper.java => ReceiversHelper.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/src/main/java/com/owncloud/android/utils/{ReceiversHelper.java => ReceiversHelper.kt} (100%) diff --git a/app/src/main/java/com/owncloud/android/utils/ReceiversHelper.java b/app/src/main/java/com/owncloud/android/utils/ReceiversHelper.kt similarity index 100% rename from app/src/main/java/com/owncloud/android/utils/ReceiversHelper.java rename to app/src/main/java/com/owncloud/android/utils/ReceiversHelper.kt From 9c9ccd05fdbeb20575cba788b90f9cbbb4462e6c Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Nov 2026 16:17:13 +0100 Subject: [PATCH 07/16] convert ReceiversHelper to kotlin Signed-off-by: alperozturk96 # Conflicts: # app/src/main/java/com/owncloud/android/MainApp.kt --- .../main/java/com/owncloud/android/MainApp.kt | 18 +- .../android/files/BootupBroadcastReceiver.kt | 9 +- .../owncloud/android/utils/ReceiversHelper.kt | 210 ++++++++---------- 3 files changed, 113 insertions(+), 124 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/MainApp.kt b/app/src/main/java/com/owncloud/android/MainApp.kt index 5aa081f415a1..2a889b125e6c 100644 --- a/app/src/main/java/com/owncloud/android/MainApp.kt +++ b/app/src/main/java/com/owncloud/android/MainApp.kt @@ -28,6 +28,7 @@ import com.nextcloud.client.core.Clock import com.nextcloud.client.device.PowerManagementService import com.nextcloud.client.di.ActivityInjector import com.nextcloud.client.di.AppComponent +import com.nextcloud.client.di.ApplicationScope import com.nextcloud.client.di.DaggerAppComponent import com.nextcloud.client.errorhandling.ExceptionHandler import com.nextcloud.client.jobs.BackgroundJobManager @@ -41,7 +42,6 @@ import com.nextcloud.client.network.WalledCheckCache import com.nextcloud.client.notifications.AppNotificationChannels import com.nextcloud.client.onboarding.OnboardingService import com.nextcloud.client.preferences.AppPreferences -import com.nextcloud.client.preferences.AppPreferencesImpl import com.nextcloud.client.preferences.DarkMode import com.nextcloud.client.systembars.SystemBarBackgroundCallbacks import com.nextcloud.ui.composeActivity.ComposeProcessTextAlias @@ -71,6 +71,7 @@ import dagger.android.AndroidInjector import dagger.android.DispatchingAndroidInjector import dagger.android.HasAndroidInjector import edu.umd.cs.findbugs.annotations.SuppressFBWarnings +import kotlinx.coroutines.CoroutineScope import org.conscrypt.Conscrypt import java.security.NoSuchAlgorithmException import java.security.Security @@ -140,6 +141,10 @@ open class MainApp : @Inject lateinit var arbitraryDataProvider: ArbitraryDataProvider + @Inject + @ApplicationScope + lateinit var appScope: CoroutineScope + private val restrictionsFilter = IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED) private val restrictionsReceiver = object : BroadcastReceiver() { @@ -218,7 +223,8 @@ open class MainApp : powerManagementService, backgroundJobManager, clock, - walledCheckCache + walledCheckCache, + appScope ) initContactsBackup(arbitraryDataProvider,accountManager, backgroundJobManager) AppNotificationChannels.create(getAppContext()) @@ -400,8 +406,6 @@ open class MainApp : override fun onTerminate() { super.onTerminate() connectivityService.removeListener(this) - ReceiversHelper.shutdown() - AppPreferencesImpl.shutdown() } companion object { @@ -473,7 +477,8 @@ open class MainApp : powerManagementService: PowerManagementService, backgroundJobManager: BackgroundJobManager, clock: Clock, - walledCheckCache: WalledCheckCache? + walledCheckCache: WalledCheckCache, + appScope: CoroutineScope ) { val appContext = getAppContext() AutoUploadEntriesMigration.updateToAutoUpload(context) @@ -504,7 +509,8 @@ open class MainApp : accountManager, connectivityService, powerManagementService, - walledCheckCache + walledCheckCache, + appScope ) ReceiversHelper.registerPowerChangeReceiver( uploadsStorageManager, diff --git a/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.kt b/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.kt index 41b5194de6d6..ebbd284c2982 100644 --- a/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.kt +++ b/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.kt @@ -12,6 +12,7 @@ import android.content.Intent import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.core.Clock import com.nextcloud.client.device.PowerManagementService +import com.nextcloud.client.di.ApplicationScope import com.nextcloud.client.jobs.BackgroundJobManager import com.nextcloud.client.network.ConnectivityService import com.nextcloud.client.network.WalledCheckCache @@ -21,6 +22,7 @@ import com.owncloud.android.datamodel.ArbitraryDataProvider import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.lib.common.utils.Log_OC import dagger.android.AndroidInjection +import kotlinx.coroutines.CoroutineScope import javax.inject.Inject class BootupBroadcastReceiver : BroadcastReceiver() { @@ -52,6 +54,10 @@ class BootupBroadcastReceiver : BroadcastReceiver() { @Inject lateinit var walledCheckCache: WalledCheckCache + @Inject + @ApplicationScope + lateinit var appScope: CoroutineScope + override fun onReceive(context: Context, intent: Intent) { AndroidInjection.inject(this, context) @@ -75,7 +81,8 @@ class BootupBroadcastReceiver : BroadcastReceiver() { powerManagementService, backgroundJobManager, clock, - walledCheckCache + walledCheckCache, + appScope ) } diff --git a/app/src/main/java/com/owncloud/android/utils/ReceiversHelper.kt b/app/src/main/java/com/owncloud/android/utils/ReceiversHelper.kt index b3f1778ce40b..79a2deab1b49 100644 --- a/app/src/main/java/com/owncloud/android/utils/ReceiversHelper.kt +++ b/app/src/main/java/com/owncloud/android/utils/ReceiversHelper.kt @@ -1,131 +1,107 @@ /* * Nextcloud - Android Client * - * SPDX-FileCopyrightText: 2020 Chris Narkiewicz - * SPDX-FileCopyrightText: 2017 Mario Danic - * SPDX-FileCopyrightText: 2017 Nextcloud GmbH - * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later */ -package com.owncloud.android.utils; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; - -import com.nextcloud.client.account.UserAccountManager; -import com.nextcloud.client.device.PowerManagementService; -import com.nextcloud.client.network.ConnectivityKey; -import com.nextcloud.client.network.ConnectivityService; -import com.nextcloud.client.network.WalledCheckCache; -import com.nextcloud.common.DNSCache; -import com.nextcloud.utils.extensions.ContextExtensionsKt; -import com.owncloud.android.MainApp; -import com.owncloud.android.datamodel.ReceiverFlag; -import com.owncloud.android.datamodel.UploadsStorageManager; -import com.owncloud.android.lib.common.utils.Log_OC; - -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -/** - * Helper for setting up network and power receivers - */ -public final class ReceiversHelper { - - private ReceiversHelper() { - // utility class -> private constructor +package com.owncloud.android.utils + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.net.ConnectivityManager +import android.net.wifi.WifiManager +import android.os.PowerManager +import com.nextcloud.client.account.UserAccountManager +import com.nextcloud.client.device.PowerManagementService +import com.nextcloud.client.network.ConnectivityKey +import com.nextcloud.client.network.ConnectivityService +import com.nextcloud.client.network.WalledCheckCache +import com.nextcloud.common.DNSCache +import com.nextcloud.utils.extensions.registerBroadcastReceiver +import com.owncloud.android.MainApp +import com.owncloud.android.datamodel.ReceiverFlag +import com.owncloud.android.datamodel.UploadsStorageManager +import com.owncloud.android.lib.common.utils.Log_OC +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch + +object ReceiversHelper { + private val TAG: String = ReceiversHelper::class.java.simpleName + + @Suppress("DEPRECATION") + private const val CONNECTIVITY_CHANGE_ACTION = ConnectivityManager.CONNECTIVITY_ACTION + + fun registerNetworkChangeReceiver( + uploadsStorageManager: UploadsStorageManager, + accountManager: UserAccountManager, + connectivityService: ConnectivityService, + powerManagementService: PowerManagementService, + walledCheckCache: WalledCheckCache, + appScope: CoroutineScope + ) { + registerReceiver(CONNECTIVITY_CHANGE_ACTION, WifiManager.NETWORK_STATE_CHANGED_ACTION) { + appScope.launch { clearNetworkCaches(accountManager, walledCheckCache) } + + if (!connectivityService.connectivity.isConnected) return@registerReceiver + + FilesSyncHelper.restartUploadsIfNeeded( + uploadsStorageManager, + accountManager, + connectivityService, + powerManagementService + ) + } } - private static final String TAG = ReceiversHelper.class.getSimpleName(); - private static final ExecutorService executor = Executors.newSingleThreadExecutor(); - - public static void registerNetworkChangeReceiver(final UploadsStorageManager uploadsStorageManager, - final UserAccountManager accountManager, - final ConnectivityService connectivityService, - final PowerManagementService powerManagementService, - final WalledCheckCache walledCheckCache) { - Context context = MainApp.getAppContext(); - - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); - intentFilter.addAction("android.net.wifi.STATE_CHANGE"); - - BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - executor.execute(() -> { - DNSCache.clear(); - walledCheckCache.clear(ConnectivityKey.Companion.getBy(accountManager)); - Log_OC.d(TAG,"DNS caches are cleared"); - }); - - if (connectivityService.getConnectivity().isConnected()) { - FilesSyncHelper.restartUploadsIfNeeded(uploadsStorageManager, - accountManager, - connectivityService, - powerManagementService); - } - } - }; - - ContextExtensionsKt.registerBroadcastReceiver(context, broadcastReceiver, intentFilter, ReceiverFlag.NotExported); + fun registerPowerChangeReceiver( + uploadsStorageManager: UploadsStorageManager, + accountManager: UserAccountManager, + connectivityService: ConnectivityService, + powerManagementService: PowerManagementService + ) { + registerReceiver(Intent.ACTION_POWER_CONNECTED, Intent.ACTION_POWER_DISCONNECTED) { intent -> + if (intent.action != Intent.ACTION_POWER_CONNECTED) return@registerReceiver + + FilesSyncHelper.restartUploadsIfNeeded( + uploadsStorageManager, + accountManager, + connectivityService, + powerManagementService + ) + } } - public static void registerPowerChangeReceiver( - final UploadsStorageManager uploadsStorageManager, - final UserAccountManager accountManager, - final ConnectivityService connectivityService, - final PowerManagementService powerManagementService - ) { - Context context = MainApp.getAppContext(); - - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(Intent.ACTION_POWER_CONNECTED); - intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED); - - BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())) { - FilesSyncHelper.restartUploadsIfNeeded(uploadsStorageManager, - accountManager, - connectivityService, - powerManagementService); - } - } - }; - - ContextExtensionsKt.registerBroadcastReceiver(context, broadcastReceiver, intentFilter, ReceiverFlag.NotExported); + fun registerPowerSaveReceiver( + uploadsStorageManager: UploadsStorageManager, + accountManager: UserAccountManager, + connectivityService: ConnectivityService, + powerManagementService: PowerManagementService + ) { + registerReceiver(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED) { + if (powerManagementService.isPowerSavingEnabled) return@registerReceiver + + FilesSyncHelper.restartUploadsIfNeeded( + uploadsStorageManager, + accountManager, + connectivityService, + powerManagementService + ) + } } - public static void registerPowerSaveReceiver( - final UploadsStorageManager uploadsStorageManager, - final UserAccountManager accountManager, - final ConnectivityService connectivityService, - final PowerManagementService powerManagementService - ) { - Context context = MainApp.getAppContext(); - - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction("android.os.action.POWER_SAVE_MODE_CHANGED"); - - BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (!powerManagementService.isPowerSavingEnabled()) { - FilesSyncHelper.restartUploadsIfNeeded(uploadsStorageManager, - accountManager, - connectivityService, - powerManagementService); - } - } - }; - - ContextExtensionsKt.registerBroadcastReceiver(context, broadcastReceiver, intentFilter, ReceiverFlag.NotExported); + private fun registerReceiver(vararg actions: String, onIntent: (Intent) -> Unit) { + val intentFilter = IntentFilter().apply { actions.forEach(::addAction) } + val broadcastReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) = onIntent(intent) + } + MainApp.getAppContext().registerBroadcastReceiver(broadcastReceiver, intentFilter, ReceiverFlag.NotExported) } - public static void shutdown() { - executor.shutdown(); + private fun clearNetworkCaches(accountManager: UserAccountManager, walledCheckCache: WalledCheckCache) { + DNSCache.clear() + walledCheckCache.clear(ConnectivityKey.getBy(accountManager)) + Log_OC.d(TAG, "DNS caches are cleared") } } From 73af37a8bb9d0a2a52c6f867345bd5b703c2159a Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Nov 2026 16:20:28 +0100 Subject: [PATCH 08/16] formatting Signed-off-by: alperozturk96 --- app/src/main/java/com/owncloud/android/MainApp.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/MainApp.kt b/app/src/main/java/com/owncloud/android/MainApp.kt index 2a889b125e6c..a8fb8f97dcb9 100644 --- a/app/src/main/java/com/owncloud/android/MainApp.kt +++ b/app/src/main/java/com/owncloud/android/MainApp.kt @@ -226,7 +226,7 @@ open class MainApp : walledCheckCache, appScope ) - initContactsBackup(arbitraryDataProvider,accountManager, backgroundJobManager) + initContactsBackup(arbitraryDataProvider, accountManager, backgroundJobManager) AppNotificationChannels.create(getAppContext()) scheduleBackgroundJobs() registerActivityLifecycleCallbacks(GlobalPassCodeProtectionCallbacks(onboarding, passCodeManager)) From 531125aa3518f845e5458d4e2d23676710dcae33 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Nov 2026 16:51:26 +0100 Subject: [PATCH 09/16] de-duplicate init sync operations Signed-off-by: alperozturk96 --- .../main/java/com/owncloud/android/MainApp.kt | 118 +++++++----------- .../android/files/BootupBroadcastReceiver.kt | 46 ------- 2 files changed, 47 insertions(+), 117 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/MainApp.kt b/app/src/main/java/com/owncloud/android/MainApp.kt index a8fb8f97dcb9..f9baa5a56c91 100644 --- a/app/src/main/java/com/owncloud/android/MainApp.kt +++ b/app/src/main/java/com/owncloud/android/MainApp.kt @@ -214,18 +214,7 @@ open class MainApp : Log_OC.d(TAG, "scheduleContentObserverJob, called") backgroundJobManager.scheduleContentObserverJob() - initSyncOperations( - this, - preferences, - uploadsStorageManager, - accountManager, - connectivityService, - powerManagementService, - backgroundJobManager, - clock, - walledCheckCache, - appScope - ) + initSyncOperations() initContactsBackup(arbitraryDataProvider, accountManager, backgroundJobManager) AppNotificationChannels.create(getAppContext()) scheduleBackgroundJobs() @@ -238,6 +227,52 @@ open class MainApp : connectivityService.addListener(this) } + private fun initSyncOperations() { + AutoUploadEntriesMigration.updateToAutoUpload(this) + AutoUploadEntriesMigration.cleanOldEntries(this, clock) + AutoUploadEntriesMigration.updateAutoUploadEntries(this, clock) + + if (PermissionUtil.checkStoragePermission(this)) { + AutoUploadEntriesMigration.splitOutAutoUploadEntries(this, clock) + } else { + preferences.setAutoUploadSplitEntriesEnabled(true) + } + + if (!preferences.isAutoUploadInitialized()) { + preferences.setAutoUploadInit(true) + } + + FilesSyncHelper.restartUploadsIfNeeded( + uploadsStorageManager, + accountManager, + connectivityService, + powerManagementService + ) + + backgroundJobManager.scheduleOfflineSync() + + ReceiversHelper.registerNetworkChangeReceiver( + uploadsStorageManager, + accountManager, + connectivityService, + powerManagementService, + walledCheckCache, + appScope + ) + ReceiversHelper.registerPowerChangeReceiver( + uploadsStorageManager, + accountManager, + connectivityService, + powerManagementService + ) + ReceiversHelper.registerPowerSaveReceiver( + uploadsStorageManager, + accountManager, + connectivityService, + powerManagementService + ) + } + fun disableDocumentsStorageProvider() { packageManager.setComponentEnabledSetting( ComponentName(this, DocumentsStorageProvider::class.java), @@ -467,65 +502,6 @@ open class MainApp : .forEach { backgroundJobManager.schedulePeriodicContactsBackup(it) } } - @JvmStatic - fun initSyncOperations( - context: Context, - preferences: AppPreferences, - uploadsStorageManager: UploadsStorageManager, - accountManager: UserAccountManager, - connectivityService: ConnectivityService, - powerManagementService: PowerManagementService, - backgroundJobManager: BackgroundJobManager, - clock: Clock, - walledCheckCache: WalledCheckCache, - appScope: CoroutineScope - ) { - val appContext = getAppContext() - AutoUploadEntriesMigration.updateToAutoUpload(context) - AutoUploadEntriesMigration.cleanOldEntries(appContext, clock) - AutoUploadEntriesMigration.updateAutoUploadEntries(appContext, clock) - - if (PermissionUtil.checkStoragePermission(appContext)) { - AutoUploadEntriesMigration.splitOutAutoUploadEntries(appContext, clock) - } else { - preferences.setAutoUploadSplitEntriesEnabled(true) - } - - if (!preferences.isAutoUploadInitialized()) { - preferences.setAutoUploadInit(true) - } - - FilesSyncHelper.restartUploadsIfNeeded( - uploadsStorageManager, - accountManager, - connectivityService, - powerManagementService - ) - - backgroundJobManager.scheduleOfflineSync() - - ReceiversHelper.registerNetworkChangeReceiver( - uploadsStorageManager, - accountManager, - connectivityService, - powerManagementService, - walledCheckCache, - appScope - ) - ReceiversHelper.registerPowerChangeReceiver( - uploadsStorageManager, - accountManager, - connectivityService, - powerManagementService - ) - ReceiversHelper.registerPowerSaveReceiver( - uploadsStorageManager, - accountManager, - connectivityService, - powerManagementService - ) - } - @JvmStatic fun string(@StringRes id: Int): String = getAppContext().getString(id) diff --git a/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.kt b/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.kt index ebbd284c2982..0b375015d499 100644 --- a/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.kt +++ b/app/src/main/java/com/owncloud/android/files/BootupBroadcastReceiver.kt @@ -10,19 +10,11 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import com.nextcloud.client.account.UserAccountManager -import com.nextcloud.client.core.Clock -import com.nextcloud.client.device.PowerManagementService -import com.nextcloud.client.di.ApplicationScope import com.nextcloud.client.jobs.BackgroundJobManager -import com.nextcloud.client.network.ConnectivityService -import com.nextcloud.client.network.WalledCheckCache -import com.nextcloud.client.preferences.AppPreferences import com.owncloud.android.MainApp import com.owncloud.android.datamodel.ArbitraryDataProvider -import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.lib.common.utils.Log_OC import dagger.android.AndroidInjection -import kotlinx.coroutines.CoroutineScope import javax.inject.Inject class BootupBroadcastReceiver : BroadcastReceiver() { @@ -30,34 +22,12 @@ class BootupBroadcastReceiver : BroadcastReceiver() { @Inject lateinit var arbitraryDataProvider: ArbitraryDataProvider - @Inject - lateinit var preferences: AppPreferences - @Inject lateinit var accountManager: UserAccountManager - @Inject - lateinit var uploadsStorageManager: UploadsStorageManager - - @Inject - lateinit var connectivityService: ConnectivityService - - @Inject - lateinit var powerManagementService: PowerManagementService - @Inject lateinit var backgroundJobManager: BackgroundJobManager - @Inject - lateinit var clock: Clock - - @Inject - lateinit var walledCheckCache: WalledCheckCache - - @Inject - @ApplicationScope - lateinit var appScope: CoroutineScope - override fun onReceive(context: Context, intent: Intent) { AndroidInjection.inject(this, context) @@ -66,26 +36,10 @@ class BootupBroadcastReceiver : BroadcastReceiver() { return } - initSyncOperations(context) scheduleAutoUploadJobs() MainApp.initContactsBackup(arbitraryDataProvider, accountManager, backgroundJobManager) } - private fun initSyncOperations(context: Context) { - MainApp.initSyncOperations( - context, - preferences, - uploadsStorageManager, - accountManager, - connectivityService, - powerManagementService, - backgroundJobManager, - clock, - walledCheckCache, - appScope - ) - } - private fun scheduleAutoUploadJobs() { Log_OC.d(TAG, "scheduleContentObserverJob, called") backgroundJobManager.scheduleContentObserverJob() From 2e1fe5d713b572bcb264e316f46099519ad3a881 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Nov 2026 16:55:48 +0100 Subject: [PATCH 10/16] de-duplicate init sync operations Signed-off-by: alperozturk96 --- .../migrations/AutoUploadEntriesMigration.kt | 53 ++++++----- .../main/java/com/owncloud/android/MainApp.kt | 49 ++--------- .../owncloud/android/utils/ReceiversHelper.kt | 87 +++++++++---------- 3 files changed, 80 insertions(+), 109 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/migrations/AutoUploadEntriesMigration.kt b/app/src/main/java/com/nextcloud/client/migrations/AutoUploadEntriesMigration.kt index 7bcf01ce6b43..7a5405b7923f 100644 --- a/app/src/main/java/com/nextcloud/client/migrations/AutoUploadEntriesMigration.kt +++ b/app/src/main/java/com/nextcloud/client/migrations/AutoUploadEntriesMigration.kt @@ -9,8 +9,7 @@ package com.nextcloud.client.migrations import android.content.Context import android.view.WindowManager.BadTokenException import com.google.android.material.dialog.MaterialAlertDialogBuilder -import com.nextcloud.client.core.Clock -import com.nextcloud.client.preferences.AppPreferencesImpl +import com.nextcloud.client.preferences.AppPreferences import com.owncloud.android.R import com.owncloud.android.datamodel.MediaFolder import com.owncloud.android.datamodel.MediaFolderType @@ -20,14 +19,28 @@ import com.owncloud.android.datamodel.SyncedFolderProvider import com.owncloud.android.lib.common.utils.Log_OC import com.owncloud.android.ui.navigation.NavigatorActivity import com.owncloud.android.ui.navigation.NavigatorScreen +import com.owncloud.android.utils.PermissionUtil +import javax.inject.Inject + +class AutoUploadEntriesMigration @Inject constructor( + private val context: Context, + private val preferences: AppPreferences, + private val syncedFolderProvider: SyncedFolderProvider +) { + + fun migrate() { + updateToAutoUpload() + cleanOldEntries() + updateAutoUploadEntries() + + if (PermissionUtil.checkStoragePermission(context)) { + splitOutAutoUploadEntries() + } else { + preferences.isAutoUploadSplitEntriesEnabled = true + } + } -object AutoUploadEntriesMigration { - - private val TAG: String = AutoUploadEntriesMigration::class.java.simpleName - private const val MEDIA_FOLDER_ITEM_LIMIT = 1 - - fun updateToAutoUpload(context: Context) { - val preferences = AppPreferencesImpl.fromContext(context) + private fun updateToAutoUpload() { if (!preferences.instantPictureUploadEnabled() && !preferences.instantVideoUploadEnabled()) { return } @@ -35,13 +48,13 @@ object AutoUploadEntriesMigration { preferences.removeLegacyPreferences() try { - showAutoUploadAlertDialog(context) + showAutoUploadAlertDialog() } catch (e: BadTokenException) { Log_OC.i(TAG, "Error showing Auto Upload Update dialog, so skipping it: " + e.message) } } - private fun showAutoUploadAlertDialog(context: Context) { + private fun showAutoUploadAlertDialog() { MaterialAlertDialogBuilder(context, R.style.Theme_ownCloud_Dialog) .setTitle(R.string.drawer_synced_folders) .setMessage(R.string.synced_folders_new_info) @@ -56,13 +69,11 @@ object AutoUploadEntriesMigration { .show() } - fun cleanOldEntries(context: Context, clock: Clock) { - val preferences = AppPreferencesImpl.fromContext(context) + private fun cleanOldEntries() { if (preferences.isLegacyClean) { return } - val syncedFolderProvider = SyncedFolderProvider(context.contentResolver, preferences, clock) val newestIds = syncedFolderProvider.syncedFolders .groupBy { it.account to it.localPath } .values @@ -79,24 +90,21 @@ object AutoUploadEntriesMigration { } } - fun updateAutoUploadEntries(context: Context, clock: Clock) { - val preferences = AppPreferencesImpl.fromContext(context) + private fun updateAutoUploadEntries() { if (preferences.isAutoUploadPathsUpdateEnabled) { return } - SyncedFolderProvider(context.contentResolver, preferences, clock).updateAutoUploadPaths(context) + syncedFolderProvider.updateAutoUploadPaths(context) } - fun splitOutAutoUploadEntries(context: Context, clock: Clock) { - val preferences = AppPreferencesImpl.fromContext(context) + private fun splitOutAutoUploadEntries() { if (preferences.isAutoUploadSplitEntriesEnabled) { return } Log_OC.i(TAG, "Migrate synced_folders records for image/video split") val contentResolver = context.contentResolver - val syncedFolderProvider = SyncedFolderProvider(contentResolver, preferences, clock) val imageMediaFolders = MediaProvider.getImageFolders(contentResolver, MEDIA_FOLDER_ITEM_LIMIT, null, true) val videoMediaFolders = MediaProvider.getVideoFolders(contentResolver, MEDIA_FOLDER_ITEM_LIMIT, null, true) val syncedFolders = syncedFolderProvider.syncedFolders @@ -130,4 +138,9 @@ object AutoUploadEntriesMigration { val primaryKey = storeSyncedFolder(newSyncedFolder) Log_OC.i(TAG, "Migrated $mediaTypeLabel synced_folders record: $primaryKey - ${newSyncedFolder.localPath}") } + + companion object { + private val TAG: String = AutoUploadEntriesMigration::class.java.simpleName + private const val MEDIA_FOLDER_ITEM_LIMIT = 1 + } } diff --git a/app/src/main/java/com/owncloud/android/MainApp.kt b/app/src/main/java/com/owncloud/android/MainApp.kt index f9baa5a56c91..89e1445aa0d6 100644 --- a/app/src/main/java/com/owncloud/android/MainApp.kt +++ b/app/src/main/java/com/owncloud/android/MainApp.kt @@ -24,11 +24,9 @@ import androidx.lifecycle.ProcessLifecycleOwner import com.nextcloud.appReview.InAppReviewHelper import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.appinfo.AppInfo -import com.nextcloud.client.core.Clock import com.nextcloud.client.device.PowerManagementService import com.nextcloud.client.di.ActivityInjector import com.nextcloud.client.di.AppComponent -import com.nextcloud.client.di.ApplicationScope import com.nextcloud.client.di.DaggerAppComponent import com.nextcloud.client.errorhandling.ExceptionHandler import com.nextcloud.client.jobs.BackgroundJobManager @@ -38,7 +36,6 @@ import com.nextcloud.client.migrations.AutoUploadEntriesMigration import com.nextcloud.client.migrations.MigrationsManager import com.nextcloud.client.network.ConnectivityService import com.nextcloud.client.network.NetworkChangeListener -import com.nextcloud.client.network.WalledCheckCache import com.nextcloud.client.notifications.AppNotificationChannels import com.nextcloud.client.onboarding.OnboardingService import com.nextcloud.client.preferences.AppPreferences @@ -63,7 +60,6 @@ import com.owncloud.android.lib.resources.status.OwnCloudVersion import com.owncloud.android.providers.documentstorage.DocumentsStorageProvider import com.owncloud.android.ui.activity.ContactsPreferenceActivity import com.owncloud.android.utils.FilesSyncHelper -import com.owncloud.android.utils.PermissionUtil import com.owncloud.android.utils.ReceiversHelper import com.owncloud.android.utils.SecurityUtils import com.owncloud.android.utils.theme.ViewThemeUtils @@ -71,7 +67,6 @@ import dagger.android.AndroidInjector import dagger.android.DispatchingAndroidInjector import dagger.android.HasAndroidInjector import edu.umd.cs.findbugs.annotations.SuppressFBWarnings -import kotlinx.coroutines.CoroutineScope import org.conscrypt.Conscrypt import java.security.NoSuchAlgorithmException import java.security.Security @@ -117,9 +112,6 @@ open class MainApp : @Inject lateinit var backgroundJobManager: BackgroundJobManager - @Inject - lateinit var clock: Clock - @Inject lateinit var migrationsManager: MigrationsManager @@ -129,9 +121,6 @@ open class MainApp : @Inject lateinit var passCodeManager: PassCodeManager - @Inject - lateinit var walledCheckCache: WalledCheckCache - @Inject lateinit var composeProcessTextAlias: ComposeProcessTextAlias @@ -142,8 +131,10 @@ open class MainApp : lateinit var arbitraryDataProvider: ArbitraryDataProvider @Inject - @ApplicationScope - lateinit var appScope: CoroutineScope + lateinit var receiversHelper: ReceiversHelper + + @Inject + lateinit var autoUploadEntriesMigration: AutoUploadEntriesMigration private val restrictionsFilter = IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED) @@ -228,15 +219,7 @@ open class MainApp : } private fun initSyncOperations() { - AutoUploadEntriesMigration.updateToAutoUpload(this) - AutoUploadEntriesMigration.cleanOldEntries(this, clock) - AutoUploadEntriesMigration.updateAutoUploadEntries(this, clock) - - if (PermissionUtil.checkStoragePermission(this)) { - AutoUploadEntriesMigration.splitOutAutoUploadEntries(this, clock) - } else { - preferences.setAutoUploadSplitEntriesEnabled(true) - } + autoUploadEntriesMigration.migrate() if (!preferences.isAutoUploadInitialized()) { preferences.setAutoUploadInit(true) @@ -250,27 +233,7 @@ open class MainApp : ) backgroundJobManager.scheduleOfflineSync() - - ReceiversHelper.registerNetworkChangeReceiver( - uploadsStorageManager, - accountManager, - connectivityService, - powerManagementService, - walledCheckCache, - appScope - ) - ReceiversHelper.registerPowerChangeReceiver( - uploadsStorageManager, - accountManager, - connectivityService, - powerManagementService - ) - ReceiversHelper.registerPowerSaveReceiver( - uploadsStorageManager, - accountManager, - connectivityService, - powerManagementService - ) + receiversHelper.registerReceivers() } fun disableDocumentsStorageProvider() { diff --git a/app/src/main/java/com/owncloud/android/utils/ReceiversHelper.kt b/app/src/main/java/com/owncloud/android/utils/ReceiversHelper.kt index 79a2deab1b49..6ea6d5e1ecd4 100644 --- a/app/src/main/java/com/owncloud/android/utils/ReceiversHelper.kt +++ b/app/src/main/java/com/owncloud/android/utils/ReceiversHelper.kt @@ -15,79 +15,58 @@ import android.net.wifi.WifiManager import android.os.PowerManager import com.nextcloud.client.account.UserAccountManager import com.nextcloud.client.device.PowerManagementService +import com.nextcloud.client.di.ApplicationScope import com.nextcloud.client.network.ConnectivityKey import com.nextcloud.client.network.ConnectivityService import com.nextcloud.client.network.WalledCheckCache import com.nextcloud.common.DNSCache import com.nextcloud.utils.extensions.registerBroadcastReceiver -import com.owncloud.android.MainApp import com.owncloud.android.datamodel.ReceiverFlag import com.owncloud.android.datamodel.UploadsStorageManager import com.owncloud.android.lib.common.utils.Log_OC import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch +import javax.inject.Inject -object ReceiversHelper { - private val TAG: String = ReceiversHelper::class.java.simpleName +class ReceiversHelper @Inject constructor( + private val context: Context, + private val uploadsStorageManager: UploadsStorageManager, + private val accountManager: UserAccountManager, + private val connectivityService: ConnectivityService, + private val powerManagementService: PowerManagementService, + private val walledCheckCache: WalledCheckCache, + @param:ApplicationScope private val appScope: CoroutineScope +) { - @Suppress("DEPRECATION") - private const val CONNECTIVITY_CHANGE_ACTION = ConnectivityManager.CONNECTIVITY_ACTION + fun registerReceivers() { + registerNetworkChangeReceiver() + registerPowerChangeReceiver() + registerPowerSaveReceiver() + } - fun registerNetworkChangeReceiver( - uploadsStorageManager: UploadsStorageManager, - accountManager: UserAccountManager, - connectivityService: ConnectivityService, - powerManagementService: PowerManagementService, - walledCheckCache: WalledCheckCache, - appScope: CoroutineScope - ) { + private fun registerNetworkChangeReceiver() { registerReceiver(CONNECTIVITY_CHANGE_ACTION, WifiManager.NETWORK_STATE_CHANGED_ACTION) { - appScope.launch { clearNetworkCaches(accountManager, walledCheckCache) } + appScope.launch { clearNetworkCaches() } if (!connectivityService.connectivity.isConnected) return@registerReceiver - FilesSyncHelper.restartUploadsIfNeeded( - uploadsStorageManager, - accountManager, - connectivityService, - powerManagementService - ) + restartUploadsIfNeeded() } } - fun registerPowerChangeReceiver( - uploadsStorageManager: UploadsStorageManager, - accountManager: UserAccountManager, - connectivityService: ConnectivityService, - powerManagementService: PowerManagementService - ) { + private fun registerPowerChangeReceiver() { registerReceiver(Intent.ACTION_POWER_CONNECTED, Intent.ACTION_POWER_DISCONNECTED) { intent -> if (intent.action != Intent.ACTION_POWER_CONNECTED) return@registerReceiver - FilesSyncHelper.restartUploadsIfNeeded( - uploadsStorageManager, - accountManager, - connectivityService, - powerManagementService - ) + restartUploadsIfNeeded() } } - fun registerPowerSaveReceiver( - uploadsStorageManager: UploadsStorageManager, - accountManager: UserAccountManager, - connectivityService: ConnectivityService, - powerManagementService: PowerManagementService - ) { + private fun registerPowerSaveReceiver() { registerReceiver(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED) { if (powerManagementService.isPowerSavingEnabled) return@registerReceiver - FilesSyncHelper.restartUploadsIfNeeded( - uploadsStorageManager, - accountManager, - connectivityService, - powerManagementService - ) + restartUploadsIfNeeded() } } @@ -96,12 +75,28 @@ object ReceiversHelper { val broadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) = onIntent(intent) } - MainApp.getAppContext().registerBroadcastReceiver(broadcastReceiver, intentFilter, ReceiverFlag.NotExported) + context.registerBroadcastReceiver(broadcastReceiver, intentFilter, ReceiverFlag.NotExported) + } + + private fun restartUploadsIfNeeded() { + FilesSyncHelper.restartUploadsIfNeeded( + uploadsStorageManager, + accountManager, + connectivityService, + powerManagementService + ) } - private fun clearNetworkCaches(accountManager: UserAccountManager, walledCheckCache: WalledCheckCache) { + private fun clearNetworkCaches() { DNSCache.clear() walledCheckCache.clear(ConnectivityKey.getBy(accountManager)) Log_OC.d(TAG, "DNS caches are cleared") } + + companion object { + private val TAG: String = ReceiversHelper::class.java.simpleName + + @Suppress("DEPRECATION") + private const val CONNECTIVITY_CHANGE_ACTION = ConnectivityManager.CONNECTIVITY_ACTION + } } From 67fdb1f40e9ac0a59b741fb5589ef75246f2d52f Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Nov 2026 16:59:03 +0100 Subject: [PATCH 11/16] Rename .java to .kt Signed-off-by: alperozturk96 --- .../nextcloud/client/preferences/{DarkMode.java => DarkMode.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename app/src/main/java/com/nextcloud/client/preferences/{DarkMode.java => DarkMode.kt} (100%) diff --git a/app/src/main/java/com/nextcloud/client/preferences/DarkMode.java b/app/src/main/java/com/nextcloud/client/preferences/DarkMode.kt similarity index 100% rename from app/src/main/java/com/nextcloud/client/preferences/DarkMode.java rename to app/src/main/java/com/nextcloud/client/preferences/DarkMode.kt From 39e5ae4e9e24fa7bc46f4f930645ba67f0eca5fc Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Nov 2026 16:59:03 +0100 Subject: [PATCH 12/16] de-duplicate set theme Signed-off-by: alperozturk96 --- .../java/com/owncloud/android/AbstractIT.kt | 3 ++- .../nextcloud/client/preferences/DarkMode.kt | 21 +++++++++++++------ .../main/java/com/owncloud/android/MainApp.kt | 12 +---------- .../android/ui/dialog/ThemeSelectionDialog.kt | 10 ++++----- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/AbstractIT.kt b/app/src/androidTest/java/com/owncloud/android/AbstractIT.kt index 661d96d7db03..0702c797f885 100644 --- a/app/src/androidTest/java/com/owncloud/android/AbstractIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/AbstractIT.kt @@ -15,6 +15,7 @@ import android.app.Instrumentation import android.content.Context import android.os.Build import android.view.View +import androidx.appcompat.app.AppCompatDelegate import androidx.fragment.app.DialogFragment import androidx.test.espresso.Espresso.onView import androidx.test.espresso.accessibility.AccessibilityChecks @@ -321,7 +322,7 @@ abstract class AbstractIT { darkMode = DARK AppPreferencesImpl.fromContext(targetContext).setDarkThemeMode(DarkMode.DARK) - MainApp.setAppTheme(DarkMode.DARK) + AppCompatDelegate.setDefaultNightMode(DarkMode.DARK.toMode()) } @JvmStatic diff --git a/app/src/main/java/com/nextcloud/client/preferences/DarkMode.kt b/app/src/main/java/com/nextcloud/client/preferences/DarkMode.kt index c516893acd0c..618fd7099efd 100644 --- a/app/src/main/java/com/nextcloud/client/preferences/DarkMode.kt +++ b/app/src/main/java/com/nextcloud/client/preferences/DarkMode.kt @@ -1,12 +1,21 @@ /* * Nextcloud - Android Client * - * SPDX-FileCopyrightText: 2019 Tobias Kaminsky - * SPDX-FileCopyrightText: 2019 Nextcloud GmbH - * SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only + * SPDX-FileCopyrightText: 2026 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later */ -package com.nextcloud.client.preferences; +package com.nextcloud.client.preferences -public enum DarkMode { - DARK, LIGHT, SYSTEM +import androidx.appcompat.app.AppCompatDelegate + +enum class DarkMode { + DARK, LIGHT, SYSTEM; + + fun toMode(): Int { + return when (this) { + LIGHT -> AppCompatDelegate.MODE_NIGHT_NO + DARK -> AppCompatDelegate.MODE_NIGHT_YES + SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM + } + } } diff --git a/app/src/main/java/com/owncloud/android/MainApp.kt b/app/src/main/java/com/owncloud/android/MainApp.kt index 89e1445aa0d6..b33537adaa4b 100644 --- a/app/src/main/java/com/owncloud/android/MainApp.kt +++ b/app/src/main/java/com/owncloud/android/MainApp.kt @@ -183,7 +183,7 @@ open class MainApp : @SuppressFBWarnings("ST") override fun onCreate() { enableStrictMode() - setAppTheme(preferences.getDarkThemeMode()) + AppCompatDelegate.setDefaultNightMode(preferences.getDarkThemeMode().toMode()) super.onCreate() ProcessLifecycleOwner.get().lifecycle.addObserver(lifecycleEventObserver) @@ -541,15 +541,5 @@ open class MainApp : "" } } - - @JvmStatic - fun setAppTheme(mode: DarkMode) { - val nightMode = when (mode) { - DarkMode.LIGHT -> AppCompatDelegate.MODE_NIGHT_NO - DarkMode.DARK -> AppCompatDelegate.MODE_NIGHT_YES - DarkMode.SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM - } - AppCompatDelegate.setDefaultNightMode(nightMode) - } } } diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt index 3e8216df7474..b524e023542e 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt @@ -9,6 +9,7 @@ package com.owncloud.android.ui.dialog import android.app.Dialog import android.os.Bundle +import androidx.appcompat.app.AppCompatDelegate import androidx.core.os.bundleOf import androidx.fragment.app.DialogFragment import androidx.fragment.app.setFragmentResult @@ -16,7 +17,6 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.nextcloud.client.di.Injectable import com.nextcloud.client.preferences.AppPreferences import com.nextcloud.client.preferences.DarkMode -import com.owncloud.android.MainApp import com.owncloud.android.R import com.owncloud.android.databinding.DialogThemeSelectionBinding import com.owncloud.android.ui.dialog.extensions.themeButtons @@ -83,13 +83,13 @@ class ThemeSelectionDialog : return builder.create() } - private fun applyTheme(mode: DarkMode) { - preferences.setDarkThemeMode(mode) - MainApp.setAppTheme(mode) + private fun applyTheme(darkMode: DarkMode) { + preferences.setDarkThemeMode(darkMode) + AppCompatDelegate.setDefaultNightMode(darkMode.toMode()) setFragmentResult( ExtendedSettingsActivityDialog.ThemeSelection.key, - bundleOf(ExtendedSettingsActivityDialog.ThemeSelection.key to mode.name) + bundleOf(ExtendedSettingsActivityDialog.ThemeSelection.key to darkMode.name) ) } From 91ae3c4e46a82887256f769abe8b13bf833a4c6b Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Nov 2026 16:59:13 +0100 Subject: [PATCH 13/16] de-duplicate set theme Signed-off-by: alperozturk96 --- app/src/main/java/com/owncloud/android/MainApp.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/MainApp.kt b/app/src/main/java/com/owncloud/android/MainApp.kt index b33537adaa4b..b9904b87c82f 100644 --- a/app/src/main/java/com/owncloud/android/MainApp.kt +++ b/app/src/main/java/com/owncloud/android/MainApp.kt @@ -39,7 +39,6 @@ import com.nextcloud.client.network.NetworkChangeListener import com.nextcloud.client.notifications.AppNotificationChannels import com.nextcloud.client.onboarding.OnboardingService import com.nextcloud.client.preferences.AppPreferences -import com.nextcloud.client.preferences.DarkMode import com.nextcloud.client.systembars.SystemBarBackgroundCallbacks import com.nextcloud.ui.composeActivity.ComposeProcessTextAlias import com.nextcloud.utils.extensions.registerBroadcastReceiver From 311d06946245bb2c0cc43ca811cec17e23ab8f18 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Nov 2026 17:04:36 +0100 Subject: [PATCH 14/16] de-duplicate set theme Signed-off-by: alperozturk96 --- app/src/androidTest/java/com/owncloud/android/AbstractIT.kt | 3 +-- .../main/java/com/nextcloud/client/preferences/DarkMode.kt | 6 +++++- app/src/main/java/com/owncloud/android/MainApp.kt | 3 +-- .../com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt | 3 +-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/AbstractIT.kt b/app/src/androidTest/java/com/owncloud/android/AbstractIT.kt index 0702c797f885..9b0002e8ef54 100644 --- a/app/src/androidTest/java/com/owncloud/android/AbstractIT.kt +++ b/app/src/androidTest/java/com/owncloud/android/AbstractIT.kt @@ -15,7 +15,6 @@ import android.app.Instrumentation import android.content.Context import android.os.Build import android.view.View -import androidx.appcompat.app.AppCompatDelegate import androidx.fragment.app.DialogFragment import androidx.test.espresso.Espresso.onView import androidx.test.espresso.accessibility.AccessibilityChecks @@ -322,7 +321,7 @@ abstract class AbstractIT { darkMode = DARK AppPreferencesImpl.fromContext(targetContext).setDarkThemeMode(DarkMode.DARK) - AppCompatDelegate.setDefaultNightMode(DarkMode.DARK.toMode()) + DarkMode.DARK.setTheme() } @JvmStatic diff --git a/app/src/main/java/com/nextcloud/client/preferences/DarkMode.kt b/app/src/main/java/com/nextcloud/client/preferences/DarkMode.kt index 618fd7099efd..025b59d998ff 100644 --- a/app/src/main/java/com/nextcloud/client/preferences/DarkMode.kt +++ b/app/src/main/java/com/nextcloud/client/preferences/DarkMode.kt @@ -11,7 +11,11 @@ import androidx.appcompat.app.AppCompatDelegate enum class DarkMode { DARK, LIGHT, SYSTEM; - fun toMode(): Int { + fun setTheme() { + AppCompatDelegate.setDefaultNightMode(this.toMode()) + } + + private fun toMode(): Int { return when (this) { LIGHT -> AppCompatDelegate.MODE_NIGHT_NO DARK -> AppCompatDelegate.MODE_NIGHT_YES diff --git a/app/src/main/java/com/owncloud/android/MainApp.kt b/app/src/main/java/com/owncloud/android/MainApp.kt index b9904b87c82f..8743f909cc8b 100644 --- a/app/src/main/java/com/owncloud/android/MainApp.kt +++ b/app/src/main/java/com/owncloud/android/MainApp.kt @@ -17,7 +17,6 @@ import android.content.pm.PackageManager import android.content.res.Resources import android.os.StrictMode import androidx.annotation.StringRes -import androidx.appcompat.app.AppCompatDelegate import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.ProcessLifecycleOwner @@ -182,7 +181,7 @@ open class MainApp : @SuppressFBWarnings("ST") override fun onCreate() { enableStrictMode() - AppCompatDelegate.setDefaultNightMode(preferences.getDarkThemeMode().toMode()) + preferences.darkThemeMode.setTheme() super.onCreate() ProcessLifecycleOwner.get().lifecycle.addObserver(lifecycleEventObserver) diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt index b524e023542e..3c46590cba38 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/ThemeSelectionDialog.kt @@ -9,7 +9,6 @@ package com.owncloud.android.ui.dialog import android.app.Dialog import android.os.Bundle -import androidx.appcompat.app.AppCompatDelegate import androidx.core.os.bundleOf import androidx.fragment.app.DialogFragment import androidx.fragment.app.setFragmentResult @@ -85,7 +84,7 @@ class ThemeSelectionDialog : private fun applyTheme(darkMode: DarkMode) { preferences.setDarkThemeMode(darkMode) - AppCompatDelegate.setDefaultNightMode(darkMode.toMode()) + darkMode.setTheme() setFragmentResult( ExtendedSettingsActivityDialog.ThemeSelection.key, From e5fa85302e34b34a9552afbba76d03b642b0d34e Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Tue, 10 Nov 2026 17:06:00 +0100 Subject: [PATCH 15/16] de-duplicate set theme Signed-off-by: alperozturk96 --- .../com/nextcloud/client/preferences/DarkMode.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/preferences/DarkMode.kt b/app/src/main/java/com/nextcloud/client/preferences/DarkMode.kt index 025b59d998ff..58cd1654ae1a 100644 --- a/app/src/main/java/com/nextcloud/client/preferences/DarkMode.kt +++ b/app/src/main/java/com/nextcloud/client/preferences/DarkMode.kt @@ -9,17 +9,17 @@ package com.nextcloud.client.preferences import androidx.appcompat.app.AppCompatDelegate enum class DarkMode { - DARK, LIGHT, SYSTEM; + DARK, + LIGHT, + SYSTEM; fun setTheme() { - AppCompatDelegate.setDefaultNightMode(this.toMode()) + AppCompatDelegate.setDefaultNightMode(toMode()) } - private fun toMode(): Int { - return when (this) { - LIGHT -> AppCompatDelegate.MODE_NIGHT_NO - DARK -> AppCompatDelegate.MODE_NIGHT_YES - SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM - } + private fun toMode(): Int = when (this) { + LIGHT -> AppCompatDelegate.MODE_NIGHT_NO + DARK -> AppCompatDelegate.MODE_NIGHT_YES + SYSTEM -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM } } From 7acd7ea88822a4c9e80d4536b1cb7365f3856802 Mon Sep 17 00:00:00 2001 From: alperozturk96 Date: Wed, 11 Nov 2026 13:09:26 +0100 Subject: [PATCH 16/16] wip Signed-off-by: alperozturk96 --- app/src/main/java/com/owncloud/android/MainApp.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/owncloud/android/MainApp.kt b/app/src/main/java/com/owncloud/android/MainApp.kt index 8743f909cc8b..f6bfa309fa53 100644 --- a/app/src/main/java/com/owncloud/android/MainApp.kt +++ b/app/src/main/java/com/owncloud/android/MainApp.kt @@ -38,6 +38,7 @@ import com.nextcloud.client.network.NetworkChangeListener import com.nextcloud.client.notifications.AppNotificationChannels import com.nextcloud.client.onboarding.OnboardingService import com.nextcloud.client.preferences.AppPreferences +import com.nextcloud.client.preferences.AppPreferencesImpl import com.nextcloud.client.systembars.SystemBarBackgroundCallbacks import com.nextcloud.ui.composeActivity.ComposeProcessTextAlias import com.nextcloud.utils.extensions.registerBroadcastReceiver @@ -402,6 +403,7 @@ open class MainApp : override fun onTerminate() { super.onTerminate() connectivityService.removeListener(this) + AppPreferencesImpl.shutdown() } companion object {