mirror of
https://github.com/nextcloud/android.git
synced 2024-12-18 23:11:58 +03:00
Merge pull request #14061 from nextcloud/mdm-enforce-protection
Feature - MDM Enforce App Protection
This commit is contained in:
commit
72fdb340eb
10 changed files with 116 additions and 22 deletions
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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 (!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
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue