From 2187d81d39ccc955f95b04f98e652e2c62adf90e Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sun, 7 Jul 2019 13:41:31 -0400 Subject: [PATCH 01/39] updated travis --- .travis.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 85f231a3..839be961 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,9 +11,11 @@ android: - platform-tools - tools # The BuildTools version used by your project + - build-tools-28.0.3 - build-tools-27.0.3 - build-tools-26.0.2 # The SDK version used to compile your project + - android-28 - android-27 - android-26 - android-21 @@ -32,15 +34,15 @@ android: before_install: # Install SDK license so Android Gradle plugin can install deps. + - yes | sdkmanager "platforms;android-28" - yes | sdkmanager "platforms;android-27" - mkdir "$ANDROID_HOME/licenses" || true - echo "8933bad161af4178b1185d1a37fbf41ea5269c55" > "$ANDROID_HOME/licenses/android-sdk-license" script: - - ./gradlew clean assemble - - ./gradlew test - - ./gradlew fetch2:connectedAndroidTest -PdisablePreDex - - ./gradlew assembleAndroidTest + - ./gradlew clean assemble + - ./gradlew test + - ./gradlew assembleAndroidTest # Emulator Management: Create, Start and Wait From 746f88638bb929bde246195c20bc001409ddc80c Mon Sep 17 00:00:00 2001 From: Carson Holzheimer Date: Tue, 27 Aug 2019 12:51:06 +1000 Subject: [PATCH 02/39] Compare to observer instance, not list, to find observer to remove --- .../main/java/com/tonyodev/fetch2/fetch/ListenerCoordinator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/fetch/ListenerCoordinator.kt b/fetch2/src/main/java/com/tonyodev/fetch2/fetch/ListenerCoordinator.kt index c20e4662..d47e7dee 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/fetch/ListenerCoordinator.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/fetch/ListenerCoordinator.kt @@ -757,7 +757,7 @@ class ListenerCoordinator(val namespace: String, if (iterator != null) { while (iterator.hasNext()) { val reference = iterator.next() - if (reference.get() == fetchObservers) { + if (reference.get() == fetchObserver) { iterator.remove() break } From 3173c93946934bc42c9d72d1912a32cce40a8982 Mon Sep 17 00:00:00 2001 From: Nitish Gadangi Date: Sun, 6 Oct 2019 23:16:36 +0530 Subject: [PATCH 03/39] Updated Prerequisites updated the instructions to add Internet Permission --- README.md | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 18708f02..ac996438 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Features * Concurrent downloading support. * Ability to pause and resume downloads. * Set the priority of a download. -* Network specific downloading support. +* Network-specific downloading support. * Ability to retry failed downloads. * Ability to group downloads. * Easy progress and status tracking. @@ -43,6 +43,12 @@ add the following storage permissions to your application's manifest. For Androi ``` +Also, as you are going to use Internet to download files. We need to add the Internet access permissions +in the Manifest. + +```xml + +``` How to use Fetch ---------------- @@ -177,27 +183,27 @@ You can query Fetch for download information in several ways. ```java //Query all downloads fetch.getDownloads(new Func>() { - @Override + @Override public void call(List downloads) { - //Access all downloads here + //Access all downloads here } }); //Get all downloads with a status fetch.getDownloadsWithStatus(Status.DOWNLOADING, new Func>() { - @Override + @Override public void call(List downloads) { - //Access downloads that are downloading + //Access downloads that are downloading } }); // You can also access grouped downloads int groupId = 52687447745; fetch.getDownloadsInGroup(groupId, new Func>() { - @Override - public void call(List downloads) { - //Access grouped downloads - } + @Override + public void call(List downloads) { + //Access grouped downloads + } }); ``` @@ -216,7 +222,7 @@ Downloaders By default Fetch uses the HttpUrlConnection client via the HttpUrlConnectionDownloader to download requests. Add the following Gradle dependency to your application's build.gradle -to use the OkHttp Downloader instead. You can create your own custom downloaders +to use the OkHttp Downloader instead. You can create your custom downloaders if necessary. See the Java docs for details. ```java @@ -232,9 +238,9 @@ Set the OkHttp Downloader for Fetch to use. OkHttpClient okHttpClient = new OkHttpClient.Builder().build(); FetchConfiguration fetchConfiguration = new FetchConfiguration.Builder(this) - .setDownloadConcurrentLimit(10) - .setHttpDownloader(new OkHttpDownloader(okHttpClient)) - .build(); + .setDownloadConcurrentLimit(10) + .setHttpDownloader(new OkHttpDownloader(okHttpClient)) + .build(); Fetch fetch = Fetch.Impl.getInstance(fetchConfiguration); ``` @@ -280,8 +286,8 @@ FetchFileServer Introducing the FetchFileServer. The FetchFileServer is a lightweight TCP File Server that acts like an HTTP file server designed specifically to share files between Android devices. You can host file resources -with the FetchFileServer on one device and have Fetch download Files from the server -on another device. See sample app for more information. Wiki on FetchFileServer will be +with the FetchFileServer on one device and have to Fetch download Files from the server +on another device. See the sample app for more information. Wiki on FetchFileServer will be added in the coming days. Start using FetchFileServer by adding the gradle dependency to your application's build.gradle file. @@ -293,7 +299,7 @@ Androidx use: implementation "androidx.tonyodev.fetch2fileserver:xfetch2fileserver:3.1.4" ``` -Start a FetchFileServer instance and add resource files that it can server to connected clients. +Start a FetchFileServer instance and add resource files that it can serve to connected clients. ```java public class TestActivity extends AppCompatActivity { @@ -450,7 +456,7 @@ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, From 4c4e388be6b55c8769e4a5445e0502dafa704198 Mon Sep 17 00:00:00 2001 From: Mike Dawson Date: Sat, 7 Dec 2019 15:49:20 +0400 Subject: [PATCH 04/39] Fix unnecessary delay to starting a sequential download. When the downloader is sequential, there is no need to make a request to the server to check if the server supports parallel downloads. This results in an unnecessary delay to starting the request. This modification adds only 6 lines. The getRequestSupportedFileDownloaderTypes on HttpUrlConnectionDownloader and OkHttpDownloader simply checks if the downloader is sequential. If it is, then the sequential downloader type is returned immediately without querying the server for the request. --- .../java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt | 4 ++++ .../main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt b/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt index cc9e23fc..1f83f893 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt @@ -193,6 +193,10 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor( } override fun getRequestSupportedFileDownloaderTypes(request: Downloader.ServerRequest): Set { + if(fileDownloaderType == Downloader.FileDownloaderType.SEQUENTIAL) { + return mutableSetOf(fileDownloaderType) + } + return try { getRequestSupportedFileDownloaderTypes(request, this) } catch (e: Exception) { diff --git a/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt b/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt index 564d73bf..fdcd3659 100644 --- a/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt +++ b/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt @@ -209,6 +209,10 @@ open class OkHttpDownloader @JvmOverloads constructor( } override fun getRequestSupportedFileDownloaderTypes(request: Downloader.ServerRequest): Set { + if(fileDownloaderType == Downloader.FileDownloaderType.SEQUENTIAL) { + return mutableSetOf(fileDownloaderType) + } + return try { getRequestSupportedFileDownloaderTypes(request, this) } catch (e: Exception) { From 0f40e90e002af30379681e8a581765f571b30f21 Mon Sep 17 00:00:00 2001 From: Mike Dawson Date: Thu, 9 Apr 2020 11:04:30 +0400 Subject: [PATCH 05/39] Update fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt Co-Authored-By: Alex Starchenko --- .../com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt b/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt index 1f83f893..fd0f0dad 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt @@ -193,7 +193,13 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor( } override fun getRequestSupportedFileDownloaderTypes(request: Downloader.ServerRequest): Set { - if(fileDownloaderType == Downloader.FileDownloaderType.SEQUENTIAL) { + return when (fileDownloaderType) { + Downloader.FileDownloaderType.SEQUENTIAL -> mutableSetOf(fileDownloaderType) + else -> try { + getRequestSupportedFileDownloaderTypes(request, this) + } catch (e: Exception) { + mutableSetOf(fileDownloaderType) + } return mutableSetOf(fileDownloaderType) } @@ -216,4 +222,4 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor( var followsRedirect = true } -} \ No newline at end of file +} From 2658afc576a7d33272846c4f335e79b82fef4d1a Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 2 May 2020 09:03:20 -0400 Subject: [PATCH 06/39] Fixes to content length --- .../com/tonyodev/fetch2core/FetchCoreUtils.kt | 22 +++---------------- .../tonyodev/fetch2okhttp/OkHttpDownloader.kt | 8 +++---- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/fetch2core/src/main/java/com/tonyodev/fetch2core/FetchCoreUtils.kt b/fetch2core/src/main/java/com/tonyodev/fetch2core/FetchCoreUtils.kt index 92913404..352e92fe 100644 --- a/fetch2core/src/main/java/com/tonyodev/fetch2core/FetchCoreUtils.kt +++ b/fetch2core/src/main/java/com/tonyodev/fetch2core/FetchCoreUtils.kt @@ -355,27 +355,11 @@ fun getSimpleInterruptMonitor() = object : InterruptMonitor { } fun getContentLengthFromHeader(responseHeaders: Map>, defaultValue: Long): Long { - // responseHeaders declared with Not-Null keys and Not-Null values - // remove unnecessary conversions here - when { + val contentLength = when { responseHeaders.containsKey(HEADER_CONTENT_LENGTH) -> responseHeaders[HEADER_CONTENT_LENGTH] - // HTTP/1.1 compat responseHeaders.containsKey(HEADER_CONTENT_LENGTH_LEGACY) -> responseHeaders[HEADER_CONTENT_LENGTH_LEGACY] + responseHeaders.containsKey(HEADER_CONTENT_LENGTH_COMPAT) -> responseHeaders[HEADER_CONTENT_LENGTH_COMPAT] else -> null - }?.firstOrNull()?.toLongOrNull()?.takeIf { it > 0 }?.also { - return it } - when { - responseHeaders.containsKey(HEADER_CONTENT_RANGE) -> responseHeaders[HEADER_CONTENT_RANGE] - // HTTP/1.1 compat - responseHeaders.containsKey(HEADER_CONTENT_RANGE_LEGACY) -> responseHeaders[HEADER_CONTENT_RANGE_LEGACY] - else -> null - }?.firstOrNull()?.also { value -> - value.lastIndexOf("/") - .takeIf { it != -1 && it < value.length.minus(1) } - ?.let { index -> value.substring(index + 1).toLongOrNull() } - ?.takeIf { size -> size > 0 } - ?.also { size -> return size } - } - return defaultValue + return contentLength?.firstOrNull()?.toLongOrNull() ?: defaultValue } \ No newline at end of file diff --git a/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt b/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt index fdcd3659..83b44a9f 100644 --- a/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt +++ b/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt @@ -105,8 +105,9 @@ open class OkHttpDownloader @JvmOverloads constructor( responseHeaders = getResponseHeaders(okHttpResponse.headers()) code = okHttpResponse.code() } + val success = okHttpResponse.isSuccessful - var contentLength = getContentLengthFromHeader(responseHeaders, -1) + val contentLength = getContentLengthFromHeader(responseHeaders, -1L) val byteStream: InputStream? = okHttpResponse.body()?.byteStream() val errorResponseString: String? = if (!success) { copyStreamToString(byteStream, false) @@ -114,11 +115,8 @@ open class OkHttpDownloader @JvmOverloads constructor( null } - val hash = getContentHash(responseHeaders) - if (contentLength < 1) { - contentLength = responseHeaders["content-length"]?.firstOrNull()?.toLong() ?: -1L - } + val hash = getContentHash(responseHeaders) val acceptsRanges = code == HttpURLConnection.HTTP_PARTIAL || responseHeaders["accept-ranges"]?.firstOrNull() == "bytes" From e0a4a892fdaffc8e035bb05b61529d58e6ff4a5f Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 2 May 2020 10:15:58 -0400 Subject: [PATCH 07/39] fixes header issues --- .../fetch2/HttpUrlConnectionDownloader.kt | 28 ++++----------- .../com/tonyodev/fetch2core/FetchCoreUtils.kt | 36 ++++++++++--------- .../tonyodev/fetch2okhttp/OkHttpDownloader.kt | 11 +++--- 3 files changed, 32 insertions(+), 43 deletions(-) diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt b/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt index fd0f0dad..eaf16daf 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt @@ -56,12 +56,12 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor( client.addRequestProperty("Referer", referer) } client.connect() - var responseHeaders = getResponseHeaders(client.headerFields) + var responseHeaders = client.headerFields var code = client.responseCode if ((code == HttpURLConnection.HTTP_MOVED_TEMP || code == HttpURLConnection.HTTP_MOVED_PERM - || code == HttpURLConnection.HTTP_SEE_OTHER) && responseHeaders.containsKey("location")) { - httpUrl = URL(responseHeaders["location"]?.firstOrNull() ?: "") + || code == HttpURLConnection.HTTP_SEE_OTHER) && getHeaderValue(responseHeaders, "Location") != null) { + httpUrl = URL(getHeaderValue(responseHeaders, "Location")?.firstOrNull() ?: "") client = httpUrl.openConnection() as HttpURLConnection onPreClientExecute(client, request) if (client.getRequestProperty("Referer") == null) { @@ -69,7 +69,7 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor( client.addRequestProperty("Referer", referer) } client.connect() - responseHeaders = getResponseHeaders(client.headerFields) + responseHeaders = client.headerFields code = client.responseCode } var success = false @@ -87,7 +87,7 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor( } val acceptsRanges = code == HttpURLConnection.HTTP_PARTIAL || - responseHeaders["accept-ranges"]?.firstOrNull() == "bytes" + getHeaderValue(responseHeaders, "Accept-Ranges")?.firstOrNull() == "bytes" onServerResponse(request, Downloader.Response( code = code, @@ -96,7 +96,7 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor( byteStream = null, request = request, hash = hash, - responseHeaders = responseHeaders, + responseHeaders = client.headerFields, acceptsRanges = acceptsRanges, errorResponse = errorResponseString)) @@ -128,7 +128,7 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor( } override fun getContentHash(responseHeaders: MutableMap>): String { - return responseHeaders["content-md5"]?.firstOrNull() ?: "" + return getHeaderValue(responseHeaders, "Content-MD5")?.firstOrNull() ?: "" } override fun close() { @@ -146,20 +146,6 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor( } } - private fun getResponseHeaders(responseHeaders: MutableMap>): MutableMap> { - val headers = mutableMapOf>() - val iterator = responseHeaders.iterator() - var entry: Map.Entry> - while (iterator.hasNext()) { - entry = iterator.next() - @Suppress("SENSELESS_COMPARISON") - if (entry.key != null) { - headers[entry.key.toLowerCase()] = entry.value - } - } - return headers - } - override fun getFileSlicingCount(request: Downloader.ServerRequest, contentLength: Long): Int? { return null } diff --git a/fetch2core/src/main/java/com/tonyodev/fetch2core/FetchCoreUtils.kt b/fetch2core/src/main/java/com/tonyodev/fetch2core/FetchCoreUtils.kt index 352e92fe..aa70eab3 100644 --- a/fetch2core/src/main/java/com/tonyodev/fetch2core/FetchCoreUtils.kt +++ b/fetch2core/src/main/java/com/tonyodev/fetch2core/FetchCoreUtils.kt @@ -2,6 +2,7 @@ package com.tonyodev.fetch2core +import android.annotation.SuppressLint import android.content.Context import android.net.Uri import java.io.* @@ -24,10 +25,6 @@ internal const val HEADER_CONTENT_LENGTH_LEGACY = "Content-Length" internal const val HEADER_CONTENT_LENGTH_COMPAT = "ContentLength" -internal const val HEADER_CONTENT_RANGE = "content-range" - -internal const val HEADER_CONTENT_RANGE_LEGACY = "Content-Range" - internal const val HEADER_TRANSFER_ENCODING = "Transfer-Encoding" internal const val HEADER_TRANSFER_ENCODING_COMPAT = "TransferEncoding" @@ -238,14 +235,7 @@ fun isParallelDownloadingSupported(responseHeaders: Map>): ?: responseHeaders[HEADER_TRANSFER_ENCODING_COMPAT]?.firstOrNull() ?: "" return transferEncoding.takeIf { it != "chunked" }?.let { - responseHeaders.let { headers -> - when { - headers.containsKey(HEADER_CONTENT_LENGTH) -> headers[HEADER_CONTENT_LENGTH] - headers.containsKey(HEADER_CONTENT_LENGTH_LEGACY) -> headers[HEADER_CONTENT_LENGTH_LEGACY] - headers.containsKey(HEADER_CONTENT_LENGTH_COMPAT) -> headers[HEADER_CONTENT_LENGTH_COMPAT] - else -> null - }?.firstOrNull()?.toLongOrNull() - }.let { value -> value != null && value > -1 } + getContentLengthFromHeader(responseHeaders, -1L) > -1L } ?: false } @@ -265,6 +255,20 @@ fun getRequestSupportedFileDownloaderTypes(request: Downloader.ServerRequest, do } } +@SuppressLint("DefaultLocale") +fun getHeaderValue(headers: MutableMap>, key: String): List? { + return getCompatHeaders(headers)[key.toLowerCase()] +} + +@SuppressLint("DefaultLocale") +private fun getCompatHeaders(headers: MutableMap>): MutableMap> { + val compatHeaders = mutableMapOf>() + for (header in headers) { + compatHeaders[header.key.toLowerCase()] = header.value + } + return compatHeaders +} + fun getRequestContentLength(request: Downloader.ServerRequest, downloader: Downloader<*, *>): Long { return try { val response = downloader.execute(request, getSimpleInterruptMonitor()) @@ -354,11 +358,11 @@ fun getSimpleInterruptMonitor() = object : InterruptMonitor { get() = false } -fun getContentLengthFromHeader(responseHeaders: Map>, defaultValue: Long): Long { +fun getContentLengthFromHeader(headers: Map>, defaultValue: Long): Long { val contentLength = when { - responseHeaders.containsKey(HEADER_CONTENT_LENGTH) -> responseHeaders[HEADER_CONTENT_LENGTH] - responseHeaders.containsKey(HEADER_CONTENT_LENGTH_LEGACY) -> responseHeaders[HEADER_CONTENT_LENGTH_LEGACY] - responseHeaders.containsKey(HEADER_CONTENT_LENGTH_COMPAT) -> responseHeaders[HEADER_CONTENT_LENGTH_COMPAT] + headers.containsKey(HEADER_CONTENT_LENGTH) -> headers[HEADER_CONTENT_LENGTH] + headers.containsKey(HEADER_CONTENT_LENGTH_LEGACY) -> headers[HEADER_CONTENT_LENGTH_LEGACY] + headers.containsKey(HEADER_CONTENT_LENGTH_COMPAT) -> headers[HEADER_CONTENT_LENGTH_COMPAT] else -> null } return contentLength?.firstOrNull()?.toLongOrNull() ?: defaultValue diff --git a/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt b/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt index 83b44a9f..51148509 100644 --- a/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt +++ b/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt @@ -57,7 +57,7 @@ open class OkHttpDownloader @JvmOverloads constructor( @Suppress("SENSELESS_COMPARISON") if (key != null) { val values = okResponseHeaders.values(key) - headers[key.toLowerCase()] = values + headers[key] = values } } return headers @@ -92,9 +92,9 @@ open class OkHttpDownloader @JvmOverloads constructor( var code = okHttpResponse.code() if ((code == HttpURLConnection.HTTP_MOVED_TEMP || code == HttpURLConnection.HTTP_MOVED_PERM - || code == HttpURLConnection.HTTP_SEE_OTHER) && responseHeaders.containsKey("location")) { + || code == HttpURLConnection.HTTP_SEE_OTHER) && getHeaderValue(responseHeaders, "Location") != null) { okHttpRequest = onPreClientExecute(client, getRedirectedServerRequest(request, - responseHeaders["location"]?.firstOrNull() ?: "")) + getHeaderValue(responseHeaders, "Location")?.firstOrNull() ?: "")) if (okHttpRequest.header("Referer") == null) { val referer = getRefererFromUrl(request.url) okHttpRequest = okHttpRequest.newBuilder() @@ -115,11 +115,10 @@ open class OkHttpDownloader @JvmOverloads constructor( null } - val hash = getContentHash(responseHeaders) val acceptsRanges = code == HttpURLConnection.HTTP_PARTIAL || - responseHeaders["accept-ranges"]?.firstOrNull() == "bytes" + getHeaderValue(responseHeaders, "Accept-Ranges")?.firstOrNull() == "bytes" onServerResponse(request, Downloader.Response( code = code, @@ -148,7 +147,7 @@ open class OkHttpDownloader @JvmOverloads constructor( } override fun getContentHash(responseHeaders: MutableMap>): String { - return responseHeaders["content-md5"]?.firstOrNull() ?: "" + return getHeaderValue(responseHeaders, "Content-MD5")?.firstOrNull() ?: "" } override fun disconnect(response: Downloader.Response) { From 40c834842956bcd518c6d34392d702a7334f938f Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 2 May 2020 10:19:16 -0400 Subject: [PATCH 08/39] kotlin update --- versions.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versions.gradle b/versions.gradle index 500bc48f..287b2e9e 100644 --- a/versions.gradle +++ b/versions.gradle @@ -1,5 +1,5 @@ ext { - kotlin_version = '1.3.41' + kotlin_version = '1.3.72' okhttp_version = '3.12.3' okhttp_url_version = '3.11.0' android_support_version = '28.0.0' From f0643215aa62e519b44d7895e8cc3f93d5bf4076 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 2 May 2020 10:47:03 -0400 Subject: [PATCH 09/39] okayhttp fixes and updates --- .../com/tonyodev/fetch2okhttp/OkHttpDownloader.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt b/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt index 51148509..df4f0458 100644 --- a/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt +++ b/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt @@ -52,7 +52,7 @@ open class OkHttpDownloader @JvmOverloads constructor( private fun getResponseHeaders(okResponseHeaders: Headers): MutableMap> { val headers = mutableMapOf>() - for (i in 0 until okResponseHeaders.size()) { + for (i in 0 until okResponseHeaders.size) { val key = okResponseHeaders.name(i) @Suppress("SENSELESS_COMPARISON") if (key != null) { @@ -88,8 +88,8 @@ open class OkHttpDownloader @JvmOverloads constructor( .build() } var okHttpResponse = client.newCall(okHttpRequest).execute() - var responseHeaders = getResponseHeaders(okHttpResponse.headers()) - var code = okHttpResponse.code() + var responseHeaders = getResponseHeaders(okHttpResponse.headers) + var code = okHttpResponse.code if ((code == HttpURLConnection.HTTP_MOVED_TEMP || code == HttpURLConnection.HTTP_MOVED_PERM || code == HttpURLConnection.HTTP_SEE_OTHER) && getHeaderValue(responseHeaders, "Location") != null) { @@ -102,13 +102,13 @@ open class OkHttpDownloader @JvmOverloads constructor( .build() } okHttpResponse = client.newCall(okHttpRequest).execute() - responseHeaders = getResponseHeaders(okHttpResponse.headers()) - code = okHttpResponse.code() + responseHeaders = getResponseHeaders(okHttpResponse.headers) + code = okHttpResponse.code } val success = okHttpResponse.isSuccessful val contentLength = getContentLengthFromHeader(responseHeaders, -1L) - val byteStream: InputStream? = okHttpResponse.body()?.byteStream() + val byteStream: InputStream? = okHttpResponse.body?.byteStream() val errorResponseString: String? = if (!success) { copyStreamToString(byteStream, false) } else { From 7f90330f91fb4baa294743d69a3aca82a8a0248b Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 2 May 2020 10:47:53 -0400 Subject: [PATCH 10/39] params rename --- fetch2rx/src/main/java/com/tonyodev/fetch2rx/RxFetchImpl.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fetch2rx/src/main/java/com/tonyodev/fetch2rx/RxFetchImpl.kt b/fetch2rx/src/main/java/com/tonyodev/fetch2rx/RxFetchImpl.kt index fa6d7c9b..cabed0fa 100644 --- a/fetch2rx/src/main/java/com/tonyodev/fetch2rx/RxFetchImpl.kt +++ b/fetch2rx/src/main/java/com/tonyodev/fetch2rx/RxFetchImpl.kt @@ -389,10 +389,10 @@ open class RxFetchImpl(override val namespace: String, } } - override fun removeAllInGroupWithStatus(id: Int, status: List): Convertible> { + override fun removeAllInGroupWithStatus(id: Int, statuses: List): Convertible> { return synchronized(lock) { throwExceptionIfClosed() - Flowable.just(Pair(id, status)) + Flowable.just(Pair(id, statuses)) .subscribeOn(scheduler) .flatMap { throwExceptionIfClosed() From 4a9030231aff80f6a83df78e2df7356720f0426e Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 2 May 2020 11:03:50 -0400 Subject: [PATCH 11/39] sanitize headers --- .../fetch2/HttpUrlConnectionDownloader.kt | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt b/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt index eaf16daf..7a225312 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt @@ -46,6 +46,17 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor( return null } + private fun getCleanedHeaders(responseHeaders: MutableMap?>): MutableMap> { + val headers = mutableMapOf>() + for (responseHeader in responseHeaders) { + val key = responseHeader.key + if (key != null) { + headers[key] = responseHeader.value ?: emptyList() + } + } + return headers + } + override fun execute(request: Downloader.ServerRequest, interruptMonitor: InterruptMonitor): Downloader.Response? { CookieHandler.setDefault(cookieManager) var httpUrl = URL(request.url) @@ -56,7 +67,7 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor( client.addRequestProperty("Referer", referer) } client.connect() - var responseHeaders = client.headerFields + var responseHeaders = getCleanedHeaders(client.headerFields) var code = client.responseCode if ((code == HttpURLConnection.HTTP_MOVED_TEMP || code == HttpURLConnection.HTTP_MOVED_PERM @@ -69,7 +80,7 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor( client.addRequestProperty("Referer", referer) } client.connect() - responseHeaders = client.headerFields + responseHeaders = getCleanedHeaders(client.headerFields) code = client.responseCode } var success = false From 9a60add84ac01c1f6dcb981ac3336d07ba730b0c Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 2 May 2020 11:07:29 -0400 Subject: [PATCH 12/39] link fixes --- sampleApp/src/main/java/com/tonyodev/fetchapp/Data.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sampleApp/src/main/java/com/tonyodev/fetchapp/Data.java b/sampleApp/src/main/java/com/tonyodev/fetchapp/Data.java index 479aa1d3..717f78c8 100644 --- a/sampleApp/src/main/java/com/tonyodev/fetchapp/Data.java +++ b/sampleApp/src/main/java/com/tonyodev/fetchapp/Data.java @@ -15,10 +15,10 @@ public final class Data { public static final String[] sampleUrls = new String[]{ "http://speedtest.ftp.otenet.gr/files/test100Mb.db", - "http://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_640x360.m4v", + "https://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_720p_stereo.ogg", "http://media.mongodb.org/zips.json", "http://www.exampletonyotest/some/unknown/123/Errorlink.txt", - "http://storage.googleapis.com/ix_choosemuse/uploads/2016/02/android-logo.png", + "https://upload.wikimedia.org/wikipedia/commons/thumb/8/82/Android_logo_2019.svg/687px-Android_logo_2019.svg.png", "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"}; private Data() { From 5512fbfdea2f3f8dbc69bffbd5d362d8b8922c31 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 2 May 2020 11:13:40 -0400 Subject: [PATCH 13/39] fix notification alert --- .../java/com/tonyodev/fetch2/DefaultFetchNotificationManager.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/DefaultFetchNotificationManager.kt b/fetch2/src/main/java/com/tonyodev/fetch2/DefaultFetchNotificationManager.kt index 469d02f2..72377859 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/DefaultFetchNotificationManager.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/DefaultFetchNotificationManager.kt @@ -90,6 +90,7 @@ abstract class DefaultFetchNotificationManager(context: Context) : FetchNotifica .setContentTitle(context.getString(R.string.fetch_notification_default_channel_name)) .setContentText("") .setStyle(style) + .setOnlyAlertOnce(true) .setGroup(groupId.toString()) .setGroupSummary(true) return false @@ -303,6 +304,7 @@ abstract class DefaultFetchNotificationManager(context: Context) : FetchNotifica .setTimeoutAfter(DEFAULT_NOTIFICATION_TIMEOUT_AFTER_RESET) .setOngoing(false) .setGroup(groupId.toString()) + .setOnlyAlertOnce(true) .setSmallIcon(android.R.drawable.stat_sys_download_done) .mActions.clear() return notificationBuilder From 7d4788df7b2e346447f455b012f4d587fc0d46b5 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 2 May 2020 11:40:14 -0400 Subject: [PATCH 14/39] fixes rx java download being null --- .../main/java/com/tonyodev/fetch2rx/RxFetchImpl.kt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/fetch2rx/src/main/java/com/tonyodev/fetch2rx/RxFetchImpl.kt b/fetch2rx/src/main/java/com/tonyodev/fetch2rx/RxFetchImpl.kt index cabed0fa..cd38c49c 100644 --- a/fetch2rx/src/main/java/com/tonyodev/fetch2rx/RxFetchImpl.kt +++ b/fetch2rx/src/main/java/com/tonyodev/fetch2rx/RxFetchImpl.kt @@ -658,7 +658,11 @@ open class RxFetchImpl(override val namespace: String, listenerCoordinator.mainListener.onQueued(download, false) } } - Flowable.just(download) + if (download != null) { + Flowable.just(download) + } else { + throw FetchException(REQUEST_DOES_NOT_EXIST) + } } .observeOn(uiScheduler) .toConvertible() @@ -824,7 +828,11 @@ open class RxFetchImpl(override val namespace: String, .flatMap { throwExceptionIfClosed() val download = fetchHandler.getDownload(id) - Flowable.just(download) + if (download != null) { + Flowable.just(download) + } else { + throw FetchException(REQUEST_DOES_NOT_EXIST) + } } .observeOn(uiScheduler) .toConvertible() From e8dd506ed866ae9843aeff7399c20e3fdaf55eb1 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 2 May 2020 14:09:33 -0400 Subject: [PATCH 15/39] Created new file resolver for fetch server --- .../com/tonyodev/fetch2core/FileResource.kt | 2 +- .../fetch2fileserver/FetchFileServer.kt | 13 +- .../fetch2fileserver/FetchFileServerImpl.kt | 7 +- .../tonyodev/fetch2fileserver/FileResolver.kt | 128 ++++++++++++++++++ .../provider/FetchFileResourceProvider.kt | 40 +----- 5 files changed, 151 insertions(+), 39 deletions(-) create mode 100644 fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FileResolver.kt diff --git a/fetch2core/src/main/java/com/tonyodev/fetch2core/FileResource.kt b/fetch2core/src/main/java/com/tonyodev/fetch2core/FileResource.kt index 7123ca23..6a497966 100644 --- a/fetch2core/src/main/java/com/tonyodev/fetch2core/FileResource.kt +++ b/fetch2core/src/main/java/com/tonyodev/fetch2core/FileResource.kt @@ -17,7 +17,7 @@ class FileResource : Parcelable, Serializable { /** Content Length */ var length: Long = 0L - /** Absolute File Path */ + /** The File Path. Can be a file or uri. */ var file: String = "" /** Unique Short name of the File Resource. diff --git a/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FetchFileServer.kt b/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FetchFileServer.kt index f737231a..133d4745 100644 --- a/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FetchFileServer.kt +++ b/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FetchFileServer.kt @@ -95,6 +95,7 @@ interface FetchFileServer { private var fileResourceDatabaseName = "LibFetchFileServerDatabaseLib.db" private var progressReportingInMillis = DEFAULT_PROGRESS_REPORTING_INTERVAL_IN_MILLISECONDS private var persistentConnectionTimeout = DEFAULT_PERSISTENT_TIME_OUT_IN_MILLISECONDS + private var fileResolver: FileResolver = object: FileResolver(context.applicationContext) {} /** Set Custom Server Socket * @param serverSocket @@ -194,6 +195,14 @@ interface FetchFileServer { return this } + /** + * Sets the file resolver that will be used to open [FileResource.file] resources. + * */ + fun setFileResolver(fileResolver: FileResolver): Builder { + this.fileResolver = fileResolver + return this + } + /** Build the FetchFileServer Instance. * @return new Fetch File Server instance. * */ @@ -207,7 +216,9 @@ interface FetchFileServer { fetchFileServerDelegate = fileServerDelegate, fetchTransferListener = transferListener, progressReportingInMillis = progressReportingInMillis, - persistentTimeoutInMillis = persistentConnectionTimeout) + persistentTimeoutInMillis = persistentConnectionTimeout, + fileResolver = fileResolver + ) } } diff --git a/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FetchFileServerImpl.kt b/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FetchFileServerImpl.kt index ce53d8f9..745b50af 100644 --- a/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FetchFileServerImpl.kt +++ b/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FetchFileServerImpl.kt @@ -30,7 +30,8 @@ class FetchFileServerImpl(context: Context, private val fetchFileServerDelegate: FetchFileServerDelegate?, private val fetchTransferListener: FetchTransferListener?, private val progressReportingInMillis: Long, - private val persistentTimeoutInMillis: Long) : FetchFileServer { + private val persistentTimeoutInMillis: Long, + private val fileResolver: FileResolver) : FetchFileServer { private val lock = Any() private val uuid = UUID.randomUUID().toString() @@ -106,7 +107,9 @@ class FetchFileServerImpl(context: Context, logger = logger, ioHandler = ioHandler, progressReportingInMillis = progressReportingInMillis, - persistentTimeoutInMillis = persistentTimeoutInMillis) + persistentTimeoutInMillis = persistentTimeoutInMillis, + fileResolver = fileResolver + ) try { fileResourceProviderMap[fileResourceProvider.id] = fileResourceProvider fileResourceProvider.execute() diff --git a/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FileResolver.kt b/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FileResolver.kt new file mode 100644 index 00000000..219ba654 --- /dev/null +++ b/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FileResolver.kt @@ -0,0 +1,128 @@ +package com.tonyodev.fetch2fileserver + +import android.content.Context +import android.net.Uri +import android.os.ParcelFileDescriptor +import com.tonyodev.fetch2core.* +import com.tonyodev.fetch2core.server.FileRequest +import java.io.* + +/** + * Used to provide [InputResourceWrapper] for [FileResource] + * */ +abstract class FileResolver(val context: Context) { + + /** + * Returns the [InputResourceWrapper] for the catalog file + * */ + open fun getCatalogInputWrapper(catalog: ByteArray, request: FileRequest, fileResource: FileResource): InputResourceWrapper { + return object : InputResourceWrapper() { + + private val inputStream = ByteArrayInputStream(catalog, request.rangeStart.toInt(), fileResource.length.toInt()) + + override fun read(byteArray: ByteArray, offSet: Int, length: Int): Int { + return inputStream.read(byteArray, offSet, length) + } + + override fun setReadOffset(offset: Long) { + inputStream.skip(offset) + } + + override fun close() { + inputStream.close() + } + } + } + + + /** + * Returns the [InputResourceWrapper] for a [FileResource]. Override this method if your [FileResource.file] + * is not a traditional File but Uri, etc. + * */ + open fun getInputWrapper(request: FileRequest, fileResource: FileResource): InputResourceWrapper { + val filePath = fileResource.file + return if (isUriPath(filePath)) { + getUriInputResourceWrapper(fileResource) + } else { + getFileInputResourceWrapper(fileResource) + } + } + + private fun getUriInputResourceWrapper(fileResource: FileResource): InputResourceWrapper { + val fileUri = Uri.parse(fileResource.file) + val contentResolver = context.contentResolver + return when (fileUri.scheme) { + "content" -> { + val parcelFileDescriptor = contentResolver.openFileDescriptor(fileUri, "w") + if (parcelFileDescriptor == null) { + throw FileNotFoundException("$fileUri $FILE_NOT_FOUND") + } else { + createUriInputResourceWrapper(FileInputStream(parcelFileDescriptor.fileDescriptor), parcelFileDescriptor) + } + } + "file" -> { + val file = File(fileUri.path) + if (file.exists() && file.canWrite()) { + createUriInputResourceWrapper(FileInputStream(file), null) + } else { + val parcelFileDescriptor = contentResolver.openFileDescriptor(fileUri, "w") + if (parcelFileDescriptor == null) { + throw FileNotFoundException("$fileUri $FILE_NOT_FOUND") + } else { + createUriInputResourceWrapper(FileInputStream(parcelFileDescriptor.fileDescriptor), parcelFileDescriptor) + } + } + } + else -> { + throw FileNotFoundException("$fileUri $FILE_NOT_FOUND") + } + } + } + + private fun createUriInputResourceWrapper( + fileInputStream: FileInputStream, + fileDescriptor: ParcelFileDescriptor? = null + ): InputResourceWrapper { + return object : InputResourceWrapper() { + + private val wrapperParcelFileDescriptor = fileDescriptor + private val wrapperFileInputStream = fileInputStream + + init { + wrapperFileInputStream.channel.position(0) + } + + override fun read(byteArray: ByteArray, offSet: Int, length: Int): Int { + return wrapperFileInputStream.read(byteArray, offSet, length) + } + + override fun setReadOffset(offset: Long) { + wrapperFileInputStream.channel.position(offset) + } + + override fun close() { + wrapperFileInputStream.close() + } + } + } + + private fun getFileInputResourceWrapper(fileResource: FileResource): InputResourceWrapper { + return object : InputResourceWrapper() { + + val randomAccessFile = RandomAccessFile(fileResource.file, "r") + + override fun read(byteArray: ByteArray, offSet: Int, length: Int): Int { + return randomAccessFile.read(byteArray, offSet, length) + } + + override fun setReadOffset(offset: Long) { + randomAccessFile.seek(offset) + } + + override fun close() { + randomAccessFile.close() + } + } + } + +} \ No newline at end of file diff --git a/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/provider/FetchFileResourceProvider.kt b/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/provider/FetchFileResourceProvider.kt index bada416d..5da50266 100644 --- a/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/provider/FetchFileResourceProvider.kt +++ b/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/provider/FetchFileResourceProvider.kt @@ -8,8 +8,7 @@ import com.tonyodev.fetch2core.server.FileResponse.CREATOR.CLOSE_CONNECTION import com.tonyodev.fetch2core.server.FileResponse.CREATOR.OPEN_CONNECTION import com.tonyodev.fetch2core.server.FileResourceTransporter import com.tonyodev.fetch2core.server.FetchFileResourceTransporter -import java.io.ByteArrayInputStream -import java.io.RandomAccessFile +import com.tonyodev.fetch2fileserver.FileResolver import java.net.HttpURLConnection import java.net.Socket import java.util.* @@ -20,7 +19,8 @@ class FetchFileResourceProvider(private val client: Socket, private val logger: FetchLogger, private val ioHandler: Handler, private val progressReportingInMillis: Long, - private val persistentTimeoutInMillis: Long) : FileResourceProvider { + private val persistentTimeoutInMillis: Long, + private val fileResolver: FileResolver) : FileResourceProvider { override val id = UUID.randomUUID().toString() private val lock = Any() @@ -81,39 +81,9 @@ class FetchFileResourceProvider(private val client: Socket, val catalog = fileResource.extras.getString("data", "{}").toByteArray(Charsets.UTF_8) fileResource.length = if (request.rangeEnd == -1L) catalog.size.toLong() else request.rangeEnd fileResource.md5 = getMd5String(catalog) - inputResourceWrapper = object : InputResourceWrapper() { - - private val inputStream = ByteArrayInputStream(catalog, request.rangeStart.toInt(), fileResource.length.toInt()) - - override fun read(byteArray: ByteArray, offSet: Int, length: Int): Int { - return inputStream.read(byteArray, offSet, length) - } - - override fun setReadOffset(offset: Long) { - inputStream.skip(offset) - } - - override fun close() { - inputStream.close() - } - } + inputResourceWrapper = fileResolver.getCatalogInputWrapper(catalog, request, fileResource) } else { - inputResourceWrapper = object : InputResourceWrapper() { - - val randomAccessFile = RandomAccessFile(fileResource.file, "r") - - override fun read(byteArray: ByteArray, offSet: Int, length: Int): Int { - return randomAccessFile.read(byteArray, offSet, length) - } - - override fun setReadOffset(offset: Long) { - randomAccessFile.seek(offset) - } - - override fun close() { - randomAccessFile.close() - } - } + inputResourceWrapper = fileResolver.getInputWrapper(request, fileResource) inputResourceWrapper?.setReadOffset(request.rangeStart) } } From 130484954ae95a24c985c1f8271b76c68c70b52d Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 2 May 2020 17:47:20 -0400 Subject: [PATCH 16/39] fixed after merge --- .../com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt | 9 +-------- .../java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt | 1 - 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt b/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt index 7a225312..52bad384 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt @@ -190,16 +190,9 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor( } override fun getRequestSupportedFileDownloaderTypes(request: Downloader.ServerRequest): Set { - return when (fileDownloaderType) { - Downloader.FileDownloaderType.SEQUENTIAL -> mutableSetOf(fileDownloaderType) - else -> try { - getRequestSupportedFileDownloaderTypes(request, this) - } catch (e: Exception) { - mutableSetOf(fileDownloaderType) - } + if(fileDownloaderType == Downloader.FileDownloaderType.SEQUENTIAL) { return mutableSetOf(fileDownloaderType) } - return try { getRequestSupportedFileDownloaderTypes(request, this) } catch (e: Exception) { diff --git a/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt b/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt index df4f0458..f9ec2319 100644 --- a/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt +++ b/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt @@ -209,7 +209,6 @@ open class OkHttpDownloader @JvmOverloads constructor( if(fileDownloaderType == Downloader.FileDownloaderType.SEQUENTIAL) { return mutableSetOf(fileDownloaderType) } - return try { getRequestSupportedFileDownloaderTypes(request, this) } catch (e: Exception) { From 7a2865e3172f5c90384f365dd296fa52c231523c Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 2 May 2020 17:52:15 -0400 Subject: [PATCH 17/39] Added clear type error. provided by danysz --- fetch2/src/main/java/com/tonyodev/fetch2/Error.kt | 10 ++++++++-- .../main/java/com/tonyodev/fetch2/FetchErrorUtils.kt | 2 ++ .../main/java/com/tonyodev/fetch2core/ErrorStrings.kt | 3 ++- sampleApp/src/main/res/xml/network_security_config.xml | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/Error.kt b/fetch2/src/main/java/com/tonyodev/fetch2/Error.kt index fb31dd61..8561ae7d 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/Error.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/Error.kt @@ -128,9 +128,14 @@ enum class Error constructor( FAILED_TO_RENAME_FILE(29), /** - * Indicates that an error occured when pre allocating the needed space on the storage system for the download. + * Indicates that an error occurred when pre allocating the needed space on the storage system for the download. * */ - FILE_ALLOCATION_FAILED(30); + FILE_ALLOCATION_FAILED(30), + + /** + * Indicates that connection to "http" is not allowed by the OS and "https" is required. + * */ + HTTP_CONNECTION_NOT_ALLOWED(31); companion object { @@ -166,6 +171,7 @@ enum class Error constructor( 28 -> FAILED_TO_RENAME_INCOMPLETE_DOWNLOAD_FILE 29 -> FAILED_TO_RENAME_FILE 30 -> FILE_ALLOCATION_FAILED + 31 -> HTTP_CONNECTION_NOT_ALLOWED else -> UNKNOWN } } diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/FetchErrorUtils.kt b/fetch2/src/main/java/com/tonyodev/fetch2/FetchErrorUtils.kt index e170f73c..380d5173 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/FetchErrorUtils.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/FetchErrorUtils.kt @@ -83,6 +83,8 @@ fun getErrorFromMessage(message: String?): Error { Error.FAILED_TO_RENAME_FILE } else if(message.contains(FILE_ALLOCATION_ERROR, true)) { Error.FILE_ALLOCATION_FAILED + } else if(message.contains(CLEAR_TEXT_NETWORK_VIOLATION, true)) { + Error.HTTP_CONNECTION_NOT_ALLOWED } else { Error.UNKNOWN } diff --git a/fetch2core/src/main/java/com/tonyodev/fetch2core/ErrorStrings.kt b/fetch2core/src/main/java/com/tonyodev/fetch2core/ErrorStrings.kt index d496f989..81e7af44 100644 --- a/fetch2core/src/main/java/com/tonyodev/fetch2core/ErrorStrings.kt +++ b/fetch2core/src/main/java/com/tonyodev/fetch2core/ErrorStrings.kt @@ -40,4 +40,5 @@ const val AWAIT_CALL_ON_UI_THREAD = "await_call_on_ui_thread" const val BLOCKING_CALL_ON_UI_THREAD = "blocking_call_on_ui_thread" const val FILE_CANNOT_BE_RENAMED = "file_cannot_be_renamed" const val FAILED_RENAME_FILE_ASSOCIATED_WITH_INCOMPLETE_DOWNLOAD = "cannot rename file associated with incomplete download" -const val FILE_ALLOCATION_ERROR = "file_allocation_error" \ No newline at end of file +const val FILE_ALLOCATION_ERROR = "file_allocation_error" +const val CLEAR_TEXT_NETWORK_VIOLATION = "Cleartext HTTP traffic to" \ No newline at end of file diff --git a/sampleApp/src/main/res/xml/network_security_config.xml b/sampleApp/src/main/res/xml/network_security_config.xml index 176d19a4..dfda68a6 100644 --- a/sampleApp/src/main/res/xml/network_security_config.xml +++ b/sampleApp/src/main/res/xml/network_security_config.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file From 9187ea6d1aee33a68bef4a3a22a4787299ed03a4 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 2 May 2020 18:08:16 -0400 Subject: [PATCH 18/39] fix context issue --- .../main/java/com/tonyodev/fetch2fileserver/FileResolver.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FileResolver.kt b/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FileResolver.kt index 219ba654..0432d177 100644 --- a/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FileResolver.kt +++ b/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FileResolver.kt @@ -10,7 +10,9 @@ import java.io.* /** * Used to provide [InputResourceWrapper] for [FileResource] * */ -abstract class FileResolver(val context: Context) { +abstract class FileResolver(context: Context) { + + private val appContext = context.applicationContext /** * Returns the [InputResourceWrapper] for the catalog file @@ -50,7 +52,7 @@ abstract class FileResolver(val context: Context) { private fun getUriInputResourceWrapper(fileResource: FileResource): InputResourceWrapper { val fileUri = Uri.parse(fileResource.file) - val contentResolver = context.contentResolver + val contentResolver = appContext.contentResolver return when (fileUri.scheme) { "content" -> { val parcelFileDescriptor = contentResolver.openFileDescriptor(fileUri, "w") From 6763748c8f96666a298853c6dd5276d36e1bfce1 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 2 May 2020 18:20:30 -0400 Subject: [PATCH 19/39] improvements to file resolver --- .../java/com/tonyodev/fetch2fileserver/FileResolver.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FileResolver.kt b/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FileResolver.kt index 0432d177..0487783e 100644 --- a/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FileResolver.kt +++ b/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FileResolver.kt @@ -1,5 +1,6 @@ package com.tonyodev.fetch2fileserver +import android.content.ContentResolver import android.content.Context import android.net.Uri import android.os.ParcelFileDescriptor @@ -12,7 +13,8 @@ import java.io.* * */ abstract class FileResolver(context: Context) { - private val appContext = context.applicationContext + protected val appContext: Context = context.applicationContext + protected val contentResolver: ContentResolver = appContext.contentResolver /** * Returns the [InputResourceWrapper] for the catalog file @@ -41,7 +43,8 @@ abstract class FileResolver(context: Context) { * Returns the [InputResourceWrapper] for a [FileResource]. Override this method if your [FileResource.file] * is not a traditional File but Uri, etc. * */ - open fun getInputWrapper(request: FileRequest, fileResource: FileResource): InputResourceWrapper { + @Throws(IOException::class) + open fun getInputWrapper(fileResource: FileResource): InputResourceWrapper { val filePath = fileResource.file return if (isUriPath(filePath)) { getUriInputResourceWrapper(fileResource) @@ -52,7 +55,6 @@ abstract class FileResolver(context: Context) { private fun getUriInputResourceWrapper(fileResource: FileResource): InputResourceWrapper { val fileUri = Uri.parse(fileResource.file) - val contentResolver = appContext.contentResolver return when (fileUri.scheme) { "content" -> { val parcelFileDescriptor = contentResolver.openFileDescriptor(fileUri, "w") From 5f2cd66cf24c8954edb74520568ebb815e464080 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 2 May 2020 18:28:46 -0400 Subject: [PATCH 20/39] remove extra param --- .../fetch2fileserver/provider/FetchFileResourceProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/provider/FetchFileResourceProvider.kt b/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/provider/FetchFileResourceProvider.kt index 5da50266..3ffb1cc0 100644 --- a/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/provider/FetchFileResourceProvider.kt +++ b/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/provider/FetchFileResourceProvider.kt @@ -83,7 +83,7 @@ class FetchFileResourceProvider(private val client: Socket, fileResource.md5 = getMd5String(catalog) inputResourceWrapper = fileResolver.getCatalogInputWrapper(catalog, request, fileResource) } else { - inputResourceWrapper = fileResolver.getInputWrapper(request, fileResource) + inputResourceWrapper = fileResolver.getInputWrapper(fileResource) inputResourceWrapper?.setReadOffset(request.rangeStart) } } From 9a6e9577012049522162eff4ccf68ca269cac971 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 2 May 2020 19:34:05 -0400 Subject: [PATCH 21/39] Fix completed status showing up twice --- .../fetch2/downloader/ParallelFileDownloaderImpl.kt | 6 ++++-- .../fetch2/downloader/SequentialFileDownloaderImpl.kt | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/downloader/ParallelFileDownloaderImpl.kt b/fetch2/src/main/java/com/tonyodev/fetch2/downloader/ParallelFileDownloaderImpl.kt index c23f1b80..afced933 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/downloader/ParallelFileDownloaderImpl.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/downloader/ParallelFileDownloaderImpl.kt @@ -196,6 +196,7 @@ class ParallelFileDownloaderImpl(private val initialDownload: Download, if (!interrupted && !terminated) { downloadInfo.etaInMilliSeconds = estimatedTimeRemainingInMilliseconds downloadInfo.downloadedBytesPerSecond = getAverageDownloadedBytesPerSecond() + val completedDownload = downloadInfo.copy() delegate?.onProgress( download = downloadInfo, etaInMilliSeconds = downloadInfo.etaInMilliSeconds, @@ -203,7 +204,7 @@ class ParallelFileDownloaderImpl(private val initialDownload: Download, downloadInfo.etaInMilliSeconds = -1 downloadInfo.downloadedBytesPerSecond = -1 delegate?.onComplete( - download = downloadInfo) + download = completedDownload) } } else { deleteAllInFolderForId(downloadInfo.id, fileTempDir) @@ -214,6 +215,7 @@ class ParallelFileDownloaderImpl(private val initialDownload: Download, if (!interrupted && !terminated) { downloadInfo.etaInMilliSeconds = estimatedTimeRemainingInMilliseconds downloadInfo.downloadedBytesPerSecond = getAverageDownloadedBytesPerSecond() + val completedDownload = downloadInfo.copy() delegate?.onProgress( download = downloadInfo, etaInMilliSeconds = downloadInfo.etaInMilliSeconds, @@ -221,7 +223,7 @@ class ParallelFileDownloaderImpl(private val initialDownload: Download, downloadInfo.etaInMilliSeconds = -1 downloadInfo.downloadedBytesPerSecond = -1 delegate?.onComplete( - download = downloadInfo) + download = completedDownload) } } } diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/downloader/SequentialFileDownloaderImpl.kt b/fetch2/src/main/java/com/tonyodev/fetch2/downloader/SequentialFileDownloaderImpl.kt index ebb4c333..e623b3cf 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/downloader/SequentialFileDownloaderImpl.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/downloader/SequentialFileDownloaderImpl.kt @@ -297,6 +297,7 @@ class SequentialFileDownloaderImpl(private val initialDownload: Download, delegate?.onDownloadBlockUpdated(downloadInfo, downloadBlock, totalDownloadBlocks) downloadInfo.etaInMilliSeconds = estimatedTimeRemainingInMilliseconds downloadInfo.downloadedBytesPerSecond = getAverageDownloadedBytesPerSecond() + val completedDownload = downloadInfo.copy() delegate?.onProgress( download = downloadInfo, etaInMilliSeconds = downloadInfo.etaInMilliSeconds, @@ -304,7 +305,7 @@ class SequentialFileDownloaderImpl(private val initialDownload: Download, downloadInfo.etaInMilliSeconds = -1 downloadInfo.downloadedBytesPerSecond = -1 delegate?.onComplete( - download = downloadInfo) + download = completedDownload) } } else { throw FetchException(INVALID_CONTENT_HASH) @@ -315,6 +316,7 @@ class SequentialFileDownloaderImpl(private val initialDownload: Download, delegate?.onDownloadBlockUpdated(downloadInfo, downloadBlock, totalDownloadBlocks) downloadInfo.etaInMilliSeconds = estimatedTimeRemainingInMilliseconds downloadInfo.downloadedBytesPerSecond = getAverageDownloadedBytesPerSecond() + val completedDownload = downloadInfo.copy() delegate?.onProgress( download = downloadInfo, etaInMilliSeconds = downloadInfo.etaInMilliSeconds, @@ -322,7 +324,7 @@ class SequentialFileDownloaderImpl(private val initialDownload: Download, downloadInfo.etaInMilliSeconds = -1 downloadInfo.downloadedBytesPerSecond = -1 delegate?.onComplete( - download = downloadInfo) + download = completedDownload) } } } From c798409b01f3c32dcd506ddb03177b719d3684ab Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 2 May 2020 19:51:05 -0400 Subject: [PATCH 22/39] fix sample app --- sampleApp/src/main/res/xml/network_security_config.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sampleApp/src/main/res/xml/network_security_config.xml b/sampleApp/src/main/res/xml/network_security_config.xml index dfda68a6..176d19a4 100644 --- a/sampleApp/src/main/res/xml/network_security_config.xml +++ b/sampleApp/src/main/res/xml/network_security_config.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file From 7d0e219c06d80db6832575c4ed958607931303eb Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 6 Jun 2020 10:41:30 -0400 Subject: [PATCH 23/39] Fixes global intent broadcast --- .../java/com/tonyodev/fetch2/downloader/DownloadManagerImpl.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/downloader/DownloadManagerImpl.kt b/fetch2/src/main/java/com/tonyodev/fetch2/downloader/DownloadManagerImpl.kt index a1ae0c29..a94be2fd 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/downloader/DownloadManagerImpl.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/downloader/DownloadManagerImpl.kt @@ -109,6 +109,7 @@ class DownloadManagerImpl(private val httpDownloader: Downloader<*, *>, } finally { removeDownloadMappings(download) val intent = Intent(ACTION_QUEUE_BACKOFF_RESET) + intent.setPackage(context.packageName) intent.putExtra(EXTRA_NAMESPACE, namespace) context.sendBroadcast(intent) } From 2e32e37997953ae5932a9f28e918da059a9fb7c7 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 6 Jun 2020 10:58:20 -0400 Subject: [PATCH 24/39] fix cast issue --- .../java/com/tonyodev/fetch2fileserver/FetchFileServerImpl.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FetchFileServerImpl.kt b/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FetchFileServerImpl.kt index 745b50af..0c324049 100644 --- a/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FetchFileServerImpl.kt +++ b/fetch2fileserver/src/main/java/com/tonyodev/fetch2fileserver/FetchFileServerImpl.kt @@ -156,7 +156,7 @@ class FetchFileServerImpl(context: Context, catalogFileResourceInfo.id = FileRequest.CATALOG_ID val catalogMap = mutableMapOf() catalogMap["data"] = catalog - catalogFileResourceInfo.extras = JSONObject(catalogMap).toString() + catalogFileResourceInfo.extras = JSONObject(catalogMap as Map<*, *>).toString() catalogFileResourceInfo.name = FileRequest.CATALOG_NAME catalogFileResourceInfo.file = FileRequest.CATALOG_FILE return catalogFileResourceInfo.toFileResource() From 58e9f7086d30669886ff5a1ba0e4f71c14d2210b Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 6 Jun 2020 11:02:30 -0400 Subject: [PATCH 25/39] link updates --- sampleApp/src/main/java/com/tonyodev/fetchapp/Data.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sampleApp/src/main/java/com/tonyodev/fetchapp/Data.java b/sampleApp/src/main/java/com/tonyodev/fetchapp/Data.java index 717f78c8..d9da4cd6 100644 --- a/sampleApp/src/main/java/com/tonyodev/fetchapp/Data.java +++ b/sampleApp/src/main/java/com/tonyodev/fetchapp/Data.java @@ -15,8 +15,7 @@ public final class Data { public static final String[] sampleUrls = new String[]{ "http://speedtest.ftp.otenet.gr/files/test100Mb.db", - "https://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_720p_stereo.ogg", - "http://media.mongodb.org/zips.json", + "https://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_720p_stereo.avi", "http://www.exampletonyotest/some/unknown/123/Errorlink.txt", "https://upload.wikimedia.org/wikipedia/commons/thumb/8/82/Android_logo_2019.svg/687px-Android_logo_2019.svg.png", "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"}; From 9cd1869956f4fd5469bf1a528e0e558166b1cf97 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 6 Jun 2020 11:10:19 -0400 Subject: [PATCH 26/39] fix links --- sampleApp/src/main/java/com/tonyodev/fetchapp/Data.java | 1 + 1 file changed, 1 insertion(+) diff --git a/sampleApp/src/main/java/com/tonyodev/fetchapp/Data.java b/sampleApp/src/main/java/com/tonyodev/fetchapp/Data.java index d9da4cd6..d87fac54 100644 --- a/sampleApp/src/main/java/com/tonyodev/fetchapp/Data.java +++ b/sampleApp/src/main/java/com/tonyodev/fetchapp/Data.java @@ -16,6 +16,7 @@ public final class Data { public static final String[] sampleUrls = new String[]{ "http://speedtest.ftp.otenet.gr/files/test100Mb.db", "https://download.blender.org/peach/bigbuckbunny_movies/big_buck_bunny_720p_stereo.avi", + "http://media.mongodb.org/zips.json", "http://www.exampletonyotest/some/unknown/123/Errorlink.txt", "https://upload.wikimedia.org/wikipedia/commons/thumb/8/82/Android_logo_2019.svg/687px-Android_logo_2019.svg.png", "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"}; From f48f469cbcafcb8ef91edba3ac585101ef551727 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sat, 6 Jun 2020 11:31:21 -0400 Subject: [PATCH 27/39] version update --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- versions.gradle | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e54d5950..3f4250ea 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Apr 22 08:01:27 EDT 2019 +#Sat Jun 06 11:30:23 EDT 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip diff --git a/versions.gradle b/versions.gradle index 287b2e9e..a0cebf73 100644 --- a/versions.gradle +++ b/versions.gradle @@ -1,19 +1,19 @@ ext { kotlin_version = '1.3.72' - okhttp_version = '3.12.3' - okhttp_url_version = '3.11.0' + okhttp_version = '4.7.2' + okhttp_url_version = '4.7.2' android_support_version = '28.0.0' constraint_layout_version = "1.1.3" room_version = '1.1.1' junit_version = '4.12' - espresso_version = '3.0.1' - test_runner_version = '1.0.1' + espresso_version = '3.0.2' + test_runner_version = '1.0.2' library_min_version = '14' library_compile_version = 28 library_target_version = 28 library_build_tools_version = "28.0.3" - gradle_tools_version = '3.4.1' - rxJava2_version = "2.2.10" + gradle_tools_version = '4.0.0' + rxJava2_version = "2.2.19" rxAndroid2_version = "2.1.1" timber_version = "4.7.1" novoda_bintray_version = "0.9" From f8a9d48e9daeb2abaedbd8195fc857a8eebfb91f Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sun, 7 Jun 2020 21:08:03 -0400 Subject: [PATCH 28/39] version --- versions.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/versions.gradle b/versions.gradle index a0cebf73..ac8b1f48 100644 --- a/versions.gradle +++ b/versions.gradle @@ -17,6 +17,6 @@ ext { rxAndroid2_version = "2.1.1" timber_version = "4.7.1" novoda_bintray_version = "0.9" - library_version = "3.0.10" - library_version_code = 73 + library_version = "3.0.11-preview" + library_version_code = 74 } \ No newline at end of file From 1772d3fa3a4dd830c2fada27129a60917c0873f2 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sun, 7 Jun 2020 21:22:36 -0400 Subject: [PATCH 29/39] reverted gradle version --- gradle/wrapper/gradle-wrapper.properties | 2 +- versions.gradle | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3f4250ea..16315bf9 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip diff --git a/versions.gradle b/versions.gradle index ac8b1f48..7a445b1a 100644 --- a/versions.gradle +++ b/versions.gradle @@ -12,11 +12,11 @@ ext { library_compile_version = 28 library_target_version = 28 library_build_tools_version = "28.0.3" - gradle_tools_version = '4.0.0' + gradle_tools_version = '3.4.1' rxJava2_version = "2.2.19" rxAndroid2_version = "2.1.1" timber_version = "4.7.1" - novoda_bintray_version = "0.9" + novoda_bintray_version = "0.9.2" library_version = "3.0.11-preview" library_version_code = 74 } \ No newline at end of file From e6efa03fa1d670dc0abf330f0e39871a33352052 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Sun, 7 Jun 2020 21:28:25 -0400 Subject: [PATCH 30/39] version update --- versions.gradle | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/versions.gradle b/versions.gradle index 7a445b1a..c7c41774 100644 --- a/versions.gradle +++ b/versions.gradle @@ -6,12 +6,12 @@ ext { constraint_layout_version = "1.1.3" room_version = '1.1.1' junit_version = '4.12' - espresso_version = '3.0.2' - test_runner_version = '1.0.2' + espresso_version = '3.0.1' + test_runner_version = '1.0.1' library_min_version = '14' - library_compile_version = 28 - library_target_version = 28 - library_build_tools_version = "28.0.3" + library_compile_version = 29 + library_target_version = 29 + library_build_tools_version = "29.0.3" gradle_tools_version = '3.4.1' rxJava2_version = "2.2.19" rxAndroid2_version = "2.1.1" From 612f8d5a2e81aa204bf934b5c21b91780e61b6b0 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Mon, 17 Aug 2020 08:22:03 -0400 Subject: [PATCH 31/39] Fixed contentLength and header issues --- .../fetch2/HttpUrlConnectionDownloader.kt | 13 +-- .../com/tonyodev/fetch2core/FetchCoreUtils.kt | 110 +++++++++++++----- .../tonyodev/fetch2okhttp/OkHttpDownloader.kt | 33 ++---- 3 files changed, 95 insertions(+), 61 deletions(-) diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt b/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt index 52bad384..58f1b007 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/HttpUrlConnectionDownloader.kt @@ -70,9 +70,9 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor( var responseHeaders = getCleanedHeaders(client.headerFields) var code = client.responseCode if ((code == HttpURLConnection.HTTP_MOVED_TEMP - || code == HttpURLConnection.HTTP_MOVED_PERM - || code == HttpURLConnection.HTTP_SEE_OTHER) && getHeaderValue(responseHeaders, "Location") != null) { - httpUrl = URL(getHeaderValue(responseHeaders, "Location")?.firstOrNull() ?: "") + || code == HttpURLConnection.HTTP_MOVED_PERM + || code == HttpURLConnection.HTTP_SEE_OTHER) && getHeaderValue(responseHeaders, "Location") != null) { + httpUrl = URL(getHeaderValue(responseHeaders, "Location") ?: "") client = httpUrl.openConnection() as HttpURLConnection onPreClientExecute(client, request) if (client.getRequestProperty("Referer") == null) { @@ -97,8 +97,7 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor( errorResponseString = copyStreamToString(client.errorStream, false) } - val acceptsRanges = code == HttpURLConnection.HTTP_PARTIAL || - getHeaderValue(responseHeaders, "Accept-Ranges")?.firstOrNull() == "bytes" + val acceptsRanges = acceptRanges(code, responseHeaders) onServerResponse(request, Downloader.Response( code = code, @@ -139,7 +138,7 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor( } override fun getContentHash(responseHeaders: MutableMap>): String { - return getHeaderValue(responseHeaders, "Content-MD5")?.firstOrNull() ?: "" + return getHeaderValue(responseHeaders, "Content-MD5") ?: "" } override fun close() { @@ -190,7 +189,7 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor( } override fun getRequestSupportedFileDownloaderTypes(request: Downloader.ServerRequest): Set { - if(fileDownloaderType == Downloader.FileDownloaderType.SEQUENTIAL) { + if (fileDownloaderType == Downloader.FileDownloaderType.SEQUENTIAL) { return mutableSetOf(fileDownloaderType) } return try { diff --git a/fetch2core/src/main/java/com/tonyodev/fetch2core/FetchCoreUtils.kt b/fetch2core/src/main/java/com/tonyodev/fetch2core/FetchCoreUtils.kt index aa70eab3..799ac812 100644 --- a/fetch2core/src/main/java/com/tonyodev/fetch2core/FetchCoreUtils.kt +++ b/fetch2core/src/main/java/com/tonyodev/fetch2core/FetchCoreUtils.kt @@ -9,6 +9,7 @@ import java.io.* import java.math.BigInteger import java.net.CookieManager import java.net.CookiePolicy +import java.net.HttpURLConnection import java.security.DigestInputStream import java.security.MessageDigest import java.util.concurrent.TimeUnit @@ -19,6 +20,12 @@ const val GET_REQUEST_METHOD = "GET" const val HEAD_REQUEST_METHOD = "HEAD" +internal const val HEADER_ACCEPT_RANGE = "Accept-Ranges" + +internal const val HEADER_ACCEPT_RANGE_LEGACY = "accept-ranges" + +internal const val HEADER_ACCEPT_RANGE_COMPAT = "AcceptRanges" + internal const val HEADER_CONTENT_LENGTH = "content-length" internal const val HEADER_CONTENT_LENGTH_LEGACY = "Content-Length" @@ -27,8 +34,16 @@ internal const val HEADER_CONTENT_LENGTH_COMPAT = "ContentLength" internal const val HEADER_TRANSFER_ENCODING = "Transfer-Encoding" +internal const val HEADER_TRANSFER_LEGACY = "transfer-encoding" + internal const val HEADER_TRANSFER_ENCODING_COMPAT = "TransferEncoding" +internal const val HEADER_CONTENT_RANGE = "Content-Range" + +internal const val HEADER_CONTENT_RANGE_LEGACY = "content-range" + +internal const val HEADER_CONTENT_RANGE_COMPAT = "ContentRange" + fun calculateProgress(downloaded: Long, total: Long): Int { return when { total < 1 -> -1 @@ -193,9 +208,10 @@ fun getRangeForFetchFileServerRequest(range: String): Pair { return Pair(start, end) } +@Suppress("ControlFlowWithEmptyBody") fun getMd5String(bytes: ByteArray, start: Int = 0, length: Int = bytes.size): String { return try { - val buffer = ByteArray(8192) + val buffer = ByteArray(kotlin.io.DEFAULT_BUFFER_SIZE) val md = MessageDigest.getInstance("MD5") val inputStream = DigestInputStream(ByteArrayInputStream(bytes, start, length), md) inputStream.use { dis -> @@ -211,10 +227,11 @@ fun getMd5String(bytes: ByteArray, start: Int = 0, length: Int = bytes.size): St } } +@Suppress("ControlFlowWithEmptyBody") fun getFileMd5String(file: String): String? { val contentFile = File(file) return try { - val buffer = ByteArray(8192) + val buffer = ByteArray(kotlin.io.DEFAULT_BUFFER_SIZE) val md = MessageDigest.getInstance("MD5") val inputStream = DigestInputStream(FileInputStream(contentFile), md) inputStream.use { dis -> @@ -230,21 +247,19 @@ fun getFileMd5String(file: String): String? { } } -fun isParallelDownloadingSupported(responseHeaders: Map>): Boolean { - val transferEncoding = responseHeaders[HEADER_TRANSFER_ENCODING]?.firstOrNull() - ?: responseHeaders[HEADER_TRANSFER_ENCODING_COMPAT]?.firstOrNull() - ?: "" - return transferEncoding.takeIf { it != "chunked" }?.let { - getContentLengthFromHeader(responseHeaders, -1L) > -1L - } ?: false +fun isParallelDownloadingSupported(code: Int, headers: Map>): Boolean { + return acceptRanges(code, headers) } -fun getRequestSupportedFileDownloaderTypes(request: Downloader.ServerRequest, downloader: Downloader<*, *>): Set { +fun getRequestSupportedFileDownloaderTypes( + request: Downloader.ServerRequest, + downloader: Downloader<*, *> +): Set { val fileDownloaderTypeSet = mutableSetOf(Downloader.FileDownloaderType.SEQUENTIAL) return try { val response = downloader.execute(request, getSimpleInterruptMonitor()) if (response != null) { - if (isParallelDownloadingSupported(response.responseHeaders)) { + if (isParallelDownloadingSupported(response.code, response.responseHeaders)) { fileDownloaderTypeSet.add(Downloader.FileDownloaderType.PARALLEL) } downloader.disconnect(response) @@ -256,23 +271,68 @@ fun getRequestSupportedFileDownloaderTypes(request: Downloader.ServerRequest, do } @SuppressLint("DefaultLocale") -fun getHeaderValue(headers: MutableMap>, key: String): List? { - return getCompatHeaders(headers)[key.toLowerCase()] +fun acceptRanges( + code: Int, + headers: Map> +): Boolean { + val acceptRangeValue = getHeaderValue( + headers, + HEADER_ACCEPT_RANGE, + HEADER_ACCEPT_RANGE_LEGACY, + HEADER_ACCEPT_RANGE_COMPAT + ) + val transferValue = getHeaderValue( + headers, + HEADER_TRANSFER_ENCODING, + HEADER_TRANSFER_LEGACY, + HEADER_TRANSFER_ENCODING_COMPAT + ) + val contentLength = getContentLengthFromHeader(headers, -1L) + val acceptsRanges = code == HttpURLConnection.HTTP_PARTIAL || acceptRangeValue == "bytes" + return (contentLength > -1L && acceptsRanges) || (contentLength > -1L && transferValue?.toLowerCase() != "chunked") } -@SuppressLint("DefaultLocale") -private fun getCompatHeaders(headers: MutableMap>): MutableMap> { - val compatHeaders = mutableMapOf>() - for (header in headers) { - compatHeaders[header.key.toLowerCase()] = header.value +fun getContentLengthFromHeader(headers: Map>, defaultValue: Long): Long { + val contentRange = getHeaderValue( + headers, + HEADER_CONTENT_RANGE, + HEADER_CONTENT_RANGE_LEGACY, + HEADER_CONTENT_RANGE_COMPAT + ) + val lastIndexOf = contentRange?.lastIndexOf("/") + var contentLength = -1L + if (lastIndexOf != null && lastIndexOf != -1 && lastIndexOf < contentRange.length) { + contentLength = contentRange.substring(lastIndexOf + 1).toLongOrNull() ?: -1L } - return compatHeaders + if (contentLength == -1L) { + contentLength = getHeaderValue( + headers, + HEADER_CONTENT_LENGTH, + HEADER_CONTENT_LENGTH_LEGACY, + HEADER_CONTENT_LENGTH_COMPAT + )?.toLongOrNull() ?: defaultValue + } + return contentLength +} + +fun getHeaderValue( + headers: Map>, + vararg keys: String +): String? { + for (key in keys) { + val value = headers[key]?.firstOrNull() + if (!value.isNullOrBlank()) { + return value + } + } + return null } fun getRequestContentLength(request: Downloader.ServerRequest, downloader: Downloader<*, *>): Long { return try { val response = downloader.execute(request, getSimpleInterruptMonitor()) - val contentLength = response?.contentLength ?: -1L + val headers = response?.responseHeaders ?: emptyMap() + val contentLength = getContentLengthFromHeader(headers, -1L) if (response != null) { downloader.disconnect(response) } @@ -356,14 +416,4 @@ fun copyStreamToString(inputStream: InputStream?, closeStream: Boolean = true): fun getSimpleInterruptMonitor() = object : InterruptMonitor { override val isInterrupted: Boolean get() = false -} - -fun getContentLengthFromHeader(headers: Map>, defaultValue: Long): Long { - val contentLength = when { - headers.containsKey(HEADER_CONTENT_LENGTH) -> headers[HEADER_CONTENT_LENGTH] - headers.containsKey(HEADER_CONTENT_LENGTH_LEGACY) -> headers[HEADER_CONTENT_LENGTH_LEGACY] - headers.containsKey(HEADER_CONTENT_LENGTH_COMPAT) -> headers[HEADER_CONTENT_LENGTH_COMPAT] - else -> null - } - return contentLength?.firstOrNull()?.toLongOrNull() ?: defaultValue } \ No newline at end of file diff --git a/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt b/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt index f9ec2319..f84b77e9 100644 --- a/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt +++ b/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt @@ -1,7 +1,6 @@ package com.tonyodev.fetch2okhttp import com.tonyodev.fetch2core.* -import okhttp3.Headers import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.Response @@ -50,19 +49,6 @@ open class OkHttpDownloader @JvmOverloads constructor( return okHttpRequestBuilder.build() } - private fun getResponseHeaders(okResponseHeaders: Headers): MutableMap> { - val headers = mutableMapOf>() - for (i in 0 until okResponseHeaders.size) { - val key = okResponseHeaders.name(i) - @Suppress("SENSELESS_COMPARISON") - if (key != null) { - val values = okResponseHeaders.values(key) - headers[key] = values - } - } - return headers - } - private fun getRedirectedServerRequest(oldRequest: Downloader.ServerRequest, redirectUrl: String): Downloader.ServerRequest { return Downloader.ServerRequest( id = oldRequest.id, @@ -88,13 +74,13 @@ open class OkHttpDownloader @JvmOverloads constructor( .build() } var okHttpResponse = client.newCall(okHttpRequest).execute() - var responseHeaders = getResponseHeaders(okHttpResponse.headers) - var code = okHttpResponse.code + var responseHeaders = okHttpResponse.headers().toMultimap() + var code = okHttpResponse.code() if ((code == HttpURLConnection.HTTP_MOVED_TEMP || code == HttpURLConnection.HTTP_MOVED_PERM || code == HttpURLConnection.HTTP_SEE_OTHER) && getHeaderValue(responseHeaders, "Location") != null) { okHttpRequest = onPreClientExecute(client, getRedirectedServerRequest(request, - getHeaderValue(responseHeaders, "Location")?.firstOrNull() ?: "")) + getHeaderValue(responseHeaders, "Location") ?: "")) if (okHttpRequest.header("Referer") == null) { val referer = getRefererFromUrl(request.url) okHttpRequest = okHttpRequest.newBuilder() @@ -102,13 +88,13 @@ open class OkHttpDownloader @JvmOverloads constructor( .build() } okHttpResponse = client.newCall(okHttpRequest).execute() - responseHeaders = getResponseHeaders(okHttpResponse.headers) - code = okHttpResponse.code + responseHeaders = okHttpResponse.headers().toMultimap() + code = okHttpResponse.code() } val success = okHttpResponse.isSuccessful val contentLength = getContentLengthFromHeader(responseHeaders, -1L) - val byteStream: InputStream? = okHttpResponse.body?.byteStream() + val byteStream: InputStream? = okHttpResponse.body()?.byteStream() val errorResponseString: String? = if (!success) { copyStreamToString(byteStream, false) } else { @@ -117,8 +103,7 @@ open class OkHttpDownloader @JvmOverloads constructor( val hash = getContentHash(responseHeaders) - val acceptsRanges = code == HttpURLConnection.HTTP_PARTIAL || - getHeaderValue(responseHeaders, "Accept-Ranges")?.firstOrNull() == "bytes" + val acceptsRanges = acceptRanges(code, responseHeaders) onServerResponse(request, Downloader.Response( code = code, @@ -147,7 +132,7 @@ open class OkHttpDownloader @JvmOverloads constructor( } override fun getContentHash(responseHeaders: MutableMap>): String { - return getHeaderValue(responseHeaders, "Content-MD5")?.firstOrNull() ?: "" + return getHeaderValue(responseHeaders, "Content-MD5") ?: "" } override fun disconnect(response: Downloader.Response) { @@ -206,7 +191,7 @@ open class OkHttpDownloader @JvmOverloads constructor( } override fun getRequestSupportedFileDownloaderTypes(request: Downloader.ServerRequest): Set { - if(fileDownloaderType == Downloader.FileDownloaderType.SEQUENTIAL) { + if (fileDownloaderType == Downloader.FileDownloaderType.SEQUENTIAL) { return mutableSetOf(fileDownloaderType) } return try { From baf93110dbe27f4b4e95f174230a364b0c621660 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Mon, 17 Aug 2020 08:32:24 -0400 Subject: [PATCH 32/39] okhttp fixes --- .../com/tonyodev/fetch2okhttp/OkHttpDownloader.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt b/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt index f84b77e9..206cebd7 100644 --- a/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt +++ b/fetch2okhttp/src/main/java/com/tonyodev/fetch2okhttp/OkHttpDownloader.kt @@ -74,8 +74,8 @@ open class OkHttpDownloader @JvmOverloads constructor( .build() } var okHttpResponse = client.newCall(okHttpRequest).execute() - var responseHeaders = okHttpResponse.headers().toMultimap() - var code = okHttpResponse.code() + var responseHeaders = okHttpResponse.headers.toMultimap() + var code = okHttpResponse.code if ((code == HttpURLConnection.HTTP_MOVED_TEMP || code == HttpURLConnection.HTTP_MOVED_PERM || code == HttpURLConnection.HTTP_SEE_OTHER) && getHeaderValue(responseHeaders, "Location") != null) { @@ -88,20 +88,20 @@ open class OkHttpDownloader @JvmOverloads constructor( .build() } okHttpResponse = client.newCall(okHttpRequest).execute() - responseHeaders = okHttpResponse.headers().toMultimap() - code = okHttpResponse.code() + responseHeaders = okHttpResponse.headers.toMultimap() + code = okHttpResponse.code } val success = okHttpResponse.isSuccessful val contentLength = getContentLengthFromHeader(responseHeaders, -1L) - val byteStream: InputStream? = okHttpResponse.body()?.byteStream() + val byteStream: InputStream? = okHttpResponse.body?.byteStream() val errorResponseString: String? = if (!success) { copyStreamToString(byteStream, false) } else { null } - val hash = getContentHash(responseHeaders) + val hash = getContentHash(responseHeaders.toMutableMap()) val acceptsRanges = acceptRanges(code, responseHeaders) From 7291ce8aa608478aae6baecb4f6ecb425b04a04b Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Mon, 17 Aug 2020 11:45:59 -0400 Subject: [PATCH 33/39] head support --- .../com/tonyodev/fetch2/downloader/DownloadManagerImpl.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/downloader/DownloadManagerImpl.kt b/fetch2/src/main/java/com/tonyodev/fetch2/downloader/DownloadManagerImpl.kt index a94be2fd..b0ac210b 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/downloader/DownloadManagerImpl.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/downloader/DownloadManagerImpl.kt @@ -258,7 +258,12 @@ class DownloadManagerImpl(private val httpDownloader: Downloader<*, *>, } private fun getFileDownloader(download: Download, downloader: Downloader<*, *>): FileDownloader { - val request = getRequestForDownload(download) + val originalRequest = getRequestForDownload(download) + val request = if (downloader.getHeadRequestMethodSupported(originalRequest)) { + getRequestForDownload(download, HEAD_REQUEST_METHOD) + } else { + originalRequest + } val supportedDownloadTypes = downloader.getRequestSupportedFileDownloaderTypes(request) return if (downloader.getRequestFileDownloaderType(request, supportedDownloadTypes) == Downloader.FileDownloaderType.SEQUENTIAL) { SequentialFileDownloaderImpl( From 65421a5d579220c6831f1477198effcdae9498a3 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Mon, 17 Aug 2020 11:53:48 -0400 Subject: [PATCH 34/39] remove call to content provider for file --- .../main/java/com/tonyodev/fetch2core/StorageResolverHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fetch2core/src/main/java/com/tonyodev/fetch2core/StorageResolverHelper.kt b/fetch2core/src/main/java/com/tonyodev/fetch2core/StorageResolverHelper.kt index ba74873f..1b0e63e8 100644 --- a/fetch2core/src/main/java/com/tonyodev/fetch2core/StorageResolverHelper.kt +++ b/fetch2core/src/main/java/com/tonyodev/fetch2core/StorageResolverHelper.kt @@ -134,7 +134,7 @@ fun deleteFile(filePath: String, context: Context): Boolean { when { uri.scheme == "file" -> { val file = File(uri.path) - if (file.canWrite() && file.exists()) deleteFile(file) else context.contentResolver.delete(uri, null, null) > 0 + if (file.canWrite() && file.exists()) deleteFile(file) else false } uri.scheme == "content" -> { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT From c6b58fbcd843de1453da95a1c6dd61a09768538d Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Mon, 17 Aug 2020 12:46:43 -0400 Subject: [PATCH 35/39] Added un metered network connection --- .../java/com/tonyodev/fetch2/NetworkType.kt | 6 ++++- .../fetch2/provider/NetworkInfoProvider.kt | 4 ++++ .../tonyodev/fetch2core/AndroidExtentions.kt | 23 +++++++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/NetworkType.kt b/fetch2/src/main/java/com/tonyodev/fetch2/NetworkType.kt index df20567e..399305da 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/NetworkType.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/NetworkType.kt @@ -15,7 +15,10 @@ enum class NetworkType(val value: Int) { ALL(0), /** Indicates that a download can be downloaded only on wifi networks.*/ - WIFI_ONLY(1); + WIFI_ONLY(1), + + /** Indicates that a download can be downloaded only on an unmetered connection.*/ + UNMETERED(2); companion object { @@ -25,6 +28,7 @@ enum class NetworkType(val value: Int) { -1 -> GLOBAL_OFF 0 -> ALL 1 -> WIFI_ONLY + 2 -> UNMETERED else -> ALL } } diff --git a/fetch2/src/main/java/com/tonyodev/fetch2/provider/NetworkInfoProvider.kt b/fetch2/src/main/java/com/tonyodev/fetch2/provider/NetworkInfoProvider.kt index 4f87531a..3b08186d 100644 --- a/fetch2/src/main/java/com/tonyodev/fetch2/provider/NetworkInfoProvider.kt +++ b/fetch2/src/main/java/com/tonyodev/fetch2/provider/NetworkInfoProvider.kt @@ -11,6 +11,7 @@ import android.net.NetworkRequest import android.os.Build import com.tonyodev.fetch2.NetworkType import com.tonyodev.fetch2core.isNetworkAvailable +import com.tonyodev.fetch2core.isOnMeteredConnection import com.tonyodev.fetch2core.isOnWiFi import java.net.HttpURLConnection import java.net.URL @@ -102,6 +103,9 @@ class NetworkInfoProvider constructor(private val context: Context, if (networkType == NetworkType.WIFI_ONLY && context.isOnWiFi()) { return true } + if (networkType == NetworkType.UNMETERED && !context.isOnMeteredConnection()) { + return true + } if (networkType == NetworkType.ALL && context.isNetworkAvailable()) { return true } diff --git a/fetch2core/src/main/java/com/tonyodev/fetch2core/AndroidExtentions.kt b/fetch2core/src/main/java/com/tonyodev/fetch2core/AndroidExtentions.kt index 71dbfda5..b8c54438 100644 --- a/fetch2core/src/main/java/com/tonyodev/fetch2core/AndroidExtentions.kt +++ b/fetch2core/src/main/java/com/tonyodev/fetch2core/AndroidExtentions.kt @@ -4,6 +4,8 @@ package com.tonyodev.fetch2core import android.content.Context import android.net.ConnectivityManager +import android.net.NetworkInfo +import android.os.Build fun Context.isOnWiFi(): Boolean { @@ -16,6 +18,27 @@ fun Context.isOnWiFi(): Boolean { } } +fun Context.isOnMeteredConnection(): Boolean { + val cm = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager + return if (Build.VERSION.SDK_INT >= 16) { + cm.isActiveNetworkMetered + } else { + val info: NetworkInfo = cm.activeNetworkInfo ?: return true + when (info.type) { + ConnectivityManager.TYPE_MOBILE, + ConnectivityManager.TYPE_MOBILE_DUN, + ConnectivityManager.TYPE_MOBILE_HIPRI, + ConnectivityManager.TYPE_MOBILE_MMS, + ConnectivityManager.TYPE_MOBILE_SUPL, + ConnectivityManager.TYPE_WIMAX -> true + ConnectivityManager.TYPE_WIFI, + ConnectivityManager.TYPE_BLUETOOTH, + ConnectivityManager.TYPE_ETHERNET -> false + else -> true + } + } +} + fun Context.isNetworkAvailable(): Boolean { val manager = this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager val activeNetworkInfo = manager.activeNetworkInfo From f6f8087f61a0b1ee2b5550f20e1a554a9f54a9ed Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Mon, 17 Aug 2020 12:58:31 -0400 Subject: [PATCH 36/39] updated change log --- CHANGELOG | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 5358e386..15ed0be0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,12 @@ +Version 3.0.11/ Androidx version 3.1.5 +2. Notification sound fixes. +3. RxJava fixes. +4. Content Length fixes +5. Added NetworkType.UNMETERED +6. Lots of bug fixes. + +Thanks to everyone who contributed! + Version 3.0.10/ Androidx version 3.1.4 1. Improvements/Bug fixes to getting a download's content-length 2. FetchDatabaseManager interface improvements. It is now easier to create custom fetch databases. From 9d3c13171f2d3c4625484d1ccee62818b867cac7 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Mon, 17 Aug 2020 13:05:18 -0400 Subject: [PATCH 37/39] version update --- versions.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/versions.gradle b/versions.gradle index c7c41774..663d42b0 100644 --- a/versions.gradle +++ b/versions.gradle @@ -17,6 +17,6 @@ ext { rxAndroid2_version = "2.1.1" timber_version = "4.7.1" novoda_bintray_version = "0.9.2" - library_version = "3.0.11-preview" - library_version_code = 74 + library_version = "3.0.11-preview2" + library_version_code = 75 } \ No newline at end of file From c56a710fe965749633d8416025333eae1ea5a855 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Wed, 19 Aug 2020 10:29:45 -0400 Subject: [PATCH 38/39] read me update --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index ac996438..41689b36 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![Build Status](https://travis-ci.org/tonyofrancis/Fetch.svg?branch=v2)](https://travis-ci.org/tonyofrancis/Fetch) -[ ![Download](https://api.bintray.com/packages/tonyofrancis/maven/fetch2/images/download.svg?version=3.0.10) ](https://bintray.com/tonyofrancis/maven/fetch2/3.0.10/link) +[ ![Download](https://api.bintray.com/packages/tonyofrancis/maven/fetch2/images/download.svg?version=3.0.11) ](https://bintray.com/tonyofrancis/maven/fetch2/3.0.11/link) [![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-Android%20Networking-blue.svg?style=flat)](https://android-arsenal.com/details/1/5196) [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/tonyofrancis/Fetch/blob/master/LICENSE) @@ -56,11 +56,11 @@ How to use Fetch Using Fetch is easy! Just add the Gradle dependency to your application's build.gradle file. ```java -implementation "com.tonyodev.fetch2:fetch2:3.0.10" +implementation "com.tonyodev.fetch2:fetch2:3.0.11" ``` Androidx use: ```java -implementation "androidx.tonyodev.fetch2:xfetch2:3.1.4" +implementation "androidx.tonyodev.fetch2:xfetch2:3.1.5" ``` Next, get an instance of Fetch and request a download. @@ -226,11 +226,11 @@ to use the OkHttp Downloader instead. You can create your custom downloaders if necessary. See the Java docs for details. ```java -implementation "com.tonyodev.fetch2okhttp:fetch2okhttp:3.0.10" +implementation "com.tonyodev.fetch2okhttp:fetch2okhttp:3.0.11" ``` Androidx use: ```java -implementation "androidx.tonyodev.fetch2okhttp:xfetch2okhttp:3.1.4" +implementation "androidx.tonyodev.fetch2okhttp:xfetch2okhttp:3.1.5" ``` Set the OkHttp Downloader for Fetch to use. @@ -252,11 +252,11 @@ If you would like to take advantage of RxJava2 features when using Fetch, add the following gradle dependency to your application's build.gradle file. ```java -implementation "com.tonyodev.fetch2rx:fetch2rx:3.0.10" +implementation "com.tonyodev.fetch2rx:fetch2rx:3.0.11" ``` Androidx use: ```java -implementation "androidx.tonyodev.fetch2rx:xfetch2rx:3.1.4" +implementation "androidx.tonyodev.fetch2rx:xfetch2rx:3.1.5" ``` RxFetch makes it super easy to enqueue download requests and query downloads using rxJava2 functional methods. @@ -292,11 +292,11 @@ added in the coming days. Start using FetchFileServer by adding the gradle dependency to your application's build.gradle file. ```java -implementation "com.tonyodev.fetch2fileserver:fetch2fileserver:3.0.10" +implementation "com.tonyodev.fetch2fileserver:fetch2fileserver:3.0.11" ``` Androidx use: ```java -implementation "androidx.tonyodev.fetch2fileserver:xfetch2fileserver:3.1.4" +implementation "androidx.tonyodev.fetch2fileserver:xfetch2fileserver:3.1.5" ``` Start a FetchFileServer instance and add resource files that it can serve to connected clients. @@ -405,11 +405,11 @@ Fetch1 Migration Migrate downloads from Fetch1 to Fetch2 using the migration assistant. Add the following gradle dependency to your application's build.gradle file. ```java -implementation "com.tonyodev.fetchmigrator:fetchmigrator:3.0.10" +implementation "com.tonyodev.fetchmigrator:fetchmigrator:3.0.11" ``` Androidx use: ```java -implementation "androidx.tonyodev.fetchmigrator:xfetchmigrator:3.1.4" +implementation "androidx.tonyodev.fetchmigrator:xfetchmigrator:3.1.5" ``` Then run the Migrator. From edfac869f3f40aedee66e832e5110d1dd6b83ac9 Mon Sep 17 00:00:00 2001 From: Tonyo Francis Date: Wed, 19 Aug 2020 10:34:53 -0400 Subject: [PATCH 39/39] version update --- versions.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/versions.gradle b/versions.gradle index 663d42b0..31558bd2 100644 --- a/versions.gradle +++ b/versions.gradle @@ -17,6 +17,6 @@ ext { rxAndroid2_version = "2.1.1" timber_version = "4.7.1" novoda_bintray_version = "0.9.2" - library_version = "3.0.11-preview2" - library_version_code = 75 + library_version = "3.0.11" + library_version_code = 76 } \ No newline at end of file