Эх сурвалжийг харах

Merge pull request #14061 from nextcloud/mdm-enforce-protection

 Feature - MDM Enforce App Protection
Tobias Kaminsky 6 сар өмнө
parent
commit
72fdb340eb

+ 3 - 0
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 <T : Any> Context.getRestriction(appConfigKey: AppConfigKeys, defaultValue: T): T {
         val restrictionsManager = getSystemService(Context.RESTRICTIONS_SERVICE) as? RestrictionsManager

+ 7 - 1
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))
             }

+ 12 - 4
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();
     }
 

+ 46 - 0
app/src/main/java/com/owncloud/android/ui/ListPreferenceDialog.kt

@@ -0,0 +1,46 @@
+/*
+ * Nextcloud - Android Client
+ *
+ * SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>
+ * 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
+    }
+}

+ 36 - 14
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<String> lockEntries = new ArrayList<>(3);
-            lockEntries.add(getString(R.string.prefs_lock_none));
+            ArrayList<String> lockEntries = new ArrayList<>(optionSize);
             lockEntries.add(getString(R.string.prefs_lock_using_passcode));
             lockEntries.add(getString(R.string.prefs_lock_using_device_credentials));
 
-            ArrayList<String> lockValues = new ArrayList<>(3);
-            lockValues.add(LOCK_NONE);
+            ArrayList<String> lockValues = new ArrayList<>(optionSize);
             lockValues.add(LOCK_PASSCODE);
             lockValues.add(LOCK_DEVICE_CREDENTIALS);
 
+            if (!enforceProtection) {
+                lockEntries.add(getString(R.string.prefs_lock_none));
+                lockValues.add(LOCK_NONE);
+            }
+
             if (!passCodeEnabled) {
-                lockEntries.remove(1);
-                lockValues.remove(1);
-            } else if (!deviceCredentialsEnabled ||
-                !DeviceCredentialUtils.areCredentialsAvailable(getApplicationContext())) {
-                lockEntries.remove(2);
-                lockValues.remove(2);
+                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

+ 2 - 1
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")
 }

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

@@ -42,6 +42,7 @@
     <bool name="disable_sharing">false</bool>
     <bool name="disable_clipboard">false</bool>
     <bool name="disable_log">false</bool>
+    <bool name="enforce_protection">false</bool>
 
     <!-- Flags to enable/disable some features -->
     <string name="send_files_to_other_apps">on</string>

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

@@ -35,6 +35,7 @@
     <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>
+    <string name="app_config_enforce_protection_title">Enforce Protection</string>
     <string name="offline_operations_file_does_not_exists_yet">File does not exists, yet. Please upload the file first.</string>
     <string name="offline_operations_worker_notification_delete_offline_folder">Delete Offline Folder</string>
     <string name="offline_operations_worker_notification_conflict_text">Conflicted Folder: %s</string>

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

@@ -61,4 +61,10 @@
         android:restrictionType="bool"
         android:title="@string/app_config_disable_log_title" />
 
+    <restriction
+        android:key="enforce_protection"
+        android:defaultValue="false"
+        android:restrictionType="bool"
+        android:title="@string/app_config_enforce_protection_title" />
+
 </restrictions>

+ 1 - 1
app/src/main/res/xml/preferences.xml

@@ -35,7 +35,7 @@
 	</PreferenceCategory>
 
 	<PreferenceCategory android:title="@string/prefs_category_details" android:key="details">
-		<ListPreference
+		<com.owncloud.android.ui.ListPreferenceDialog
 			android:title="@string/prefs_lock"
 			android:key="lock"
 			android:dialogTitle="@string/prefs_lock_title"