/*
* Copyright 2015 Hippo Seven
*
* 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
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.network;
import android.text.TextUtils;
import android.webkit.MimeTypeMap;
import com.hippo.io.UniFileOutputStreamPipe;
import com.hippo.unifile.UniFile;
import com.hippo.yorozuya.FileUtils;
import com.hippo.yorozuya.StringUtils;
import com.hippo.yorozuya.Utilities;
import com.hippo.yorozuya.io.OutputStreamPipe;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
public class DownloadClient {
private static long transferData(InputStream in, OutputStream out, OnDownloadListener listener)
throws Exception {
final byte data[] = new byte[1024 * 4];
long receivedSize = 0;
while (true) {
int bytesRead = in.read(data);
if (bytesRead == -1) {
break;
}
out.write(data, 0, bytesRead);
receivedSize += bytesRead;
if (listener != null) {
listener.onDonwlad(receivedSize, bytesRead);
}
}
out.flush();
return receivedSize;
}
private static String getFilenameFromContentDisposition(String contentDisposition) {
if (contentDisposition == null) {
return null;
}
String[] pieces = StringUtils.split(contentDisposition, ';');
for (String piece : pieces) {
int index = piece.indexOf('=');
if (index < 0) {
continue;
}
String key = piece.substring(0, index).trim();
String value = piece.substring(index + 1).trim();
if ("filename".equals(key) && !TextUtils.isEmpty(value)) {
return value;
}
}
return null;
}
public static boolean execute(DownloadRequest request) {
OnDownloadListener listener = request.mListener;
OkHttpClient okHttpClient = request.mOkHttpClient;
UniFile uniFile = null;
OutputStreamPipe osPipe = null;
try {
Call call = okHttpClient.newCall(new Request.Builder().url(request.mUrl).build());
request.mCall = call;
// Listener
if (listener != null) {
listener.onStartDownloading();
}
Response response = call.execute();
ResponseBody body = response.body();
// Check response code
int responseCode = response.code();
if (responseCode >= 400) {
throw new ResponseCodeException(responseCode);
}
osPipe = request.mOSPipe;
if (osPipe == null) {
String extension;
String name;
String dispositionFilename = getFilenameFromContentDisposition(response.header("Content-Disposition"));
if (dispositionFilename != null) {
name = FileUtils.getNameFromFilename(dispositionFilename);
extension = FileUtils.getExtensionFromFilename(dispositionFilename);
} else {
name = Utilities.getNameFromUrl(request.mUrl);
extension = Utilities.getExtensionFromMimeType(response.header("Content-Type"));
if (extension == null) {
extension = MimeTypeMap.getFileExtensionFromUrl(request.mUrl);
}
}
String filename;
if (listener != null) {
filename = listener.onFixname(name, extension, request.mFilename);
} else {
filename = request.mFilename;
}
request.mFilename = filename;
// Use Temp filename
uniFile = request.mDir.createFile(FileUtils.sanitizeFilename(filename + ".download"));
if (uniFile == null) {
// Listener
if (listener != null) {
listener.onFailed(new IOException("Can't create file " + filename));
}
return false;
}
osPipe = new UniFileOutputStreamPipe(uniFile);
}
osPipe.obtain();
long contentLength = body.contentLength();
// Listener
if (listener != null) {
listener.onConnect(contentLength);
}
long receivedSize = transferData(body.byteStream(), osPipe.open(), listener);
if (contentLength > 0 && contentLength != receivedSize) {
throw new IOException("contentLength is " + contentLength + ", but receivedSize is " + receivedSize);
}
// Rename
if (uniFile != null && request.mFilename != null) {
uniFile.renameTo(request.mFilename);
}
// Listener
if (listener != null) {
listener.onSucceed();
}
return true;
} catch (Exception e) {
// remove download failed file
if (uniFile != null) {
uniFile.delete();
}
if (listener != null) {
listener.onFailed(e);
}
return false;
} finally {
if (osPipe != null) {
osPipe.close();
osPipe.release();
}
}
}
public static class SimpleDownloadListener implements OnDownloadListener {
@Override
public void onStartDownloading() {
}
@Override
public String onFixname(String newFilename, String newExtension, String oldFilename) {
return oldFilename;
}
@Override
public void onConnect(long totalSize) {
}
@Override
public void onDonwlad(long receivedSize, long singleReceivedSize) {
}
@Override
public void onFailed(Exception e) {
}
@Override
public void onSucceed() {
}
}
public interface OnDownloadListener {
void onStartDownloading();
String onFixname(String fileFirstname, String extension, String oldFilename);
void onConnect(long totalSize);
void onDonwlad(long receivedSize, long singleReceivedSize);
void onFailed(Exception e);
void onSucceed();
}
}