From d631131f4d68c61ad028fb3471e65e60f9524abc Mon Sep 17 00:00:00 2001 From: alperozturk Date: Wed, 20 Nov 2024 16:42:55 +0100 Subject: [PATCH] add enforce mdm Signed-off-by: alperozturk --- .../java/com/nextcloud/utils/mdm/MDMConfig.kt | 3 ++ .../com/nmc/android/ui/LauncherActivity.kt | 8 ++- .../authentication/AuthenticatorActivity.java | 16 ++++-- .../android/ui/ListPreferenceDialog.kt | 46 ++++++++++++++++ .../android/ui/activity/SettingsActivity.java | 52 +++++++++++++------ .../android/utils/appConfig/AppConfigKeys.kt | 3 +- app/src/main/res/values/setup.xml | 1 + app/src/main/res/values/strings.xml | 1 + app/src/main/res/xml/app_config.xml | 6 +++ app/src/main/res/xml/preferences.xml | 2 +- 10 files changed, 116 insertions(+), 22 deletions(-) create mode 100644 app/src/main/java/com/owncloud/android/ui/ListPreferenceDialog.kt diff --git a/app/src/main/java/com/nextcloud/utils/mdm/MDMConfig.kt b/app/src/main/java/com/nextcloud/utils/mdm/MDMConfig.kt index 126dcf3404..3670e84484 100644 --- a/app/src/main/java/com/nextcloud/utils/mdm/MDMConfig.kt +++ b/app/src/main/java/com/nextcloud/utils/mdm/MDMConfig.kt @@ -119,6 +119,9 @@ object MDMConfig { fun getPort(context: Context): Int = context.getRestriction(AppConfigKeys.ProxyPort, context.resources.getInteger(R.integer.proxy_port)) + fun enforceProtection(context: Context): Boolean = + context.getRestriction(AppConfigKeys.EnforceProtection, context.resources.getBoolean(R.bool.enforce_protection)) + @Suppress("UNCHECKED_CAST") private fun Context.getRestriction(appConfigKey: AppConfigKeys, defaultValue: T): T { val restrictionsManager = getSystemService(Context.RESTRICTIONS_SERVICE) as? RestrictionsManager diff --git a/app/src/main/java/com/nmc/android/ui/LauncherActivity.kt b/app/src/main/java/com/nmc/android/ui/LauncherActivity.kt index b3858c03d1..b39b3f8122 100644 --- a/app/src/main/java/com/nmc/android/ui/LauncherActivity.kt +++ b/app/src/main/java/com/nmc/android/ui/LauncherActivity.kt @@ -17,11 +17,13 @@ import android.view.View import androidx.annotation.VisibleForTesting import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import com.nextcloud.client.preferences.AppPreferences +import com.nextcloud.utils.mdm.MDMConfig import com.owncloud.android.R import com.owncloud.android.authentication.AuthenticatorActivity import com.owncloud.android.databinding.ActivitySplashBinding import com.owncloud.android.ui.activity.BaseActivity import com.owncloud.android.ui.activity.FileDisplayActivity +import com.owncloud.android.ui.activity.SettingsActivity import javax.inject.Inject class LauncherActivity : BaseActivity() { @@ -65,7 +67,11 @@ class LauncherActivity : BaseActivity() { private fun scheduleSplashScreen() { Handler(Looper.getMainLooper()).postDelayed({ if (user.isPresent) { - startActivity(Intent(this, FileDisplayActivity::class.java)) + if (MDMConfig.enforceProtection(this) && appPreferences.lockPreference == SettingsActivity.LOCK_NONE) { + startActivity(Intent(this, SettingsActivity::class.java)) + } else { + startActivity(Intent(this, FileDisplayActivity::class.java)) + } } else { startActivity(Intent(this, AuthenticatorActivity::class.java)) } diff --git a/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java b/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java index 10f63668bc..7f12948467 100644 --- a/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java +++ b/app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java @@ -105,6 +105,7 @@ import com.owncloud.android.services.OperationsService; import com.owncloud.android.services.OperationsService.OperationsServiceBinder; import com.owncloud.android.ui.NextcloudWebViewClient; import com.owncloud.android.ui.activity.FileDisplayActivity; +import com.owncloud.android.ui.activity.SettingsActivity; import com.owncloud.android.ui.dialog.IndeterminateProgressDialog; import com.owncloud.android.ui.dialog.SslUntrustedCertDialog; import com.owncloud.android.ui.dialog.SslUntrustedCertDialog.OnSslUntrustedCertListener; @@ -123,6 +124,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -1361,11 +1363,17 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity private void endSuccess() { if (!onlyAdd) { - Intent i = new Intent(this, FileDisplayActivity.class); - i.setAction(FileDisplayActivity.RESTART); - i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(i); + if (MDMConfig.INSTANCE.enforceProtection(this) && Objects.equals(preferences.getLockPreference(), SettingsActivity.LOCK_NONE)) { + Intent i = new Intent(this, SettingsActivity.class); + startActivity(i); + } else { + Intent i = new Intent(this, FileDisplayActivity.class); + i.setAction(FileDisplayActivity.RESTART); + i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(i); + } } + finish(); } diff --git a/app/src/main/java/com/owncloud/android/ui/ListPreferenceDialog.kt b/app/src/main/java/com/owncloud/android/ui/ListPreferenceDialog.kt new file mode 100644 index 0000000000..57c67d56ea --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/ListPreferenceDialog.kt @@ -0,0 +1,46 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2024 Alper Ozturk + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.ui + +import android.app.AlertDialog +import android.app.Dialog +import android.content.Context +import android.preference.ListPreference +import android.util.AttributeSet +import com.nextcloud.utils.extensions.setVisibleIf + +@Suppress("DEPRECATION") +class ListPreferenceDialog(context: Context?, attrs: AttributeSet?) : ListPreference(context, attrs) { + + fun showDialog() { + if (!isDialogCreated()) { + onClick() + } + } + + fun dismissible(value: Boolean) { + if (isDialogCreated()) { + dialog.setCancelable(value) + dialog.setCanceledOnTouchOutside(value) + } + } + + fun enableCancelButton(value: Boolean) { + if (isDialogCreated()) { + (dialog as? AlertDialog)?.let { + val cancelButton = it.getButton(Dialog.BUTTON_NEGATIVE) + cancelButton?.setVisibleIf(value) + cancelButton?.isEnabled = value + } + } + } + + private fun isDialogCreated(): Boolean { + return dialog != null + } +} diff --git a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java index 77d2675752..91b7081773 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/SettingsActivity.java @@ -61,6 +61,7 @@ import com.owncloud.android.lib.common.ExternalLink; import com.owncloud.android.lib.common.ExternalLinkType; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.providers.DocumentsStorageProvider; +import com.owncloud.android.ui.ListPreferenceDialog; import com.owncloud.android.ui.ThemeableSwitchPreference; import com.owncloud.android.ui.asynctasks.LoadingVersionNumberTask; import com.owncloud.android.ui.dialog.setupEncryption.SetupEncryptionDialogFragment; @@ -75,6 +76,7 @@ import com.owncloud.android.utils.theme.ViewThemeUtils; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import javax.inject.Inject; @@ -122,7 +124,7 @@ public class SettingsActivity extends PreferenceActivity private Uri serverBaseUri; - private ListPreference lock; + private ListPreferenceDialog lock; private ThemeableSwitchPreference showHiddenFiles; private ThemeableSwitchPreference showEcosystemApps; private AppCompatDelegate delegate; @@ -139,7 +141,6 @@ public class SettingsActivity extends PreferenceActivity @Inject ViewThemeUtils viewThemeUtils; @Inject ConnectivityService connectivityService; - @SuppressWarnings("deprecation") @Override public void onCreate(Bundle savedInstanceState) { @@ -185,6 +186,15 @@ public class SettingsActivity extends PreferenceActivity // workaround for mismatched color when app dark mode and system dark mode don't agree setListBackground(); + showPasscodeDialogIfEnforceAppProtection(); + } + + private void showPasscodeDialogIfEnforceAppProtection() { + if (MDMConfig.INSTANCE.enforceProtection(this) && Objects.equals(preferences.getLockPreference(), SettingsActivity.LOCK_NONE) && lock != null) { + lock.showDialog(); + lock.dismissible(false); + lock.enableCancelButton(false); + } } private void setupDevCategory(PreferenceScreen preferenceScreen) { @@ -678,26 +688,35 @@ public class SettingsActivity extends PreferenceActivity private void setupLockPreference(PreferenceCategory preferenceCategoryDetails, boolean passCodeEnabled, boolean deviceCredentialsEnabled) { - lock = (ListPreference) findPreference(PREFERENCE_LOCK); + boolean enforceProtection = MDMConfig.INSTANCE.enforceProtection(this); + lock = (ListPreferenceDialog) findPreference(PREFERENCE_LOCK); + int optionSize = 3; + if (enforceProtection) { + optionSize = 2; + } + if (lock != null && (passCodeEnabled || deviceCredentialsEnabled)) { - ArrayList lockEntries = new ArrayList<>(3); - lockEntries.add(getString(R.string.prefs_lock_none)); + ArrayList lockEntries = new ArrayList<>(optionSize); lockEntries.add(getString(R.string.prefs_lock_using_passcode)); lockEntries.add(getString(R.string.prefs_lock_using_device_credentials)); - ArrayList lockValues = new ArrayList<>(3); - lockValues.add(LOCK_NONE); + ArrayList lockValues = new ArrayList<>(optionSize); lockValues.add(LOCK_PASSCODE); lockValues.add(LOCK_DEVICE_CREDENTIALS); - if (!passCodeEnabled) { - lockEntries.remove(1); - lockValues.remove(1); - } else if (!deviceCredentialsEnabled || - !DeviceCredentialUtils.areCredentialsAvailable(getApplicationContext())) { - lockEntries.remove(2); - lockValues.remove(2); + if (!enforceProtection) { + lockEntries.add(getString(R.string.prefs_lock_none)); + lockValues.add(LOCK_NONE); } + + if (!passCodeEnabled) { + lockEntries.remove(getString(R.string.prefs_lock_using_passcode)); + lockValues.remove(LOCK_PASSCODE); + } else if (!deviceCredentialsEnabled || !DeviceCredentialUtils.areCredentialsAvailable(getApplicationContext())) { + lockEntries.remove(getString(R.string.prefs_lock_using_device_credentials)); + lockValues.remove(LOCK_DEVICE_CREDENTIALS); + } + String[] lockEntriesArr = new String[lockEntries.size()]; lockEntriesArr = lockEntries.toArray(lockEntriesArr); String[] lockValuesArr = new String[lockValues.size()]; @@ -706,6 +725,7 @@ public class SettingsActivity extends PreferenceActivity lock.setEntries(lockEntriesArr); lock.setEntryValues(lockValuesArr); lock.setSummary(lock.getEntry()); + lock.setOnPreferenceChangeListener((preference, o) -> { pendingLock = LOCK_NONE; String oldValue = ((ListPreference) preference).getValue(); @@ -935,7 +955,9 @@ public class SettingsActivity extends PreferenceActivity protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); - if (requestCode == ACTION_REQUEST_PASSCODE && resultCode == RESULT_OK) { + if (requestCode == ACTION_REQUEST_PASSCODE && resultCode == RESULT_CANCELED) { + showPasscodeDialogIfEnforceAppProtection(); + } else if (requestCode == ACTION_REQUEST_PASSCODE && resultCode == RESULT_OK) { String passcode = data.getStringExtra(PassCodeActivity.KEY_PASSCODE); if (passcode != null && passcode.length() == 4) { SharedPreferences.Editor appPrefs = PreferenceManager diff --git a/app/src/main/java/com/owncloud/android/utils/appConfig/AppConfigKeys.kt b/app/src/main/java/com/owncloud/android/utils/appConfig/AppConfigKeys.kt index 30a86e413a..dd7e7c465e 100644 --- a/app/src/main/java/com/owncloud/android/utils/appConfig/AppConfigKeys.kt +++ b/app/src/main/java/com/owncloud/android/utils/appConfig/AppConfigKeys.kt @@ -19,5 +19,6 @@ enum class AppConfigKeys(val key: String) { DisableClipboard("disable_clipboard"), DisableMoreExternalSite("disable_more_external_site"), DisableIntro("disable_intro"), - DisableLog("disable_log") + DisableLog("disable_log"), + EnforceProtection("enforce_protection") } diff --git a/app/src/main/res/values/setup.xml b/app/src/main/res/values/setup.xml index aa6be51253..139e8b2e8d 100644 --- a/app/src/main/res/values/setup.xml +++ b/app/src/main/res/values/setup.xml @@ -42,6 +42,7 @@ false false false + false on diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bbf49635e8..5acf54124e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -35,6 +35,7 @@ Base URL Proxy Hostname Proxy Port + Enforce Protection File does not exists, yet. Please upload the file first. Delete Offline Folder Conflicted Folder: %s diff --git a/app/src/main/res/xml/app_config.xml b/app/src/main/res/xml/app_config.xml index a8475a9d28..179efd1776 100644 --- a/app/src/main/res/xml/app_config.xml +++ b/app/src/main/res/xml/app_config.xml @@ -61,4 +61,10 @@ android:restrictionType="bool" android:title="@string/app_config_disable_log_title" /> + + \ No newline at end of file diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 90599ffb49..63a1902c52 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -35,7 +35,7 @@ -