Loading app/build.gradle +1 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ android { defaultConfig { applicationId "at.bitfire.davdroid" versionCode 400000000 versionCode 400000001 buildConfigField "long", "buildTime", System.currentTimeMillis() + "L" minSdkVersion 21 // Android 5 Loading app/src/main/java/at/bitfire/davdroid/ui/webdav/WebdavMountsActivity.kt +2 −2 Original line number Diff line number Diff line Loading @@ -106,10 +106,10 @@ class WebdavMountsActivity: AppCompatActivity() { if (info.rootDocument?.quotaUsed != null || info.rootDocument?.quotaAvailable != null) { binding.quota.visibility = View.VISIBLE binding.quota.text = context.getString(R.string.webdav_mounts_quota_used_available, info.rootDocument.quotaAvailable?.let { info.rootDocument.quotaUsed?.let { FileUtils.byteCountToDisplaySize(it) } ?: "?", info.rootDocument.quotaUsed?.let { info.rootDocument.quotaAvailable?.let { FileUtils.byteCountToDisplaySize(it) } ?: "?" ) Loading app/src/main/java/at/bitfire/davdroid/webdav/DavDocumentsProvider.kt +35 −33 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ import android.webkit.MimeTypeMap import androidx.annotation.WorkerThread import androidx.core.content.ContextCompat import androidx.lifecycle.Observer import at.bitfire.cert4android.CertUtils import at.bitfire.dav4jvm.DavCollection import at.bitfire.dav4jvm.DavResource import at.bitfire.dav4jvm.Response Loading @@ -41,8 +40,6 @@ import okhttp3.logging.HttpLoggingInterceptor import java.io.ByteArrayOutputStream import java.io.FileNotFoundException import java.net.HttpURLConnection import java.security.MessageDigest import java.security.spec.MGF1ParameterSpec.SHA1 import java.util.* import java.util.concurrent.* import java.util.logging.Level Loading Loading @@ -312,31 +309,32 @@ class DavDocumentsProvider: DocumentsProvider() { override fun copyDocument(sourceDocumentId: String, targetParentDocumentId: String): String { Logger.log.fine("WebDAV copyDocument $sourceDocumentId $targetParentDocumentId") val srcDoc = documentDao.get(sourceDocumentId.toLong()) ?: throw FileNotFoundException() val dstDoc = documentDao.get(targetParentDocumentId.toLong()) ?: throw FileNotFoundException() val dstFolder = documentDao.get(targetParentDocumentId.toLong()) ?: throw FileNotFoundException() val name = srcDoc.name if (srcDoc.mountId != dstDoc.mountId) if (srcDoc.mountId != dstFolder.mountId) throw UnsupportedOperationException("Can't COPY between WebDAV servers") var dstDocId = sourceDocumentId val dstDocId: String httpClient(srcDoc.mountId).use { client -> val dav = DavResource(client.okHttpClient, srcDoc.toHttpUrl(db)) try { val dstUrl = dstDoc.toHttpUrl(db).newBuilder() val dstUrl = dstFolder.toHttpUrl(db).newBuilder() .addPathSegment(name) .build() dav.copy(dstUrl, false) { // successfully copied } dstDocId = documentDao.insertOrReplace(WebDavDocument( mountId = dstDoc.mountId, parentId = dstDoc.id, mountId = dstFolder.mountId, parentId = dstFolder.id, name = name, isDirectory = srcDoc.isDirectory, displayName = srcDoc.displayName, mimeType = srcDoc.mimeType, size = srcDoc.size )).toString() } notifyFolderChanged(targetParentDocumentId) } catch (e: HttpException) { Loading Loading @@ -428,9 +426,10 @@ class DavDocumentsProvider: DocumentsProvider() { try { dav.move(newLocation, false) { // successfully moved } doc.parentId = dstParent.id documentDao.update(doc) } notifyFolderChanged(sourceParentDocumentId) notifyFolderChanged(targetParentDocumentId) Loading Loading @@ -521,7 +520,11 @@ class DavDocumentsProvider: DocumentsProvider() { val accessor = RandomAccessCallback(context!!, client, url, doc.mimeType, fileInfo, signal) storageManager.openProxyFileDescriptor(modeFlags, accessor, accessor.workerHandler) } else { val fd = StreamingFileDescriptor(context!!, client, url, doc.mimeType, signal) val fd = StreamingFileDescriptor(context!!, client, url, doc.mimeType, signal) { // called when transfer is finished notifyFolderChanged(doc.parentId) } if (readOnly) fd.download() else Loading Loading @@ -555,7 +558,7 @@ class DavDocumentsProvider: DocumentsProvider() { BitmapFactory.decodeStream(data)?.let { bitmap -> val thumb = ThumbnailUtils.extractThumbnail(bitmap, sizeHint.x, sizeHint.y) val baos = ByteArrayOutputStream() thumb.compress(Bitmap.CompressFormat.JPEG, 92, baos) thumb.compress(Bitmap.CompressFormat.JPEG, 95, baos) result = baos.toByteArray() } } Loading Loading @@ -616,26 +619,25 @@ class DavDocumentsProvider: DocumentsProvider() { context!!.contentResolver.notifyChange(buildChildDocumentsUri(authority, parentDocumentId), null) } private fun sha1(s: String): String { val md = MessageDigest.getInstance(SHA1.digestAlgorithm) return CertUtils.hexString(md.digest(s.toByteArray())) } private fun HttpException.throwForDocumentProvider(ignorePreconditionFailed: Boolean = false) { when (code) { HttpURLConnection.HTTP_UNAUTHORIZED -> { if (Build.VERSION.SDK_INT >= 26) { // TODO edit mount val intent = Intent(context!!, WebdavMountsActivity::class.java) throw AuthenticationRequiredException(this, PendingIntent.getActivity(context!!, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)) } HttpURLConnection.HTTP_NOT_FOUND -> throw FileNotFoundException() } HttpURLConnection.HTTP_NOT_FOUND -> throw FileNotFoundException() HttpURLConnection.HTTP_PRECON_FAILED -> if (!ignorePreconditionFailed) throw this else -> throw this if (ignorePreconditionFailed) return } // re-throw throw this } } No newline at end of file app/src/main/java/at/bitfire/davdroid/webdav/PageCache.kt +9 −2 Original line number Diff line number Diff line package at.bitfire.davdroid.webdav import android.content.Context import android.os.Build import android.os.storage.StorageManager import androidx.annotation.WorkerThread import androidx.core.content.ContextCompat import at.bitfire.davdroid.AndroidSingleton import at.bitfire.davdroid.log.Logger import okhttp3.HttpUrl import org.apache.commons.io.FileUtils import java.io.File @WorkerThread class PageCache( context: Context ) { Loading @@ -30,8 +34,11 @@ class PageCache( init { val storageManager = ContextCompat.getSystemService(context, StorageManager::class.java)!! val cacheDir = File(context.cacheDir, "webdav/page") val maxBytes = storageManager.getCacheQuotaBytes(storageManager.getUuidForPath(cacheDir)) / 2 Logger.log.info("Initializing WebDAV page cache in $cacheDir") val maxBytes = if (Build.VERSION.SDK_INT >= 26) storageManager.getCacheQuotaBytes(storageManager.getUuidForPath(cacheDir)) / 2 else 50*FileUtils.ONE_MB Logger.log.info("Initializing WebDAV page cache in $cacheDir with ${FileUtils.byteCountToDisplaySize(maxBytes)}") cache = DiskCache(cacheDir, maxBytes) } Loading app/src/main/java/at/bitfire/davdroid/webdav/RandomAccessCallback.kt +3 −0 Original line number Diff line number Diff line package at.bitfire.davdroid.webdav import android.annotation.TargetApi import android.content.Context import android.os.CancellationSignal import android.os.Handler Loading @@ -7,6 +8,7 @@ import android.os.HandlerThread import android.os.ProxyFileDescriptorCallback import android.system.ErrnoException import android.system.OsConstants import androidx.annotation.RequiresApi import at.bitfire.dav4jvm.DavResource import at.bitfire.dav4jvm.HttpUtils import at.bitfire.dav4jvm.exception.HttpException Loading @@ -20,6 +22,7 @@ import java.io.InterruptedIOException import java.net.HttpURLConnection import java.util.logging.Level @TargetApi(26) class RandomAccessCallback( val context: Context, val httpClient: HttpClient, Loading Loading
app/build.gradle +1 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,7 @@ android { defaultConfig { applicationId "at.bitfire.davdroid" versionCode 400000000 versionCode 400000001 buildConfigField "long", "buildTime", System.currentTimeMillis() + "L" minSdkVersion 21 // Android 5 Loading
app/src/main/java/at/bitfire/davdroid/ui/webdav/WebdavMountsActivity.kt +2 −2 Original line number Diff line number Diff line Loading @@ -106,10 +106,10 @@ class WebdavMountsActivity: AppCompatActivity() { if (info.rootDocument?.quotaUsed != null || info.rootDocument?.quotaAvailable != null) { binding.quota.visibility = View.VISIBLE binding.quota.text = context.getString(R.string.webdav_mounts_quota_used_available, info.rootDocument.quotaAvailable?.let { info.rootDocument.quotaUsed?.let { FileUtils.byteCountToDisplaySize(it) } ?: "?", info.rootDocument.quotaUsed?.let { info.rootDocument.quotaAvailable?.let { FileUtils.byteCountToDisplaySize(it) } ?: "?" ) Loading
app/src/main/java/at/bitfire/davdroid/webdav/DavDocumentsProvider.kt +35 −33 Original line number Diff line number Diff line Loading @@ -22,7 +22,6 @@ import android.webkit.MimeTypeMap import androidx.annotation.WorkerThread import androidx.core.content.ContextCompat import androidx.lifecycle.Observer import at.bitfire.cert4android.CertUtils import at.bitfire.dav4jvm.DavCollection import at.bitfire.dav4jvm.DavResource import at.bitfire.dav4jvm.Response Loading @@ -41,8 +40,6 @@ import okhttp3.logging.HttpLoggingInterceptor import java.io.ByteArrayOutputStream import java.io.FileNotFoundException import java.net.HttpURLConnection import java.security.MessageDigest import java.security.spec.MGF1ParameterSpec.SHA1 import java.util.* import java.util.concurrent.* import java.util.logging.Level Loading Loading @@ -312,31 +309,32 @@ class DavDocumentsProvider: DocumentsProvider() { override fun copyDocument(sourceDocumentId: String, targetParentDocumentId: String): String { Logger.log.fine("WebDAV copyDocument $sourceDocumentId $targetParentDocumentId") val srcDoc = documentDao.get(sourceDocumentId.toLong()) ?: throw FileNotFoundException() val dstDoc = documentDao.get(targetParentDocumentId.toLong()) ?: throw FileNotFoundException() val dstFolder = documentDao.get(targetParentDocumentId.toLong()) ?: throw FileNotFoundException() val name = srcDoc.name if (srcDoc.mountId != dstDoc.mountId) if (srcDoc.mountId != dstFolder.mountId) throw UnsupportedOperationException("Can't COPY between WebDAV servers") var dstDocId = sourceDocumentId val dstDocId: String httpClient(srcDoc.mountId).use { client -> val dav = DavResource(client.okHttpClient, srcDoc.toHttpUrl(db)) try { val dstUrl = dstDoc.toHttpUrl(db).newBuilder() val dstUrl = dstFolder.toHttpUrl(db).newBuilder() .addPathSegment(name) .build() dav.copy(dstUrl, false) { // successfully copied } dstDocId = documentDao.insertOrReplace(WebDavDocument( mountId = dstDoc.mountId, parentId = dstDoc.id, mountId = dstFolder.mountId, parentId = dstFolder.id, name = name, isDirectory = srcDoc.isDirectory, displayName = srcDoc.displayName, mimeType = srcDoc.mimeType, size = srcDoc.size )).toString() } notifyFolderChanged(targetParentDocumentId) } catch (e: HttpException) { Loading Loading @@ -428,9 +426,10 @@ class DavDocumentsProvider: DocumentsProvider() { try { dav.move(newLocation, false) { // successfully moved } doc.parentId = dstParent.id documentDao.update(doc) } notifyFolderChanged(sourceParentDocumentId) notifyFolderChanged(targetParentDocumentId) Loading Loading @@ -521,7 +520,11 @@ class DavDocumentsProvider: DocumentsProvider() { val accessor = RandomAccessCallback(context!!, client, url, doc.mimeType, fileInfo, signal) storageManager.openProxyFileDescriptor(modeFlags, accessor, accessor.workerHandler) } else { val fd = StreamingFileDescriptor(context!!, client, url, doc.mimeType, signal) val fd = StreamingFileDescriptor(context!!, client, url, doc.mimeType, signal) { // called when transfer is finished notifyFolderChanged(doc.parentId) } if (readOnly) fd.download() else Loading Loading @@ -555,7 +558,7 @@ class DavDocumentsProvider: DocumentsProvider() { BitmapFactory.decodeStream(data)?.let { bitmap -> val thumb = ThumbnailUtils.extractThumbnail(bitmap, sizeHint.x, sizeHint.y) val baos = ByteArrayOutputStream() thumb.compress(Bitmap.CompressFormat.JPEG, 92, baos) thumb.compress(Bitmap.CompressFormat.JPEG, 95, baos) result = baos.toByteArray() } } Loading Loading @@ -616,26 +619,25 @@ class DavDocumentsProvider: DocumentsProvider() { context!!.contentResolver.notifyChange(buildChildDocumentsUri(authority, parentDocumentId), null) } private fun sha1(s: String): String { val md = MessageDigest.getInstance(SHA1.digestAlgorithm) return CertUtils.hexString(md.digest(s.toByteArray())) } private fun HttpException.throwForDocumentProvider(ignorePreconditionFailed: Boolean = false) { when (code) { HttpURLConnection.HTTP_UNAUTHORIZED -> { if (Build.VERSION.SDK_INT >= 26) { // TODO edit mount val intent = Intent(context!!, WebdavMountsActivity::class.java) throw AuthenticationRequiredException(this, PendingIntent.getActivity(context!!, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)) } HttpURLConnection.HTTP_NOT_FOUND -> throw FileNotFoundException() } HttpURLConnection.HTTP_NOT_FOUND -> throw FileNotFoundException() HttpURLConnection.HTTP_PRECON_FAILED -> if (!ignorePreconditionFailed) throw this else -> throw this if (ignorePreconditionFailed) return } // re-throw throw this } } No newline at end of file
app/src/main/java/at/bitfire/davdroid/webdav/PageCache.kt +9 −2 Original line number Diff line number Diff line package at.bitfire.davdroid.webdav import android.content.Context import android.os.Build import android.os.storage.StorageManager import androidx.annotation.WorkerThread import androidx.core.content.ContextCompat import at.bitfire.davdroid.AndroidSingleton import at.bitfire.davdroid.log.Logger import okhttp3.HttpUrl import org.apache.commons.io.FileUtils import java.io.File @WorkerThread class PageCache( context: Context ) { Loading @@ -30,8 +34,11 @@ class PageCache( init { val storageManager = ContextCompat.getSystemService(context, StorageManager::class.java)!! val cacheDir = File(context.cacheDir, "webdav/page") val maxBytes = storageManager.getCacheQuotaBytes(storageManager.getUuidForPath(cacheDir)) / 2 Logger.log.info("Initializing WebDAV page cache in $cacheDir") val maxBytes = if (Build.VERSION.SDK_INT >= 26) storageManager.getCacheQuotaBytes(storageManager.getUuidForPath(cacheDir)) / 2 else 50*FileUtils.ONE_MB Logger.log.info("Initializing WebDAV page cache in $cacheDir with ${FileUtils.byteCountToDisplaySize(maxBytes)}") cache = DiskCache(cacheDir, maxBytes) } Loading
app/src/main/java/at/bitfire/davdroid/webdav/RandomAccessCallback.kt +3 −0 Original line number Diff line number Diff line package at.bitfire.davdroid.webdav import android.annotation.TargetApi import android.content.Context import android.os.CancellationSignal import android.os.Handler Loading @@ -7,6 +8,7 @@ import android.os.HandlerThread import android.os.ProxyFileDescriptorCallback import android.system.ErrnoException import android.system.OsConstants import androidx.annotation.RequiresApi import at.bitfire.dav4jvm.DavResource import at.bitfire.dav4jvm.HttpUtils import at.bitfire.dav4jvm.exception.HttpException Loading @@ -20,6 +22,7 @@ import java.io.InterruptedIOException import java.net.HttpURLConnection import java.util.logging.Level @TargetApi(26) class RandomAccessCallback( val context: Context, val httpClient: HttpClient, Loading