Skip to content

Commit

Permalink
Merge branch 'v3-develop' into v3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
tonyofrancis committed Aug 19, 2020
2 parents 61e5b53 + edfac86 commit fb88cb8
Show file tree
Hide file tree
Showing 26 changed files with 412 additions and 199 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
62 changes: 34 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -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)

Expand All @@ -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.
Expand All @@ -43,18 +43,24 @@ add the following storage permissions to your application's manifest. For Androi
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
```
Also, as you are going to use Internet to download files. We need to add the Internet access permissions
in the Manifest.

```xml
<uses-permission android:name="android.permission.INTERNET"/>
```

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.
Expand Down Expand Up @@ -177,27 +183,27 @@ You can query Fetch for download information in several ways.
```java
//Query all downloads
fetch.getDownloads(new Func<List<? extends Download>>() {
@Override
@Override
public void call(List<? extends Download> downloads) {
//Access all downloads here
//Access all downloads here
}
});

//Get all downloads with a status
fetch.getDownloadsWithStatus(Status.DOWNLOADING, new Func<List<? extends Download>>() {
@Override
@Override
public void call(List<? extends Download> 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<List<? extends Download>>() {
@Override
public void call(List<? extends Download> downloads) {
//Access grouped downloads
}
@Override
public void call(List<? extends Download> downloads) {
//Access grouped downloads
}
});
```

Expand All @@ -216,25 +222,25 @@ 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
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.
```java
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);
```
Expand All @@ -246,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.
Expand Down Expand Up @@ -280,20 +286,20 @@ 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.
```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 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 {

Expand Down Expand Up @@ -399,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.
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
10 changes: 8 additions & 2 deletions fetch2/src/main/java/com/tonyodev/fetch2/Error.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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
}
}
Expand Down
2 changes: 2 additions & 0 deletions fetch2/src/main/java/com/tonyodev/fetch2/FetchErrorUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor(
return null
}

private fun getCleanedHeaders(responseHeaders: MutableMap<String?, List<String>?>): MutableMap<String, List<String>> {
val headers = mutableMapOf<String, List<String>>()
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)
Expand All @@ -56,20 +67,20 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor(
client.addRequestProperty("Referer", referer)
}
client.connect()
var responseHeaders = getResponseHeaders(client.headerFields)
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) && responseHeaders.containsKey("location")) {
httpUrl = URL(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) {
val referer = getRefererFromUrl(request.url)
client.addRequestProperty("Referer", referer)
}
client.connect()
responseHeaders = getResponseHeaders(client.headerFields)
responseHeaders = getCleanedHeaders(client.headerFields)
code = client.responseCode
}
var success = false
Expand All @@ -86,8 +97,7 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor(
errorResponseString = copyStreamToString(client.errorStream, false)
}

val acceptsRanges = code == HttpURLConnection.HTTP_PARTIAL ||
responseHeaders["accept-ranges"]?.firstOrNull() == "bytes"
val acceptsRanges = acceptRanges(code, responseHeaders)

onServerResponse(request, Downloader.Response(
code = code,
Expand All @@ -96,7 +106,7 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor(
byteStream = null,
request = request,
hash = hash,
responseHeaders = responseHeaders,
responseHeaders = client.headerFields,
acceptsRanges = acceptsRanges,
errorResponse = errorResponseString))

Expand Down Expand Up @@ -128,7 +138,7 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor(
}

override fun getContentHash(responseHeaders: MutableMap<String, List<String>>): String {
return responseHeaders["content-md5"]?.firstOrNull() ?: ""
return getHeaderValue(responseHeaders, "Content-MD5") ?: ""
}

override fun close() {
Expand All @@ -146,20 +156,6 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor(
}
}

private fun getResponseHeaders(responseHeaders: MutableMap<String, List<String>>): MutableMap<String, List<String>> {
val headers = mutableMapOf<String, List<String>>()
val iterator = responseHeaders.iterator()
var entry: Map.Entry<String, List<String>>
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
}
Expand Down Expand Up @@ -193,6 +189,9 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor(
}

override fun getRequestSupportedFileDownloaderTypes(request: Downloader.ServerRequest): Set<Downloader.FileDownloaderType> {
if (fileDownloaderType == Downloader.FileDownloaderType.SEQUENTIAL) {
return mutableSetOf(fileDownloaderType)
}
return try {
getRequestSupportedFileDownloaderTypes(request, this)
} catch (e: Exception) {
Expand All @@ -212,4 +211,4 @@ open class HttpUrlConnectionDownloader @JvmOverloads constructor(
var followsRedirect = true
}

}
}
6 changes: 5 additions & 1 deletion fetch2/src/main/java/com/tonyodev/fetch2/NetworkType.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand All @@ -25,6 +28,7 @@ enum class NetworkType(val value: Int) {
-1 -> GLOBAL_OFF
0 -> ALL
1 -> WIFI_ONLY
2 -> UNMETERED
else -> ALL
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -257,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(
Expand Down

0 comments on commit fb88cb8

Please sign in to comment.