Skip to content

Commit

Permalink
Merge pull request #12884 from nextcloud/feature/app-config
Browse files Browse the repository at this point in the history
App Config With Restriction Manager
  • Loading branch information
tobiasKaminsky authored May 10, 2024
2 parents e13d243 + 1565b32 commit 176a096
Show file tree
Hide file tree
Showing 11 changed files with 270 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Your Name <[email protected]>
* 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 changes: 4 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@
android:usesCleartextTraffic="true"
tools:ignore="UnusedAttribute"
tools:replace="android:allowBackup">

<meta-data android:name="android.content.APP_RESTRICTIONS"
android:resource="@xml/app_config" />

<activity
android:name="com.nextcloud.ui.composeActivity.ComposeActivity"
android:exported="false" />
Expand Down
49 changes: 44 additions & 5 deletions app/src/main/java/com/owncloud/android/MainApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@
import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.RestrictionsManager;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
Expand Down Expand Up @@ -55,6 +58,7 @@
import com.nextcloud.client.preferences.AppPreferences;
import com.nextcloud.client.preferences.AppPreferencesImpl;
import com.nextcloud.client.preferences.DarkMode;
import com.nextcloud.utils.extensions.ContextExtensionsKt;
import com.nmc.android.ui.LauncherActivity;
import com.owncloud.android.authentication.AuthenticatorActivity;
import com.owncloud.android.authentication.PassCodeManager;
Expand All @@ -63,6 +67,7 @@
import com.owncloud.android.datamodel.MediaFolder;
import com.owncloud.android.datamodel.MediaFolderType;
import com.owncloud.android.datamodel.MediaProvider;
import com.owncloud.android.datamodel.ReceiverFlag;
import com.owncloud.android.datamodel.SyncedFolder;
import com.owncloud.android.datamodel.SyncedFolderProvider;
import com.owncloud.android.datamodel.ThumbnailsCacheManager;
Expand All @@ -75,6 +80,7 @@
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import com.owncloud.android.ui.activity.SyncedFoldersActivity;
import com.owncloud.android.ui.notifications.NotificationUtils;
import com.owncloud.android.utils.appConfig.AppConfigManager;
import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.FilesSyncHelper;
import com.owncloud.android.utils.PermissionUtil;
Expand Down Expand Up @@ -191,6 +197,8 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
@SuppressWarnings("unused")
private boolean mBound;

private AppConfigManager appConfigManager;

private static AppComponent appComponent;

/**
Expand Down Expand Up @@ -281,6 +289,7 @@ public static AppComponent getAppComponent() {
return appComponent;
}


@SuppressFBWarnings("ST")
@Override
public void onCreate() {
Expand Down Expand Up @@ -314,11 +323,15 @@ public void onCreate() {

OwnCloudClientManagerFactory.setUserAgent(getUserAgent());

try {
OwnCloudClientManagerFactory.setProxyHost(getResources().getString(R.string.proxy_host));
OwnCloudClientManagerFactory.setProxyPort(getResources().getInteger(R.integer.proxy_port));
} catch (Resources.NotFoundException e) {
// no proxy set
if (isClientBrandedPlus()) {
RestrictionsManager restrictionsManager = (RestrictionsManager) getSystemService(Context.RESTRICTIONS_SERVICE);
appConfigManager = new AppConfigManager(this, restrictionsManager.getApplicationRestrictions());
appConfigManager.setProxyConfig(isClientBrandedPlus());

// Listen app config changes
ContextExtensionsKt.registerBroadcastReceiver(this, restrictionsReceiver, restrictionsFilter, ReceiverFlag.NotExported);
} else {
setProxyForNonBrandedPlusClients();
}

// initialise thumbnails cache on background thread
Expand Down Expand Up @@ -364,9 +377,35 @@ public void onCreate() {
} else if (event == Lifecycle.Event.ON_STOP) {
passCodeManager.setCanAskPin(true);
Log_OC.d(TAG, "APP IN BACKGROUND");
} else if (event == Lifecycle.Event.ON_RESUME) {
if (appConfigManager == null) return;
appConfigManager.setProxyConfig(isClientBrandedPlus());
Log_OC.d(TAG, "APP ON RESUME");
}
});

private void setProxyForNonBrandedPlusClients() {
try {
OwnCloudClientManagerFactory.setProxyHost(getResources().getString(R.string.proxy_host));
OwnCloudClientManagerFactory.setProxyPort(getResources().getInteger(R.integer.proxy_port));
} catch (Resources.NotFoundException e) {
Log_OC.d(TAG, "Error caught at setProxyForNonBrandedPlusClients: " + e);
}
}

public static boolean isClientBrandedPlus() {
return (getAppContext().getResources().getBoolean(R.bool.is_branded_plus_client));
}

private final IntentFilter restrictionsFilter = new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);

private final BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
if (appConfigManager == null) return;
appConfigManager.setProxyConfig(isClientBrandedPlus());
}
};

private void registerGlobalPassCodeProtection() {
registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
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;
Expand Down Expand Up @@ -83,6 +84,7 @@
import com.owncloud.android.lib.common.OwnCloudCredentials;
import com.owncloud.android.lib.common.OwnCloudCredentialsFactory;
import com.owncloud.android.lib.common.UserInfo;
import com.owncloud.android.lib.common.accounts.AccountUtils;
import com.owncloud.android.lib.common.accounts.AccountUtils.AccountNotFoundException;
import com.owncloud.android.lib.common.accounts.AccountUtils.Constants;
import com.owncloud.android.lib.common.network.CertificateCombinedException;
Expand Down Expand Up @@ -111,6 +113,7 @@
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;

Expand Down Expand Up @@ -318,9 +321,18 @@ protected void onCreate(Bundle savedInstanceState) {
mIsFirstAuthAttempt = savedInstanceState.getBoolean(KEY_AUTH_IS_FIRST_ATTEMPT_TAG);
}

String webloginUrl = null;
boolean webViewLoginMethod;
if (getIntent().getBooleanExtra(EXTRA_USE_PROVIDER_AS_WEBLOGIN, false)) {
String webloginUrl = null;

if (MainApp.isClientBrandedPlus()) {
RestrictionsManager restrictionsManager = (RestrictionsManager) getSystemService(Context.RESTRICTIONS_SERVICE);
AppConfigManager appConfigManager = new AppConfigManager(this, restrictionsManager.getApplicationRestrictions());
webloginUrl = appConfigManager.getBaseUrl(MainApp.isClientBrandedPlus());
}

if (webloginUrl != null) {
webViewLoginMethod = true;
} else if (getIntent().getBooleanExtra(EXTRA_USE_PROVIDER_AS_WEBLOGIN, false)) {
webViewLoginMethod = true;
webloginUrl = getString(R.string.provider_registration_server);
} else {
Expand Down Expand Up @@ -1375,7 +1387,7 @@ protected boolean createAccount(RemoteOperationResult<UserInfo> authResult) {
// can be anything: email, name, name with whitespaces
String loginName = webViewUser;

String accountName = com.owncloud.android.lib.common.accounts.AccountUtils.buildAccountName(uri, loginName);
String accountName = AccountUtils.buildAccountName(uri, loginName);
Account newAccount = new Account(accountName, accountType);
if (accountManager.exists(newAccount)) {
// fail - not a new account, but an existing one; disallow
Expand Down Expand Up @@ -1480,7 +1492,7 @@ private void startQRScanner() {
public void onRequestPermissionsResult(int requestCode,
@NonNull String[] permissions,
@NonNull int[] grantResults) {
if (requestCode == PermissionUtil.PERMISSIONS_CAMERA) {// If request is cancelled, result arrays are empty.
if (requestCode == PERMISSIONS_CAMERA) {// If request is cancelled, result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted
startQRScanner();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import com.nextcloud.common.NextcloudClient;
import com.nextcloud.ui.fileactions.FileActionsBottomSheet;
import com.nextcloud.utils.extensions.BundleExtensionsKt;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.databinding.FragmentPreviewMediaBinding;
import com.owncloud.android.datamodel.OCFile;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import android.view.Menu;

import com.nextcloud.client.account.User;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.lib.resources.status.OCCapability;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Your Name <[email protected]>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

package com.owncloud.android.utils.appConfig

/**
* These keys are connected to app_config.xml
*/
enum class AppConfigKeys(val key: String) {
BaseUrl("base_url"),
ProxyHost("proxy_host"),
ProxyPort("proxy_port")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2024 Your Name <[email protected]>
* 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
}
}
}
1 change: 1 addition & 0 deletions app/src/main/res/values/setup.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
<bool name="show_external_links">true</bool>
<bool name="show_outdated_server_warning">true</bool>
<bool name="is_branded_client">false</bool>
<bool name="is_branded_plus_client">false</bool>

<!-- Calendar & Contacts backup -->
<string name="contacts_backup_folder">/.Contacts-Backup</string>
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@

<string name="ecosystem_apps_display_assistant">Assistant</string>

<string name="app_config_base_url_title">Base Url</string>
<string name="app_config_proxy_host_title">Proxy Host Name</string>
<string name="app_config_proxy_port_title">Proxy Port</string>

<string name="assistant_screen_task_types_error_state_message">Unable to fetch task types, please check your internet connection.</string>
<string name="assistant_screen_task_list_error_state_message">Unable to fetch task list, please check your internet connection.</string>

Expand Down
Loading

0 comments on commit 176a096

Please sign in to comment.