diff --git a/opencloudApp/src/main/AndroidManifest.xml b/opencloudApp/src/main/AndroidManifest.xml
index 0d6ba96aa..ca76bb9ca 100644
--- a/opencloudApp/src/main/AndroidManifest.xml
+++ b/opencloudApp/src/main/AndroidManifest.xml
@@ -23,6 +23,7 @@
API >= 23; the app needs to handle this
-->
+
+ Download all files
+ Download all files from your cloud for offline access (requires significant storage)
+ Download Everything
+ This will download ALL files from your cloud. This may use significant storage space and bandwidth. Continue?
+
+
+ Auto-sync local changes
+ Automatically upload changes to locally modified files
+ Auto-Sync
+ Local file changes will be automatically synced to the cloud. This requires a stable network connection. Continue?
+
+
+ Prefer local version on conflict
+ When a file is modified both locally and on server, upload local version instead of creating a conflicted copy
+
diff --git a/opencloudApp/src/main/res/xml/settings_security.xml b/opencloudApp/src/main/res/xml/settings_security.xml
index 91c72bb0d..3e2888145 100644
--- a/opencloudApp/src/main/res/xml/settings_security.xml
+++ b/opencloudApp/src/main/res/xml/settings_security.xml
@@ -49,4 +49,25 @@
app:summary="@string/prefs_touches_with_other_visible_windows_summary"
app:title="@string/prefs_touches_with_other_visible_windows" />
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/opencloudComLibrary/src/main/java/eu/opencloud/android/lib/resources/users/GetRemoteUserAvatarOperation.kt b/opencloudComLibrary/src/main/java/eu/opencloud/android/lib/resources/users/GetRemoteUserAvatarOperation.kt
index 9e355c03c..6f0bfd4b1 100644
--- a/opencloudComLibrary/src/main/java/eu/opencloud/android/lib/resources/users/GetRemoteUserAvatarOperation.kt
+++ b/opencloudComLibrary/src/main/java/eu/opencloud/android/lib/resources/users/GetRemoteUserAvatarOperation.kt
@@ -31,7 +31,6 @@ import eu.opencloud.android.lib.common.network.WebdavUtils
import eu.opencloud.android.lib.common.operations.RemoteOperation
import eu.opencloud.android.lib.common.operations.RemoteOperationResult
import timber.log.Timber
-import java.io.File
import java.io.IOException
import java.io.InputStream
import java.net.URL
@@ -42,14 +41,14 @@ import java.net.URL
* @author David A. Velasco
* @author David González Verdugo
*/
+@Suppress("UnusedPrivateProperty")
class GetRemoteUserAvatarOperation(private val avatarDimension: Int) : RemoteOperation() {
override fun run(client: OpenCloudClient): RemoteOperationResult {
var inputStream: InputStream? = null
var result: RemoteOperationResult
try {
- val endPoint =
- client.baseUri.toString() + NON_OFFICIAL_AVATAR_PATH + client.credentials.username + File.separator + avatarDimension
+ val endPoint = client.baseUri.toString() + GRAPH_AVATAR_PATH
Timber.d("avatar URI: %s", endPoint)
val getMethod = GetMethod(URL(endPoint))
@@ -109,6 +108,6 @@ class GetRemoteUserAvatarOperation(private val avatarDimension: Int) : RemoteOpe
private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK
companion object {
- private const val NON_OFFICIAL_AVATAR_PATH = "/index.php/avatar/"
+ private const val GRAPH_AVATAR_PATH = "/graph/v1.0/me/photo/\$value"
}
}
diff --git a/opencloudData/src/main/java/eu/opencloud/android/data/providers/LocalStorageProvider.kt b/opencloudData/src/main/java/eu/opencloud/android/data/providers/LocalStorageProvider.kt
index c41846fa6..fde8bdcfb 100644
--- a/opencloudData/src/main/java/eu/opencloud/android/data/providers/LocalStorageProvider.kt
+++ b/opencloudData/src/main/java/eu/opencloud/android/data/providers/LocalStorageProvider.kt
@@ -49,7 +49,10 @@ sealed class LocalStorageProvider(private val rootFolderName: String) {
/**
* Get local storage path for accountName.
*/
- private fun getAccountDirectoryPath(
+ /**
+ * Get local storage path for accountName.
+ */
+ protected open fun getAccountDirectoryPath(
accountName: String
): String = getRootFolderPath() + File.separator + getEncodedAccountName(accountName)
@@ -62,9 +65,15 @@ sealed class LocalStorageProvider(private val rootFolderName: String) {
accountName: String,
remotePath: String,
spaceId: String?,
+ spaceName: String? = null,
): String =
if (spaceId != null) {
- getAccountDirectoryPath(accountName) + File.separator + spaceId + File.separator + remotePath
+ val spaceFolder = if (!spaceName.isNullOrBlank()) {
+ spaceName.replace("/", "_").replace("\\", "_").replace(":", "_")
+ } else {
+ spaceId
+ }
+ getAccountDirectoryPath(accountName) + File.separator + spaceFolder + File.separator + remotePath
} else {
getAccountDirectoryPath(accountName) + remotePath
}
diff --git a/opencloudData/src/main/java/eu/opencloud/android/data/providers/ScopedStorageProvider.kt b/opencloudData/src/main/java/eu/opencloud/android/data/providers/ScopedStorageProvider.kt
index a9a4c996c..fce95812c 100644
--- a/opencloudData/src/main/java/eu/opencloud/android/data/providers/ScopedStorageProvider.kt
+++ b/opencloudData/src/main/java/eu/opencloud/android/data/providers/ScopedStorageProvider.kt
@@ -20,12 +20,19 @@
package eu.opencloud.android.data.providers
import android.content.Context
+import android.os.Environment
import java.io.File
+@Suppress("UnusedPrivateProperty")
class ScopedStorageProvider(
rootFolderName: String,
private val context: Context
) : LocalStorageProvider(rootFolderName) {
- override fun getPrimaryStorageDirectory(): File = context.filesDir
+ override fun getPrimaryStorageDirectory(): File = Environment.getExternalStorageDirectory()
+
+ override fun getAccountDirectoryPath(accountName: String): String {
+ val sanitizedName = accountName.replace("/", "_").replace("\\", "_").replace(":", "_")
+ return getRootFolderPath() + File.separator + sanitizedName
+ }
}
diff --git a/opencloudData/src/test/java/eu/opencloud/android/data/providers/ScopedStorageProviderTest.kt b/opencloudData/src/test/java/eu/opencloud/android/data/providers/ScopedStorageProviderTest.kt
index d01ab0ae0..fbc213f42 100644
--- a/opencloudData/src/test/java/eu/opencloud/android/data/providers/ScopedStorageProviderTest.kt
+++ b/opencloudData/src/test/java/eu/opencloud/android/data/providers/ScopedStorageProviderTest.kt
@@ -2,13 +2,17 @@ package eu.opencloud.android.data.providers
import android.content.Context
import android.net.Uri
+import android.os.Environment
import eu.opencloud.android.domain.transfers.model.OCTransfer
import eu.opencloud.android.testutil.OC_FILE
import eu.opencloud.android.testutil.OC_SPACE_PROJECT_WITH_IMAGE
import io.mockk.every
import io.mockk.mockk
import io.mockk.mockkStatic
+import io.mockk.unmockkAll
+import io.mockk.spyk
import io.mockk.verify
+import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Before
@@ -43,17 +47,25 @@ class ScopedStorageProviderTest {
File(this, "child.bin").writeBytes(ByteArray(expectedSizeOfDirectoryValue.toInt()))
}
- scopedStorageProvider = ScopedStorageProvider(rootFolderName, context)
+ mockkStatic(Environment::class)
+ every { Environment.getExternalStorageDirectory() } returns filesDir
+
+ scopedStorageProvider = spyk(ScopedStorageProvider(rootFolderName, context))
every { context.filesDir } returns filesDir
}
+ @After
+ fun tearDown() {
+ unmockkAll()
+ }
+
@Test
fun `getPrimaryStorageDirectory returns filesDir`() {
val result = scopedStorageProvider.getPrimaryStorageDirectory()
assertEquals(filesDir, result)
verify(exactly = 1) {
- context.filesDir
+ Environment.getExternalStorageDirectory()
}
}
@@ -71,10 +83,8 @@ class ScopedStorageProviderTest {
@Test
fun `getDefaultSavePathFor returns the path with spaces when there is a space`() {
- mockkStatic(Uri::class)
- every { Uri.encode(accountName, "@") } returns uriEncoded
-
- val accountDirectoryPath = filesDir.absolutePath + File.separator + rootFolderName + File.separator + uriEncoded
+ // ScopedStorageProvider overrides getAccountDirectoryPath and does NOT use Uri.encode
+ val accountDirectoryPath = filesDir.absolutePath + File.separator + rootFolderName + File.separator + accountName
val expectedPath = accountDirectoryPath + File.separator + spaceId + File.separator + remotePath
val actualPath = scopedStorageProvider.getDefaultSavePathFor(accountName, remotePath, spaceId)
@@ -89,10 +99,8 @@ class ScopedStorageProviderTest {
fun `getDefaultSavePathFor returns the path without spaces when there is not space`() {
val spaceId = null
- mockkStatic(Uri::class)
- every { Uri.encode(accountName, "@") } returns uriEncoded
-
- val accountDirectoryPath = filesDir.absolutePath + File.separator + rootFolderName + File.separator + uriEncoded
+ // ScopedStorageProvider overrides getAccountDirectoryPath and does NOT use Uri.encode
+ val accountDirectoryPath = filesDir.absolutePath + File.separator + rootFolderName + File.separator + accountName
val expectedPath = accountDirectoryPath + remotePath
val actualPath = scopedStorageProvider.getDefaultSavePathFor(accountName, remotePath, spaceId)