Browse Source

Merge pull request #13942 from nextcloud/feature/add-more-mdm

Feature - Add More MDM
Tobias Kaminsky 4 tháng trước cách đây
mục cha
commit
79d4753bba
30 tập tin đã thay đổi với 428 bổ sung272 xóa
  1. 0 86
      app/src/androidTest/java/com/nextcloud/utils/AppConfigManagerTests.kt
  2. 4 5
      app/src/main/java/com/nextcloud/client/onboarding/FirstRunActivity.kt
  3. 3 3
      app/src/main/java/com/nextcloud/client/onboarding/OnboardingServiceImpl.kt
  4. 2 2
      app/src/main/java/com/nextcloud/ui/ChooseAccountDialogFragment.kt
  5. 134 0
      app/src/main/java/com/nextcloud/utils/mdm/MDMConfig.kt
  6. 42 15
      app/src/main/java/com/owncloud/android/MainApp.java
  7. 2 1
      app/src/main/java/com/owncloud/android/authentication/AccountAuthenticator.java
  8. 6 10
      app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java
  9. 2 4
      app/src/main/java/com/owncloud/android/authentication/DeepLinkLoginActivity.kt
  10. 21 7
      app/src/main/java/com/owncloud/android/files/FileMenuFilter.java
  11. 5 7
      app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java
  12. 9 6
      app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java
  13. 3 3
      app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java
  14. 3 5
      app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java
  15. 7 1
      app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java
  16. 6 1
      app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java
  17. 7 0
      app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt
  18. 59 34
      app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java
  19. 13 6
      app/src/main/java/com/owncloud/android/ui/adapter/UserListAdapter.java
  20. 1 1
      app/src/main/java/com/owncloud/android/ui/dialog/MultipleAccountsDialog.kt
  21. 11 1
      app/src/main/java/com/owncloud/android/ui/dialog/SendShareDialog.kt
  22. 5 0
      app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java
  23. 16 3
      app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java
  24. 5 1
      app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingMenuBottomSheetDialog.java
  25. 5 0
      app/src/main/java/com/owncloud/android/utils/ClipboardUtil.kt
  26. 7 1
      app/src/main/java/com/owncloud/android/utils/appConfig/AppConfigKeys.kt
  27. 0 68
      app/src/main/java/com/owncloud/android/utils/appConfig/AppConfigManager.kt
  28. 7 0
      app/src/main/res/values/setup.xml
  29. 7 1
      app/src/main/res/values/strings.xml
  30. 36 0
      app/src/main/res/xml/app_config.xml

+ 0 - 86
app/src/androidTest/java/com/nextcloud/utils/AppConfigManagerTests.kt

@@ -1,86 +0,0 @@
-/*
- * Nextcloud - Android Client
- *
- * SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-package com.nextcloud.utils
-
-import android.os.Bundle
-import com.owncloud.android.AbstractIT
-import com.owncloud.android.lib.common.OwnCloudClientManagerFactory
-import com.owncloud.android.utils.appConfig.AppConfigKeys
-import com.owncloud.android.utils.appConfig.AppConfigManager
-import org.junit.AfterClass
-import org.junit.Test
-
-class AppConfigManagerTests : AbstractIT() {
-
-    private val testBaseUrl = "nextcloud.cloud.cloud"
-    private val testProxyHost = "nextcloud.cloud.cloud.com"
-
-    @Suppress("MagicNumber")
-    private val testProxyPort = 8800
-
-    @Test
-    fun testSetProxyConfigWhenGivenClientBrandedPlusAndCorrectBundleDataProxyConfigurationShouldSet() {
-        val proxySetting = Bundle().apply {
-            putString(AppConfigKeys.ProxyHost.key, testProxyHost)
-            putInt(AppConfigKeys.ProxyPort.key, testProxyPort)
-        }
-
-        AppConfigManager(targetContext, proxySetting).run {
-            setProxyConfig(true)
-        }
-
-        val proxyHost = OwnCloudClientManagerFactory.getProxyHost()
-        val proxyPort = OwnCloudClientManagerFactory.getProxyPort()
-
-        assert(proxyHost.equals(testProxyHost))
-        assert(proxyPort == testProxyPort)
-    }
-
-    @Test
-    fun testSetProxyConfigWhenGivenClientNotBrandedPlusAndCorrectBundleDataProxyConfigurationShouldNotSet() {
-        val proxySetting = Bundle().apply {
-            putString(AppConfigKeys.ProxyHost.key, testProxyHost)
-            putInt(AppConfigKeys.ProxyPort.key, testProxyPort)
-        }
-
-        AppConfigManager(targetContext, proxySetting).run {
-            setProxyConfig(false)
-        }
-
-        val proxyHost = OwnCloudClientManagerFactory.getProxyHost()
-        val proxyPort = OwnCloudClientManagerFactory.getProxyPort()
-
-        assert(proxyHost.equals(""))
-        assert(proxyPort == -1)
-    }
-
-    @Test
-    fun testGetBaseUrlConfigWhenGivenClientBrandedPlusAndCorrectBundleDataBaseUrlConfigurationShouldSet() {
-        val baseUrlConfig = Bundle().apply {
-            putString(AppConfigKeys.BaseUrl.key, testBaseUrl)
-        }
-        val sut = AppConfigManager(targetContext, baseUrlConfig)
-        assert(!sut.getBaseUrl(true).isNullOrEmpty())
-    }
-
-    @Test
-    fun testGetBaseUrlConfigWhenGivenClientBrandedPlusAndBrokenBundleDataBaseUrlConfigurationShouldNotSet() {
-        val baseUrlConfig = Bundle()
-        val sut = AppConfigManager(targetContext, baseUrlConfig)
-        assert(sut.getBaseUrl(true).isNullOrEmpty())
-    }
-
-    companion object {
-        @JvmStatic
-        @AfterClass
-        fun tearDown() {
-            OwnCloudClientManagerFactory.setProxyHost("")
-            OwnCloudClientManagerFactory.setProxyPort(-1)
-        }
-    }
-}

+ 4 - 5
app/src/main/java/com/nextcloud/client/onboarding/FirstRunActivity.kt

@@ -24,6 +24,7 @@ import com.nextcloud.client.account.UserAccountManager
 import com.nextcloud.client.appinfo.AppInfo
 import com.nextcloud.client.di.Injectable
 import com.nextcloud.client.preferences.AppPreferences
+import com.nextcloud.utils.mdm.MDMConfig
 import com.owncloud.android.BuildConfig
 import com.owncloud.android.R
 import com.owncloud.android.authentication.AuthenticatorActivity
@@ -76,13 +77,12 @@ class FirstRunActivity : BaseActivity(), Injectable {
         binding = FirstRunActivityBinding.inflate(layoutInflater)
         setContentView(binding.root)
 
-        val isProviderOrOwnInstallationVisible = resources.getBoolean(R.bool.show_provider_or_own_installation)
         setSlideshowSize(resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE)
 
         registerActivityResult()
         setupLoginButton()
-        setupSignupButton(isProviderOrOwnInstallationVisible)
-        setupHostOwnServerTextView(isProviderOrOwnInstallationVisible)
+        setupSignupButton(MDMConfig.showIntro(this))
+        setupHostOwnServerTextView(MDMConfig.showIntro(this))
         deleteAccountAtFirstLaunch()
         setupFeaturesViewAdapter()
         handleOnBackPressed()
@@ -207,10 +207,9 @@ class FirstRunActivity : BaseActivity(), Injectable {
     }
 
     private fun setSlideshowSize(isLandscape: Boolean) {
-        val isProviderOrOwnInstallationVisible = resources.getBoolean(R.bool.show_provider_or_own_installation)
         binding.buttonLayout.orientation = if (isLandscape) LinearLayout.HORIZONTAL else LinearLayout.VERTICAL
 
-        val layoutParams: LinearLayout.LayoutParams = if (isProviderOrOwnInstallationVisible) {
+        val layoutParams: LinearLayout.LayoutParams = if (MDMConfig.showIntro(this)) {
             LinearLayout.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.WRAP_CONTENT

+ 3 - 3
app/src/main/java/com/nextcloud/client/onboarding/OnboardingServiceImpl.kt

@@ -13,13 +13,14 @@ import android.content.Intent
 import android.content.res.Resources
 import com.nextcloud.client.account.CurrentAccountProvider
 import com.nextcloud.client.preferences.AppPreferences
+import com.nextcloud.utils.mdm.MDMConfig
 import com.owncloud.android.BuildConfig
 import com.owncloud.android.R
 import com.owncloud.android.authentication.AuthenticatorActivity
 import com.owncloud.android.features.FeatureItem
 import com.owncloud.android.ui.activity.PassCodeActivity
 
-internal class OnboardingServiceImpl constructor(
+internal class OnboardingServiceImpl(
     private val resources: Resources,
     private val preferences: AppPreferences,
     private val accountProvider: CurrentAccountProvider
@@ -61,8 +62,7 @@ internal class OnboardingServiceImpl constructor(
     }
 
     override fun launchFirstRunIfNeeded(activity: Activity): Boolean {
-        val isProviderOrOwnInstallationVisible = resources.getBoolean(R.bool.show_provider_or_own_installation)
-        val canLaunch = isProviderOrOwnInstallationVisible && isFirstRun && activity is AuthenticatorActivity
+        val canLaunch = MDMConfig.showIntro(activity) && isFirstRun && activity is AuthenticatorActivity
         if (canLaunch) {
             val intent = Intent(activity, FirstRunActivity::class.java)
             activity.startActivityForResult(intent, AuthenticatorActivity.REQUEST_CODE_FIRST_RUN)

+ 2 - 2
app/src/main/java/com/nextcloud/ui/ChooseAccountDialogFragment.kt

@@ -25,6 +25,7 @@ import com.nextcloud.client.account.UserAccountManager
 import com.nextcloud.client.di.Injectable
 import com.nextcloud.client.network.ClientFactory
 import com.nextcloud.utils.extensions.getParcelableArgument
+import com.nextcloud.utils.mdm.MDMConfig
 import com.owncloud.android.R
 import com.owncloud.android.databinding.DialogChooseAccountBinding
 import com.owncloud.android.datamodel.FileDataStorageManager
@@ -120,8 +121,7 @@ class ChooseAccountDialogFragment :
                 viewThemeUtils
             )
 
-            // hide "add account" when no multi account
-            if (!resources.getBoolean(R.bool.multiaccount_support)) {
+            if (!MDMConfig.multiAccountSupport(requireContext())) {
                 binding.addAccount.visibility = View.GONE
             }
 

+ 134 - 0
app/src/main/java/com/nextcloud/utils/mdm/MDMConfig.kt

@@ -0,0 +1,134 @@
+/*
+ * Nextcloud - Android Client
+ *
+ * SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+package com.nextcloud.utils.mdm
+
+import android.content.Context
+import android.content.RestrictionsManager
+import com.owncloud.android.BuildConfig
+import com.owncloud.android.R
+import com.owncloud.android.utils.appConfig.AppConfigKeys
+
+object MDMConfig {
+    fun multiAccountSupport(context: Context): Boolean {
+        val multiAccountSupport = context.resources.getBoolean(R.bool.multiaccount_support)
+
+        val disableMultiAccountViaMDM = context.getRestriction(
+            AppConfigKeys.DisableMultiAccount,
+            context.resources.getBoolean(R.bool.disable_multiaccount)
+        )
+
+        return multiAccountSupport && !disableMultiAccountViaMDM
+    }
+
+    fun shareViaLink(context: Context): Boolean {
+        val disableShareViaMDM = context.getRestriction(
+            AppConfigKeys.DisableSharing,
+            context.resources.getBoolean(R.bool.disable_sharing)
+        )
+
+        val shareViaLink = context.resources.getBoolean(R.bool.share_via_link_feature)
+
+        return shareViaLink && !disableShareViaMDM
+    }
+
+    fun shareViaUser(context: Context): Boolean {
+        val disableShareViaMDM = context.getRestriction(
+            AppConfigKeys.DisableSharing,
+            context.resources.getBoolean(R.bool.disable_sharing)
+        )
+
+        val shareViaUsers = context.resources.getBoolean(R.bool.share_with_users_feature)
+
+        return shareViaUsers && !disableShareViaMDM
+    }
+
+    fun sendFilesSupport(context: Context): Boolean {
+        val disableShareViaMDM = context.getRestriction(
+            AppConfigKeys.DisableSharing,
+            context.resources.getBoolean(R.bool.disable_sharing)
+        )
+
+        val sendFilesToOtherApp = "on".equals(context.getString(R.string.send_files_to_other_apps), ignoreCase = true)
+
+        return sendFilesToOtherApp && !disableShareViaMDM
+    }
+
+    fun sharingSupport(context: Context): Boolean {
+        val disableShareViaMDM = context.getRestriction(
+            AppConfigKeys.DisableSharing,
+            context.resources.getBoolean(R.bool.disable_sharing)
+        )
+
+        val sendFilesToOtherApp = "on".equals(context.getString(R.string.send_files_to_other_apps), ignoreCase = true)
+
+        val shareViaUsers = context.resources.getBoolean(R.bool.share_with_users_feature)
+
+        val shareViaLink = context.resources.getBoolean(R.bool.share_via_link_feature)
+
+        return sendFilesToOtherApp && shareViaLink && shareViaUsers && !disableShareViaMDM
+    }
+
+    fun clipBoardSupport(context: Context): Boolean {
+        val disableClipboardSupport = context.getRestriction(
+            AppConfigKeys.DisableClipboard,
+            context.resources.getBoolean(R.bool.disable_clipboard)
+        )
+
+        return !disableClipboardSupport
+    }
+
+    fun externalSiteSupport(context: Context): Boolean {
+        val disableMoreExternalSiteViaMDM = context.getRestriction(
+            AppConfigKeys.DisableMoreExternalSite,
+            context.resources.getBoolean(R.bool.disable_more_external_site)
+        )
+
+        val showExternalLinks = context.resources.getBoolean(R.bool.show_external_links)
+
+        return showExternalLinks && !disableMoreExternalSiteViaMDM
+    }
+
+    fun showIntro(context: Context): Boolean {
+        val disableIntroViaMDM =
+            context.getRestriction(AppConfigKeys.DisableIntro, context.resources.getBoolean(R.bool.disable_intro))
+
+        val isProviderOrOwnInstallationVisible = context.resources.getBoolean(R.bool.show_provider_or_own_installation)
+
+        return isProviderOrOwnInstallationVisible && !disableIntroViaMDM
+    }
+
+    fun isLogEnabled(context: Context): Boolean {
+        val disableLogViaMDM =
+            context.getRestriction(AppConfigKeys.DisableLog, context.resources.getBoolean(R.bool.disable_log))
+
+        val loggerEnabled = context.resources.getBoolean(R.bool.logger_enabled)
+
+        return loggerEnabled && !disableLogViaMDM && BuildConfig.DEBUG
+    }
+
+    fun getBaseUrl(context: Context): String = context.getRestriction(AppConfigKeys.BaseUrl, "")
+
+    fun getHost(context: Context): String =
+        context.getRestriction(AppConfigKeys.ProxyHost, context.getString(R.string.proxy_host))
+
+    fun getPort(context: Context): Int =
+        context.getRestriction(AppConfigKeys.ProxyPort, context.resources.getInteger(R.integer.proxy_port))
+
+    @Suppress("UNCHECKED_CAST")
+    private fun <T : Any> Context.getRestriction(appConfigKey: AppConfigKeys, defaultValue: T): T {
+        val restrictionsManager = getSystemService(Context.RESTRICTIONS_SERVICE) as? RestrictionsManager
+        val appRestrictions = restrictionsManager?.getApplicationRestrictions() ?: return defaultValue
+
+        return when (defaultValue) {
+            is String -> appRestrictions.getString(appConfigKey.key, defaultValue) as T? ?: defaultValue
+            is Int -> appRestrictions.getInt(appConfigKey.key, defaultValue) as T? ?: defaultValue
+            is Boolean -> appRestrictions.getBoolean(appConfigKey.key, defaultValue) as T? ?: defaultValue
+            else -> defaultValue
+        }
+    }
+}

+ 42 - 15
app/src/main/java/com/owncloud/android/MainApp.java

@@ -22,11 +22,11 @@ import android.app.Application;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.RestrictionsManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
@@ -62,6 +62,7 @@ import com.nextcloud.client.preferences.DarkMode;
 import com.nextcloud.receiver.NetworkChangeListener;
 import com.nextcloud.receiver.NetworkChangeReceiver;
 import com.nextcloud.utils.extensions.ContextExtensionsKt;
+import com.nextcloud.utils.mdm.MDMConfig;
 import com.nmc.android.ui.LauncherActivity;
 import com.owncloud.android.authentication.PassCodeManager;
 import com.owncloud.android.datamodel.ArbitraryDataProvider;
@@ -87,7 +88,6 @@ 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.appConfig.AppConfigManager;
 import com.owncloud.android.utils.theme.ViewThemeUtils;
 
 import org.conscrypt.Conscrypt;
@@ -199,8 +199,6 @@ public class MainApp extends Application implements HasAndroidInjector, NetworkC
     @SuppressWarnings("unused")
     private boolean mBound;
 
-    private AppConfigManager appConfigManager;
-
     private static AppComponent appComponent;
 
     private NetworkChangeReceiver networkChangeReceiver;
@@ -333,11 +331,7 @@ public class MainApp extends Application implements HasAndroidInjector, NetworkC
         OwnCloudClientManagerFactory.setUserAgent(getUserAgent());
 
         if (isClientBrandedPlus()) {
-            RestrictionsManager restrictionsManager = (RestrictionsManager) getSystemService(Context.RESTRICTIONS_SERVICE);
-            appConfigManager = new AppConfigManager(this, restrictionsManager.getApplicationRestrictions());
-            appConfigManager.setProxyConfig(isClientBrandedPlus());
-
-            // Listen app config changes
+            setProxyConfig();
             ContextExtensionsKt.registerBroadcastReceiver(this, restrictionsReceiver, restrictionsFilter, ReceiverFlag.NotExported);
         } else {
             setProxyForNonBrandedPlusClients();
@@ -346,8 +340,7 @@ public class MainApp extends Application implements HasAndroidInjector, NetworkC
         // initialise thumbnails cache on background thread
         new ThumbnailsCacheManager.InitDiskCacheTask().execute();
 
-
-        if (BuildConfig.DEBUG || getApplicationContext().getResources().getBoolean(R.bool.logger_enabled)) {
+        if (MDMConfig.INSTANCE.isLogEnabled(this)) {
             // use app writable dir, no permissions needed
             Log_OC.setLoggerImplementation(new LegacyLoggerAdapter(logger));
             Log_OC.d("Debug", "start logging");
@@ -388,6 +381,18 @@ public class MainApp extends Application implements HasAndroidInjector, NetworkC
         registerGlobalPassCodeProtection();
         networkChangeReceiver = new NetworkChangeReceiver(this, connectivityService);
         registerNetworkChangeReceiver();
+
+        if (!MDMConfig.INSTANCE.sendFilesSupport(this)) {
+            disableDocumentsStorageProvider();
+        }
+     }
+
+    public void disableDocumentsStorageProvider() {
+        String packageName = getPackageName();
+        String providerClassName = "com.owncloud.android.providers.DocumentsStorageProvider";
+        ComponentName componentName = new ComponentName(packageName, providerClassName);
+        PackageManager packageManager = getPackageManager();
+        packageManager.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
     }
 
     private final LifecycleEventObserver lifecycleEventObserver = ((lifecycleOwner, event) -> {
@@ -397,8 +402,7 @@ public class MainApp extends Application implements HasAndroidInjector, NetworkC
             passCodeManager.setCanAskPin(true);
             Log_OC.d(TAG, "APP IN BACKGROUND");
         } else if (event == Lifecycle.Event.ON_RESUME) {
-            if (appConfigManager == null) return;
-            appConfigManager.setProxyConfig(isClientBrandedPlus());
+            setProxyConfig();
             Log_OC.d(TAG, "APP ON RESUME");
         }
     });
@@ -420,11 +424,34 @@ public class MainApp extends Application implements HasAndroidInjector, NetworkC
 
     private final BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
         @Override public void onReceive(Context context, Intent intent) {
-            if (appConfigManager == null) return;
-            appConfigManager.setProxyConfig(isClientBrandedPlus());
+            setProxyConfig();
         }
     };
 
+    private void setProxyConfig() {
+        if (!isClientBrandedPlus()) {
+            Log_OC.d(TAG, "Proxy configuration cannot be set. Client is not branded plus.");
+            return;
+        }
+
+        String host = MDMConfig.INSTANCE.getHost(this);
+        int port = MDMConfig.INSTANCE.getPort(this);
+
+        if (TextUtils.isEmpty(host) || port == -1) {
+            Log_OC.d(TAG, "Proxy configuration cannot be found");
+            return;
+        }
+
+        try {
+            OwnCloudClientManagerFactory.setProxyHost(host);
+            OwnCloudClientManagerFactory.setProxyPort(port);
+
+            Log_OC.d(TAG, "Proxy configuration successfully set");
+        } catch (Resources.NotFoundException e) {
+            Log_OC.e(TAG, "Proxy config cannot able to set due to: $e");
+        }
+    }
+
     private void registerGlobalPassCodeProtection() {
         registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
 

+ 2 - 1
app/src/main/java/com/owncloud/android/authentication/AccountAuthenticator.java

@@ -21,6 +21,7 @@ import android.os.Bundle;
 import android.os.Handler;
 import android.widget.Toast;
 
+import com.nextcloud.utils.mdm.MDMConfig;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.lib.common.accounts.AccountTypeUtils;
@@ -70,7 +71,7 @@ public class AccountAuthenticator extends AbstractAccountAuthenticator {
 
         final Bundle bundle = new Bundle();
 
-        if (mContext.getResources().getBoolean(R.bool.multiaccount_support) || accounts.length < 1) {
+        if (accounts.length < 1 || MDMConfig.INSTANCE.multiAccountSupport(mContext)) {
             try {
                 validateAccountType(accountType);
             } catch (AuthenticatorException e) {

+ 6 - 10
app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java

@@ -21,7 +21,6 @@ import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.RestrictionsManager;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
@@ -71,6 +70,7 @@ import com.nextcloud.client.preferences.AppPreferences;
 import com.nextcloud.common.PlainClient;
 import com.nextcloud.operations.PostMethod;
 import com.nextcloud.utils.extensions.BundleExtensionsKt;
+import com.nextcloud.utils.mdm.MDMConfig;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.databinding.AccountSetupBinding;
@@ -112,7 +112,6 @@ import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.ErrorMessageAdapter;
 import com.owncloud.android.utils.PermissionUtil;
 import com.owncloud.android.utils.WebViewUtil;
-import com.owncloud.android.utils.appConfig.AppConfigManager;
 import com.owncloud.android.utils.theme.CapabilityUtils;
 import com.owncloud.android.utils.theme.ViewThemeUtils;
 
@@ -320,11 +319,9 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
         String webloginUrl = null;
 
         if (MainApp.isClientBrandedPlus()) {
-            RestrictionsManager restrictionsManager = (RestrictionsManager) getSystemService(Context.RESTRICTIONS_SERVICE);
-            AppConfigManager appConfigManager = new AppConfigManager(this, restrictionsManager.getApplicationRestrictions());
-
-            if (!TextUtils.isEmpty(appConfigManager.getBaseUrl(MainApp.isClientBrandedPlus()))) {
-                webloginUrl = appConfigManager.getBaseUrl(MainApp.isClientBrandedPlus()) + WEB_LOGIN;
+            String baseUrl = MDMConfig.INSTANCE.getBaseUrl(this);
+            if (!TextUtils.isEmpty(baseUrl)) {
+                webloginUrl = baseUrl + WEB_LOGIN;
             }
         }
 
@@ -812,9 +809,8 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
         passCodeManager.onActivityResumed(this);
 
         Uri data = intent.getData();
-
         if (data != null && data.toString().startsWith(getString(R.string.login_data_own_scheme))) {
-            if (!getResources().getBoolean(R.bool.multiaccount_support) &&
+            if (!MDMConfig.INSTANCE.multiAccountSupport(this) &&
                 accountManager.getAccounts().length == 1) {
                 Toast.makeText(this, R.string.no_mutliple_accounts_allowed, Toast.LENGTH_LONG).show();
                 finish();
@@ -1535,7 +1531,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
                     return;
                 }
 
-                if (!getResources().getBoolean(R.bool.multiaccount_support) &&
+                if (!MDMConfig.INSTANCE.multiAccountSupport(this) &&
                     accountManager.getAccounts().length == 1) {
                     Toast.makeText(this, R.string.no_mutliple_accounts_allowed, Toast.LENGTH_LONG).show();
                 } else {

+ 2 - 4
app/src/main/java/com/owncloud/android/authentication/DeepLinkLoginActivity.kt

@@ -11,16 +11,14 @@ import android.os.Bundle
 import android.widget.TextView
 import android.widget.Toast
 import com.nextcloud.client.di.Injectable
+import com.nextcloud.utils.mdm.MDMConfig
 import com.owncloud.android.R
 
 class DeepLinkLoginActivity : AuthenticatorActivity(), Injectable {
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
-
-        if (!resources.getBoolean(R.bool.multiaccount_support) &&
-            accountManager.accounts.size == 1
-        ) {
+        if (!MDMConfig.multiAccountSupport(this) && accountManager.accounts.size == 1) {
             Toast.makeText(this, R.string.no_mutliple_accounts_allowed, Toast.LENGTH_LONG).show()
             return
         }

+ 21 - 7
app/src/main/java/com/owncloud/android/files/FileMenuFilter.java

@@ -23,6 +23,7 @@ import com.nextcloud.client.editimage.EditImageActivity;
 import com.nextcloud.client.jobs.download.FileDownloadHelper;
 import com.nextcloud.client.jobs.upload.FileUploadHelper;
 import com.nextcloud.utils.EditorUtils;
+import com.nextcloud.utils.mdm.MDMConfig;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.FileDataStorageManager;
 import com.owncloud.android.datamodel.OCFile;
@@ -184,9 +185,24 @@ public class FileMenuFilter {
     }
 
     private void filterSendFiles(List<Integer> toHide, boolean inSingleFileFragment) {
-        if ((overflowMenu || SEND_OFF.equalsIgnoreCase(context.getString(R.string.send_files_to_other_apps)) || containsEncryptedFile()) ||
-            (!inSingleFileFragment && (isSingleSelection() || !allFileDown())) ||
-            !toHide.contains(R.id.action_send_share_file)) {
+        boolean sendFilesNotSupported = context != null && !MDMConfig.INSTANCE.sendFilesSupport(context);
+        boolean hasEncryptedFile = containsEncryptedFile();
+        boolean isSingleSelection = isSingleSelection();
+        boolean allFilesNotDown = !allFileDown();
+
+        if (sendFilesNotSupported) {
+            toHide.add(R.id.action_send_file);
+            return;
+        }
+
+        if (overflowMenu || hasEncryptedFile) {
+            toHide.add(R.id.action_send_file);
+            return;
+        }
+
+        if (!inSingleFileFragment && (isSingleSelection || allFilesNotDown)) {
+            toHide.add(R.id.action_send_file);
+        } else if (!toHide.contains(R.id.action_send_share_file)) {
             toHide.add(R.id.action_send_file);
         }
     }
@@ -425,13 +441,11 @@ public class FileMenuFilter {
     }
 
     private boolean isShareWithUsersAllowed() {
-        return context != null &&
-            context.getResources().getBoolean(R.bool.share_with_users_feature);
+        return context != null && MDMConfig.INSTANCE.shareViaUser(context);
     }
 
     private boolean isShareViaLinkAllowed() {
-        return context != null &&
-            context.getResources().getBoolean(R.bool.share_via_link_feature);
+        return context != null && MDMConfig.INSTANCE.shareViaLink(context);
     }
 
     private boolean isSingleSelection() {

+ 5 - 7
app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java

@@ -59,6 +59,7 @@ import com.nextcloud.common.NextcloudClient;
 import com.nextcloud.ui.ChooseAccountDialogFragment;
 import com.nextcloud.ui.composeActivity.ComposeActivity;
 import com.nextcloud.ui.composeActivity.ComposeDestination;
+import com.nextcloud.utils.mdm.MDMConfig;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.PassCodeManager;
@@ -602,10 +603,7 @@ public abstract class DrawerActivity extends ToolbarActivity
     }
 
     public void openAddAccount() {
-        boolean isProviderOrOwnInstallationVisible = getResources()
-            .getBoolean(R.bool.show_provider_or_own_installation);
-
-        if (isProviderOrOwnInstallationVisible) {
+        if (MDMConfig.INSTANCE.showIntro(this)) {
             Intent firstRunIntent = new Intent(getApplicationContext(), FirstRunActivity.class);
             firstRunIntent.putExtra(FirstRunActivity.EXTRA_ALLOW_CLOSE, true);
             startActivity(firstRunIntent);
@@ -824,7 +822,7 @@ public abstract class DrawerActivity extends ToolbarActivity
 
     private void updateQuotaLink() {
         if (mQuotaTextLink != null) {
-            if (getBaseContext().getResources().getBoolean(R.bool.show_external_links)) {
+            if (MDMConfig.INSTANCE.externalSiteSupport(this)) {
                 List<ExternalLink> quotas = externalLinksProvider.getExternalLink(ExternalLinkType.QUOTA);
 
                 float density = getResources().getDisplayMetrics().density;
@@ -973,7 +971,7 @@ public abstract class DrawerActivity extends ToolbarActivity
     }
 
     private void updateExternalLinksInDrawer() {
-        if (mNavigationView != null && getBaseContext().getResources().getBoolean(R.bool.show_external_links)) {
+        if (mNavigationView != null && MDMConfig.INSTANCE.externalSiteSupport(this)) {
             mNavigationView.getMenu().removeGroup(R.id.drawer_menu_external_links);
 
             int greyColor = ContextCompat.getColor(this, R.color.drawer_menu_icon);
@@ -1222,7 +1220,7 @@ public abstract class DrawerActivity extends ToolbarActivity
      * Retrieves external links via api from 'external' app
      */
     public void fetchExternalLinks(final boolean force) {
-        if (!getBaseContext().getResources().getBoolean(R.bool.show_external_links)) {
+        if (!MDMConfig.INSTANCE.externalSiteSupport(this)) {
             return;
         }
 

+ 9 - 6
app/src/main/java/com/owncloud/android/ui/activity/FileActivity.java

@@ -45,6 +45,7 @@ import com.nextcloud.utils.extensions.ActivityExtensionsKt;
 import com.nextcloud.utils.extensions.BundleExtensionsKt;
 import com.nextcloud.utils.extensions.FileExtensionsKt;
 import com.nextcloud.utils.extensions.IntentExtensionsKt;
+import com.nextcloud.utils.mdm.MDMConfig;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.AuthenticatorActivity;
@@ -718,12 +719,14 @@ public abstract class FileActivity extends DrawerActivity
                                             OCFile file,
                                             String link,
                                             final ViewThemeUtils viewThemeUtils) {
-        ClipboardUtil.copyToClipboard(activity, link, false);
-        Snackbar snackbar = Snackbar.make(activity.findViewById(android.R.id.content), R.string.clipboard_text_copied,
-                                          Snackbar.LENGTH_LONG)
-            .setAction(R.string.share, v -> showShareLinkDialog(activity, file, link));
-        viewThemeUtils.material.themeSnackbar(snackbar);
-        snackbar.show();
+        if (MDMConfig.INSTANCE.shareViaLink(activity) && MDMConfig.INSTANCE.clipBoardSupport(activity)) {
+            ClipboardUtil.copyToClipboard(activity, link, false);
+            Snackbar snackbar = Snackbar.make(activity.findViewById(android.R.id.content), R.string.clipboard_text_copied,
+                                              Snackbar.LENGTH_LONG)
+                .setAction(R.string.share, v -> showShareLinkDialog(activity, file, link));
+            viewThemeUtils.material.themeSnackbar(snackbar);
+            snackbar.show();
+        }
     }
 
     public static void showShareLinkDialog(FileActivity activity, ServerFileInterface file, String link) {

+ 3 - 3
app/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java

@@ -30,6 +30,7 @@ import com.nextcloud.client.onboarding.FirstRunActivity;
 import com.nextcloud.model.WorkerState;
 import com.nextcloud.model.WorkerStateLiveData;
 import com.nextcloud.utils.extensions.BundleExtensionsKt;
+import com.nextcloud.utils.mdm.MDMConfig;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.AuthenticatorActivity;
@@ -131,8 +132,7 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap
         }
 
         arbitraryDataProvider = new ArbitraryDataProviderImpl(this);
-
-        multipleAccountsSupported = getResources().getBoolean(R.bool.multiaccount_support);
+        multipleAccountsSupported = MDMConfig.INSTANCE.multiAccountSupport(this);
 
         userListAdapter = new UserListAdapter(this,
                                               accountManager,
@@ -230,7 +230,7 @@ public class ManageAccountsActivity extends FileActivity implements UserListAdap
             userListItems.add(new UserListItem(user, !pendingForRemoval));
         }
 
-        if (getResources().getBoolean(R.bool.multiaccount_support)) {
+        if (MDMConfig.INSTANCE.multiAccountSupport(this)) {
             userListItems.add(new UserListItem());
         }
 

+ 3 - 5
app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java

@@ -50,7 +50,7 @@ import com.nextcloud.client.network.ConnectivityService;
 import com.nextcloud.client.preferences.AppPreferences;
 import com.nextcloud.client.preferences.AppPreferencesImpl;
 import com.nextcloud.client.preferences.DarkMode;
-import com.owncloud.android.BuildConfig;
+import com.nextcloud.utils.mdm.MDMConfig;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.authentication.AuthenticatorActivity;
@@ -379,11 +379,9 @@ public class SettingsActivity extends PreferenceActivity
     }
 
     private void setupLoggingPreference(PreferenceCategory preferenceCategoryMore) {
-
-        boolean loggerEnabled = getResources().getBoolean(R.bool.logger_enabled) || BuildConfig.DEBUG;
         Preference pLogger = findPreference("logger");
         if (pLogger != null) {
-            if (loggerEnabled) {
+            if (MDMConfig.INSTANCE.isLogEnabled(this)) {
                 pLogger.setOnPreferenceClickListener(preference -> {
                     Intent loggerIntent = new Intent(getApplicationContext(), LogsActivity.class);
                     startActivity(loggerIntent);
@@ -1101,7 +1099,7 @@ public class SettingsActivity extends PreferenceActivity
     }
 
     private void loadExternalSettingLinks(PreferenceCategory preferenceCategory) {
-        if (getBaseContext().getResources().getBoolean(R.bool.show_external_links)) {
+        if (MDMConfig.INSTANCE.externalSiteSupport(this)) {
             ExternalLinksProvider externalLinksProvider = new ExternalLinksProvider(getContentResolver());
 
             for (final ExternalLink link : externalLinksProvider.getExternalLink(ExternalLinkType.SETTINGS)) {

+ 7 - 1
app/src/main/java/com/owncloud/android/ui/adapter/LinkShareViewHolder.java

@@ -19,6 +19,7 @@ import android.graphics.PorterDuff;
 import android.text.TextUtils;
 import android.view.View;
 
+import com.nextcloud.utils.mdm.MDMConfig;
 import com.owncloud.android.R;
 import com.owncloud.android.databinding.FileDetailsShareLinkShareItemBinding;
 import com.owncloud.android.lib.resources.shares.OCShare;
@@ -78,11 +79,16 @@ class LinkShareViewHolder extends RecyclerView.ViewHolder {
         String permissionName = SharingMenuHelper.getPermissionName(context, publicShare);
         setPermissionName(publicShare, permissionName);
 
-        binding.copyLink.setOnClickListener(v -> listener.copyLink(publicShare));
         binding.overflowMenu.setOnClickListener(v -> listener.showSharingMenuActionSheet(publicShare));
         if (!SharingMenuHelper.isSecureFileDrop(publicShare)) {
             binding.shareByLinkContainer.setOnClickListener(v -> listener.showPermissionsDialog(publicShare));
         }
+
+        if (MDMConfig.INSTANCE.clipBoardSupport(context)) {
+            binding.copyLink.setOnClickListener(v -> listener.copyLink(publicShare));
+        } else {
+            binding.copyLink.setVisibility(View.GONE);
+        }
     }
 
     private void setPermissionName(OCShare publicShare, String permissionName) {

+ 6 - 1
app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java

@@ -36,9 +36,10 @@ import com.nextcloud.client.account.User;
 import com.nextcloud.client.database.entity.OfflineOperationEntity;
 import com.nextcloud.client.jobs.upload.FileUploadHelper;
 import com.nextcloud.client.preferences.AppPreferences;
-import com.nextcloud.model.OfflineOperationType;
 import com.nextcloud.model.OCFileFilterType;
+import com.nextcloud.model.OfflineOperationType;
 import com.nextcloud.utils.extensions.ViewExtensionsKt;
+import com.nextcloud.utils.mdm.MDMConfig;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.databinding.GridImageBinding;
@@ -458,6 +459,10 @@ public class OCFileListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
             }
 
             updateLivePhotoIndicators(gridViewHolder, file);
+
+            if (!MDMConfig.INSTANCE.sharingSupport(activity)) {
+                gridViewHolder.getShared().setVisibility(View.GONE);
+            }
         }
     }
 

+ 7 - 0
app/src/main/java/com/owncloud/android/ui/adapter/OCFileListDelegate.kt

@@ -22,6 +22,7 @@ import com.nextcloud.client.jobs.download.FileDownloadHelper
 import com.nextcloud.client.jobs.upload.FileUploadHelper
 import com.nextcloud.client.preferences.AppPreferences
 import com.nextcloud.utils.extensions.createRoundedOutline
+import com.nextcloud.utils.mdm.MDMConfig
 import com.owncloud.android.R
 import com.owncloud.android.datamodel.FileDataStorageManager
 import com.owncloud.android.datamodel.OCFile
@@ -368,6 +369,12 @@ class OCFileListDelegate(
 
     private fun showShareIcon(gridViewHolder: ListViewHolder, file: OCFile) {
         val sharedIconView = gridViewHolder.shared
+
+        if (!MDMConfig.sharingSupport(context)) {
+            sharedIconView.visibility = View.GONE
+            return
+        }
+
         if (gridViewHolder is OCFileListItemViewHolder || file.unreadCommentsCount == 0) {
             sharedIconView.visibility = View.VISIBLE
             if (file.isSharedWithSharee || file.isSharedWithMe) {

+ 59 - 34
app/src/main/java/com/owncloud/android/ui/adapter/ShareeListAdapter.java

@@ -14,10 +14,12 @@ package com.owncloud.android.ui.adapter;
 import android.annotation.SuppressLint;
 import android.graphics.drawable.Drawable;
 import android.view.LayoutInflater;
+import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 
 import com.nextcloud.client.account.User;
+import com.nextcloud.utils.mdm.MDMConfig;
 import com.owncloud.android.R;
 import com.owncloud.android.databinding.FileDetailsShareInternalShareLinkBinding;
 import com.owncloud.android.databinding.FileDetailsShareLinkShareItemBinding;
@@ -79,43 +81,51 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
     @NonNull
     @Override
     public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
-        switch (ShareType.fromValue(viewType)) {
-            case PUBLIC_LINK, EMAIL -> {
-                return new LinkShareViewHolder(
-                    FileDetailsShareLinkShareItemBinding.inflate(LayoutInflater.from(fileActivity),
-                                                                 parent,
-                                                                 false),
-                    fileActivity,
-                    viewThemeUtils);
-            }
-            case NEW_PUBLIC_LINK -> {
-                if (encrypted) {
-                    return new NewSecureFileDropViewHolder(
-                        FileDetailsShareSecureFileDropAddNewItemBinding.inflate(LayoutInflater.from(fileActivity),
+        boolean shareViaLink = MDMConfig.INSTANCE.shareViaLink(fileActivity);
+
+        if (shareViaLink) {
+            switch (ShareType.fromValue(viewType)) {
+                case PUBLIC_LINK, EMAIL -> {
+                    return new LinkShareViewHolder(
+                        FileDetailsShareLinkShareItemBinding.inflate(LayoutInflater.from(fileActivity),
+                                                                     parent,
+                                                                     false),
+                        fileActivity,
+                        viewThemeUtils);
+                }
+                case NEW_PUBLIC_LINK -> {
+                    if (encrypted) {
+                        return new NewSecureFileDropViewHolder(
+                            FileDetailsShareSecureFileDropAddNewItemBinding.inflate(LayoutInflater.from(fileActivity),
+                                                                                    parent,
+                                                                                    false)
+                        );
+                    } else {
+                        return new NewLinkShareViewHolder(
+                            FileDetailsSharePublicLinkAddNewItemBinding.inflate(LayoutInflater.from(fileActivity),
                                                                                 parent,
                                                                                 false)
-                    );
-                } else {
-                    return new NewLinkShareViewHolder(
-                        FileDetailsSharePublicLinkAddNewItemBinding.inflate(LayoutInflater.from(fileActivity),
-                                                                            parent,
-                                                                            false)
-                    );
+                        );
+                    }
+                }
+                case INTERNAL -> {
+                    return new InternalShareViewHolder(
+                        FileDetailsShareInternalShareLinkBinding.inflate(LayoutInflater.from(fileActivity), parent, false),
+                        fileActivity);
+                }
+                default -> {
+                    return new ShareViewHolder(FileDetailsShareShareItemBinding.inflate(LayoutInflater.from(fileActivity),
+                                                                                        parent,
+                                                                                        false),
+                                               user,
+                                               fileActivity,
+                                               viewThemeUtils);
                 }
             }
-            case INTERNAL -> {
-                return new InternalShareViewHolder(
-                    FileDetailsShareInternalShareLinkBinding.inflate(LayoutInflater.from(fileActivity), parent, false),
-                    fileActivity);
-            }
-            default -> {
-                return new ShareViewHolder(FileDetailsShareShareItemBinding.inflate(LayoutInflater.from(fileActivity),
-                                                                                    parent,
-                                                                                    false),
-                                           user,
-                                           fileActivity,
-                                           viewThemeUtils);
-            }
+        } else {
+            return new InternalShareViewHolder(
+                FileDetailsShareInternalShareLinkBinding.inflate(LayoutInflater.from(fileActivity), parent, false),
+                fileActivity);
         }
     }
 
@@ -127,6 +137,16 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
 
         final OCShare share = shares.get(position);
 
+        boolean shareViaLink = MDMConfig.INSTANCE.shareViaLink(fileActivity);
+
+        if (!shareViaLink) {
+            if (holder instanceof InternalShareViewHolder internalShareViewHolder) {
+                internalShareViewHolder.bind(share, listener);
+            }
+
+            return;
+        }
+
         if (holder instanceof LinkShareViewHolder publicShareViewHolder) {
             publicShareViewHolder.bind(share, listener);
         } else if (holder instanceof InternalShareViewHolder internalShareViewHolder) {
@@ -148,7 +168,12 @@ public class ShareeListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
 
     @Override
     public int getItemCount() {
-        return shares.size();
+        boolean shareViaLink = MDMConfig.INSTANCE.shareViaLink(fileActivity);
+        if (shareViaLink) {
+            return shares.size();
+        } else {
+            return 1;
+        }
     }
 
     @SuppressLint("NotifyDataSetChanged")

+ 13 - 6
app/src/main/java/com/owncloud/android/ui/adapter/UserListAdapter.java

@@ -22,6 +22,7 @@ import android.widget.ImageView;
 
 import com.nextcloud.client.account.User;
 import com.nextcloud.client.account.UserAccountManager;
+import com.nextcloud.utils.mdm.MDMConfig;
 import com.owncloud.android.R;
 import com.owncloud.android.databinding.AccountActionBinding;
 import com.owncloud.android.databinding.AccountItemBinding;
@@ -94,7 +95,9 @@ public class UserListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
                                              viewThemeUtils);
         } else {
             return new AddAccountViewHolderItem(
-                AccountActionBinding.inflate(LayoutInflater.from(context), parent, false));
+                AccountActionBinding.inflate(LayoutInflater.from(context), parent, false),
+                context
+            );
         }
     }
 
@@ -303,8 +306,11 @@ public class UserListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
      */
     static class AddAccountViewHolderItem extends RecyclerView.ViewHolder {
 
-        AddAccountViewHolderItem(@NonNull AccountActionBinding binding) {
+        private final Context context;
+
+        AddAccountViewHolderItem(@NonNull AccountActionBinding binding, Context context) {
             super(binding.getRoot());
+            this.context = context;
         }
 
         /**
@@ -313,11 +319,12 @@ public class UserListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
          * @param accountListAdapterListener {@link Listener}
          */
         private void bind(Listener accountListAdapterListener) {
-            // bind action listener
-            boolean isProviderOrOwnInstallationVisible = itemView.getContext().getResources()
-                .getBoolean(R.bool.show_provider_or_own_installation);
+            if (context == null) {
+                Log_OC.d(TAG,"Context cannot be null, AddAccountViewHolderItem onClick is disabled");
+                return;
+            }
 
-            if (isProviderOrOwnInstallationVisible) {
+            if (MDMConfig.INSTANCE.showIntro(context)) {
                 itemView.setOnClickListener(v -> accountListAdapterListener.showFirstRunActivity());
             } else {
                 itemView.setOnClickListener(v -> accountListAdapterListener.startAccountCreation());

+ 1 - 1
app/src/main/java/com/owncloud/android/ui/dialog/MultipleAccountsDialog.kt

@@ -65,7 +65,7 @@ class MultipleAccountsDialog : DialogFragment(), Injectable, UserListAdapter.Cli
     private val accountListItems: List<UserListItem>
         /**
          * creates the account list items list including the add-account action in case
-         * multiaccount_support is enabled.
+         * multi account support is enabled.
          *
          * @return list of account list items
          */

+ 11 - 1
app/src/main/java/com/owncloud/android/ui/dialog/SendShareDialog.kt

@@ -27,6 +27,7 @@ import com.nextcloud.android.common.ui.theme.utils.ColorRole
 import com.nextcloud.client.di.Injectable
 import com.nextcloud.client.utils.IntentUtil.createSendIntent
 import com.nextcloud.utils.extensions.getParcelableArgument
+import com.nextcloud.utils.mdm.MDMConfig
 import com.owncloud.android.BuildConfig
 import com.owncloud.android.R
 import com.owncloud.android.databinding.SendShareFragmentBinding
@@ -73,7 +74,12 @@ class SendShareDialog : BottomSheetDialogFragment(R.layout.send_share_fragment),
         binding = SendShareFragmentBinding.inflate(inflater, container, false)
 
         binding.btnShare.setOnClickListener { shareFile(file) }
-        binding.btnLink.setOnClickListener { shareByLink() }
+
+        if (MDMConfig.shareViaLink(requireContext()) && MDMConfig.clipBoardSupport(requireContext())) {
+            binding.btnLink.setOnClickListener { shareByLink() }
+        } else {
+            binding.btnLink.visibility = View.GONE
+        }
 
         applyTintColor()
         setupBottomSheetBehaviour()
@@ -85,6 +91,10 @@ class SendShareDialog : BottomSheetDialogFragment(R.layout.send_share_fragment),
 
     @Suppress("MagicNumber")
     private fun setupSendButtonRecyclerView() {
+        if (!MDMConfig.sendFilesSupport(requireContext())) {
+            return
+        }
+
         val sendIntent = createSendIntent(requireContext(), file!!)
         val sendButtonDataList = setupSendButtonData(sendIntent)
         val clickListener = setupSendButtonClickListener(sendIntent)

+ 5 - 0
app/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java

@@ -36,6 +36,7 @@ import com.nextcloud.ui.fileactions.FileActionsBottomSheet;
 import com.nextcloud.utils.MenuUtils;
 import com.nextcloud.utils.extensions.BundleExtensionsKt;
 import com.nextcloud.utils.extensions.FileExtensionsKt;
+import com.nextcloud.utils.mdm.MDMConfig;
 import com.owncloud.android.MainApp;
 import com.owncloud.android.R;
 import com.owncloud.android.databinding.FileDetailsFragmentBinding;
@@ -841,6 +842,10 @@ public class FileDetailFragment extends FileFragment implements OnClickListener,
     }
 
     private boolean showSharingTab() {
+         if (!MDMConfig.INSTANCE.shareViaLink(requireContext()) && !MDMConfig.INSTANCE.shareViaUser(requireContext())) {
+            return false;
+        }
+
         if (getFile().isEncrypted()) {
             if (parentFolder == null) {
                 parentFolder = storageManager.getFileById(getFile().getParentId());

+ 16 - 3
app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingFragment.java

@@ -37,6 +37,7 @@ import com.nextcloud.client.di.Injectable;
 import com.nextcloud.client.network.ClientFactory;
 import com.nextcloud.utils.extensions.BundleExtensionsKt;
 import com.nextcloud.utils.extensions.FileExtensionsKt;
+import com.nextcloud.utils.mdm.MDMConfig;
 import com.owncloud.android.R;
 import com.owncloud.android.databinding.FileDetailsSharingFragmentBinding;
 import com.owncloud.android.datamodel.FileDataStorageManager;
@@ -244,6 +245,14 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
             binding.pickContactEmailBtn.setVisibility(View.GONE);
             disableSearchView(binding.searchView);
         }
+
+        checkShareViaUser();
+    }
+
+    private void checkShareViaUser() {
+        if (!MDMConfig.INSTANCE.shareViaUser(requireContext())) {
+            binding.searchContainer.setVisibility(View.GONE);
+        }
     }
 
     private void disableSearchView(View view) {
@@ -494,9 +503,13 @@ public class FileDetailSharingFragment extends Fragment implements ShareeListAda
     }
 
     private void pickContactEmail() {
-        Intent intent = new Intent(Intent.ACTION_PICK);
-        intent.setDataAndType(ContactsContract.Contacts.CONTENT_URI, ContactsContract.CommonDataKinds.Email.CONTENT_TYPE);
-        onContactSelectionResultLauncher.launch(intent);
+        Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Email.CONTENT_URI);
+
+        if (intent.resolveActivity(requireContext().getPackageManager()) != null) {
+            onContactSelectionResultLauncher.launch(intent);
+        } else {
+            DisplayUtils.showSnackMessage(requireActivity(), getString(R.string.file_detail_sharing_fragment_no_contact_app_message));
+        }
     }
 
     private void handleContactResult(@NonNull Uri contactUri) {

+ 5 - 1
app/src/main/java/com/owncloud/android/ui/fragment/FileDetailSharingMenuBottomSheetDialog.java

@@ -16,6 +16,7 @@ import android.view.ViewGroup;
 
 import com.google.android.material.bottomsheet.BottomSheetBehavior;
 import com.google.android.material.bottomsheet.BottomSheetDialog;
+import com.nextcloud.utils.mdm.MDMConfig;
 import com.owncloud.android.databinding.FileDetailsSharingMenuBottomSheetFragmentBinding;
 import com.owncloud.android.lib.resources.shares.OCShare;
 import com.owncloud.android.lib.resources.shares.ShareType;
@@ -72,7 +73,10 @@ public class FileDetailSharingMenuBottomSheetDialog extends BottomSheetDialog {
     private void updateUI() {
         if (ocShare.getShareType() == ShareType.PUBLIC_LINK) {
             binding.menuShareAddAnotherLink.setVisibility(View.VISIBLE);
-            binding.menuShareSendLink.setVisibility(View.VISIBLE);
+
+            if (MDMConfig.INSTANCE.sendFilesSupport(getContext())) {
+                binding.menuShareSendLink.setVisibility(View.VISIBLE);
+            }
         } else {
             binding.menuShareAddAnotherLink.setVisibility(View.GONE);
             binding.menuShareSendLink.setVisibility(View.GONE);

+ 5 - 0
app/src/main/java/com/owncloud/android/utils/ClipboardUtil.kt

@@ -12,6 +12,7 @@ import android.content.ClipboardManager
 import android.content.Context
 import android.text.TextUtils
 import android.widget.Toast
+import com.nextcloud.utils.mdm.MDMConfig
 import com.owncloud.android.R
 import com.owncloud.android.lib.common.utils.Log_OC
 
@@ -25,6 +26,10 @@ object ClipboardUtil {
     @JvmOverloads
     @Suppress("TooGenericExceptionCaught")
     fun copyToClipboard(activity: Activity, text: String?, showToast: Boolean = true) {
+        if (!MDMConfig.clipBoardSupport(activity)) {
+            return
+        }
+
         if (!TextUtils.isEmpty(text)) {
             try {
                 val clip = ClipData.newPlainText(

+ 7 - 1
app/src/main/java/com/owncloud/android/utils/appConfig/AppConfigKeys.kt

@@ -13,5 +13,11 @@ package com.owncloud.android.utils.appConfig
 enum class AppConfigKeys(val key: String) {
     BaseUrl("base_url"),
     ProxyHost("proxy_host"),
-    ProxyPort("proxy_port")
+    ProxyPort("proxy_port"),
+    DisableMultiAccount("disable_multiaccount"),
+    DisableSharing("disable_sharing"),
+    DisableClipboard("disable_clipboard"),
+    DisableMoreExternalSite("disable_more_external_site"),
+    DisableIntro("disable_intro"),
+    DisableLog("disable_log")
 }

+ 0 - 68
app/src/main/java/com/owncloud/android/utils/appConfig/AppConfigManager.kt

@@ -1,68 +0,0 @@
-/*
- * Nextcloud - Android Client
- *
- * SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
- * SPDX-License-Identifier: AGPL-3.0-or-later
- */
-
-package com.owncloud.android.utils.appConfig
-
-import android.content.Context
-import android.content.res.Resources
-import android.os.Bundle
-import android.text.TextUtils
-import com.owncloud.android.R
-import com.owncloud.android.lib.common.OwnCloudClientManagerFactory
-import com.owncloud.android.lib.common.utils.Log_OC
-
-class AppConfigManager(private val context: Context, private val appRestrictions: Bundle) {
-
-    private val tag = "AppConfigManager"
-
-    fun setProxyConfig(isBrandedPlus: Boolean) {
-        if (!isBrandedPlus) {
-            Log_OC.d(tag, "Proxy configuration cannot be set. Client is not branded plus.")
-            return
-        }
-
-        val host = if (appRestrictions.containsKey(AppConfigKeys.ProxyHost.key)) {
-            appRestrictions.getString(AppConfigKeys.ProxyHost.key)
-        } else {
-            context.getString(R.string.proxy_host)
-        }
-
-        val port = if (appRestrictions.containsKey(AppConfigKeys.ProxyPort.key)) {
-            appRestrictions.getInt(AppConfigKeys.ProxyPort.key)
-        } else {
-            context.resources.getInteger(R.integer.proxy_port)
-        }
-
-        if (TextUtils.isEmpty(host) || port == -1) {
-            Log_OC.d(tag, "Proxy configuration cannot be found")
-            return
-        }
-
-        try {
-            OwnCloudClientManagerFactory.setProxyHost(host)
-            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")
-        }
-    }
-
-    fun getBaseUrl(isBrandedPlus: Boolean): String? {
-        if (!isBrandedPlus) {
-            Log_OC.d(tag, "Proxy configuration cannot be set. Client is not branded plus. Default url applied")
-            return null
-        }
-
-        return if (appRestrictions.containsKey(AppConfigKeys.BaseUrl.key)) {
-            appRestrictions.getString(AppConfigKeys.BaseUrl.key)
-        } else {
-            Log_OC.d(tag, "BaseUrl configuration cannot be found, default url applied")
-            null
-        }
-    }
-}

+ 7 - 0
app/src/main/res/values/setup.xml

@@ -36,6 +36,13 @@
     <string name="proxy_host"></string>
     <integer name="proxy_port">-1</integer>
 
+    <bool name="disable_intro">false</bool>
+    <bool name="disable_multiaccount">false</bool>
+    <bool name="disable_more_external_site">false</bool>
+    <bool name="disable_sharing">false</bool>
+    <bool name="disable_clipboard">false</bool>
+    <bool name="disable_log">false</bool>
+
     <!-- Flags to enable/disable some features -->
     <string name="send_files_to_other_apps">on</string>
     <bool name="share_via_link_feature">true</bool>

+ 7 - 1
app/src/main/res/values/strings.xml

@@ -26,6 +26,12 @@
     <string name="oc_file_list_adapter_offline_operation_description_text">Pending Operation</string>
     <string name="ecosystem_apps_display_assistant">Assistant</string>
     <string name="unexpected_error_occurred">Unexpected error occurred</string>
+    <string name="app_config_disable_multiaccount_title">Disable Multi Account</string>
+    <string name="app_config_disable_sharing_title">Disable Sharing</string>
+    <string name="app_config_disable_clipboard_title">Disable Clipboard</string>
+    <string name="app_config_disable_more_external_site_title">Disable External Sites</string>
+    <string name="app_config_disable_intro_title">Disable Intro</string>
+    <string name="app_config_disable_log_title">Disable Log</string>
     <string name="app_config_base_url_title">Base URL</string>
     <string name="app_config_proxy_host_title">Proxy Hostname</string>
     <string name="app_config_proxy_port_title">Proxy Port</string>
@@ -808,7 +814,7 @@
     <string name="userinfo_no_info_text">Add name, picture and contact details on your profile page.</string>
     <string name="drawer_header_background">Background image of drawer header</string>
     <string name="account_icon">Account icon</string>
-
+    <string name="file_detail_sharing_fragment_no_contact_app_message">No app available to select contacts</string>
     <string name="end_to_end_encryption_folder_not_empty">This folder is not empty.</string>
     <string name="end_to_end_encryption_wrong_password">Error while decrypting. Wrong password?</string>
     <string name="end_to_end_encryption_decrypting">Decrypting…</string>

+ 36 - 0
app/src/main/res/xml/app_config.xml

@@ -25,4 +25,40 @@
         android:restrictionType="string"
         android:title="@string/app_config_base_url_title" />
 
+    <restriction
+        android:key="disable_multiaccount"
+        android:defaultValue="false"
+        android:restrictionType="bool"
+        android:title="@string/app_config_disable_multiaccount_title" />
+
+    <restriction
+        android:key="disable_sharing"
+        android:defaultValue="false"
+        android:restrictionType="bool"
+        android:title="@string/app_config_disable_sharing_title" />
+
+    <restriction
+        android:key="disable_clipboard"
+        android:defaultValue="false"
+        android:restrictionType="bool"
+        android:title="@string/app_config_disable_clipboard_title" />
+
+    <restriction
+        android:key="disable_more_external_site"
+        android:defaultValue="false"
+        android:restrictionType="bool"
+        android:title="@string/app_config_disable_more_external_site_title" />
+
+    <restriction
+        android:key="disable_intro"
+        android:defaultValue="false"
+        android:restrictionType="bool"
+        android:title="@string/app_config_disable_intro_title" />
+
+    <restriction
+        android:key="disable_log"
+        android:defaultValue="true"
+        android:restrictionType="bool"
+        android:title="@string/app_config_disable_log_title" />
+
 </restrictions>