2013-10-25 17:19:00 +02:00
|
|
|
/*
|
2013-12-20 20:25:49 +01:00
|
|
|
* This is the source code of Telegram for Android v. 1.3.2.
|
2013-10-25 17:19:00 +02:00
|
|
|
* It is licensed under GNU GPL v. 2 or later.
|
|
|
|
* You should have received a copy of the license in this archive (see LICENSE).
|
|
|
|
*
|
|
|
|
* Copyright Nikolai Kudashov, 2013.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package org.telegram.messenger;
|
|
|
|
|
|
|
|
import android.graphics.Bitmap;
|
|
|
|
import android.graphics.BitmapFactory;
|
2013-12-20 20:25:49 +01:00
|
|
|
import android.os.Build;
|
2014-06-12 17:53:20 +02:00
|
|
|
import android.provider.MediaStore;
|
|
|
|
|
|
|
|
import org.telegram.ui.ApplicationLoader;
|
2013-10-25 17:19:00 +02:00
|
|
|
|
|
|
|
import java.io.RandomAccessFile;
|
|
|
|
import java.net.URL;
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.net.URLConnection;
|
2014-02-28 23:28:25 +01:00
|
|
|
import java.nio.channels.FileChannel;
|
2013-10-25 17:19:00 +02:00
|
|
|
import java.util.Scanner;
|
|
|
|
|
|
|
|
public class FileLoadOperation {
|
2014-06-20 21:34:16 +02:00
|
|
|
private int downloadChunkSize = 1024 * 256;
|
2013-10-25 17:19:00 +02:00
|
|
|
|
|
|
|
public int datacenter_id;
|
2013-12-20 20:25:49 +01:00
|
|
|
public TLRPC.InputFileLocation location;
|
2013-10-25 17:19:00 +02:00
|
|
|
public volatile int state = 0;
|
|
|
|
private int downloadedBytes;
|
|
|
|
public int totalBytesCount;
|
|
|
|
public FileLoadOperationDelegate delegate;
|
|
|
|
public Bitmap image;
|
|
|
|
public String filter;
|
|
|
|
private byte[] key;
|
|
|
|
private byte[] iv;
|
|
|
|
private long requestToken = 0;
|
2014-06-20 21:34:16 +02:00
|
|
|
private long requestToken2 = 0;
|
|
|
|
private int requestProgress = 0;
|
|
|
|
private int requestProgress2 = 0;
|
|
|
|
private int nextDownloadOffset = 0;
|
|
|
|
private TLRPC.TL_upload_file delayedRes = null;
|
|
|
|
private int delayedResOffset = 0;
|
|
|
|
private int delayedResTokenNum = 0;
|
2013-10-25 17:19:00 +02:00
|
|
|
|
|
|
|
private File cacheFileTemp;
|
|
|
|
private File cacheFileFinal;
|
2013-12-20 20:25:49 +01:00
|
|
|
private File cacheIvTemp;
|
2013-10-25 17:19:00 +02:00
|
|
|
|
2013-12-26 12:43:37 +01:00
|
|
|
private String ext;
|
2013-10-25 17:19:00 +02:00
|
|
|
private String httpUrl;
|
|
|
|
private URLConnection httpConnection;
|
|
|
|
public boolean needBitmapCreate = true;
|
|
|
|
private InputStream httpConnectionStream;
|
|
|
|
private RandomAccessFile fileOutputStream;
|
2013-12-20 20:25:49 +01:00
|
|
|
RandomAccessFile fiv;
|
2013-10-25 17:19:00 +02:00
|
|
|
|
|
|
|
public static interface FileLoadOperationDelegate {
|
|
|
|
public abstract void didFinishLoadingFile(FileLoadOperation operation);
|
|
|
|
public abstract void didFailedLoadingFile(FileLoadOperation operation);
|
|
|
|
public abstract void didChangedLoadProgress(FileLoadOperation operation, float progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
public FileLoadOperation(TLRPC.FileLocation fileLocation) {
|
|
|
|
if (fileLocation instanceof TLRPC.TL_fileEncryptedLocation) {
|
|
|
|
location = new TLRPC.TL_inputEncryptedFileLocation();
|
|
|
|
location.id = fileLocation.volume_id;
|
|
|
|
location.volume_id = fileLocation.volume_id;
|
|
|
|
location.access_hash = fileLocation.secret;
|
|
|
|
location.local_id = fileLocation.local_id;
|
|
|
|
iv = new byte[32];
|
|
|
|
System.arraycopy(fileLocation.iv, 0, iv, 0, iv.length);
|
|
|
|
key = fileLocation.key;
|
|
|
|
datacenter_id = fileLocation.dc_id;
|
|
|
|
} else if (fileLocation instanceof TLRPC.TL_fileLocation) {
|
|
|
|
location = new TLRPC.TL_inputFileLocation();
|
|
|
|
location.volume_id = fileLocation.volume_id;
|
|
|
|
location.secret = fileLocation.secret;
|
|
|
|
location.local_id = fileLocation.local_id;
|
|
|
|
datacenter_id = fileLocation.dc_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public FileLoadOperation(TLRPC.Video videoLocation) {
|
2014-06-20 02:18:13 +02:00
|
|
|
if (videoLocation instanceof TLRPC.TL_videoEncrypted) {
|
2013-10-25 17:19:00 +02:00
|
|
|
location = new TLRPC.TL_inputEncryptedFileLocation();
|
|
|
|
location.id = videoLocation.id;
|
|
|
|
location.access_hash = videoLocation.access_hash;
|
|
|
|
datacenter_id = videoLocation.dc_id;
|
|
|
|
iv = new byte[32];
|
|
|
|
System.arraycopy(videoLocation.iv, 0, iv, 0, iv.length);
|
|
|
|
key = videoLocation.key;
|
2014-06-20 02:18:13 +02:00
|
|
|
} else if (videoLocation instanceof TLRPC.TL_video) {
|
|
|
|
location = new TLRPC.TL_inputVideoFileLocation();
|
|
|
|
datacenter_id = videoLocation.dc_id;
|
|
|
|
location.id = videoLocation.id;
|
|
|
|
location.access_hash = videoLocation.access_hash;
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
2013-12-26 12:43:37 +01:00
|
|
|
ext = ".mp4";
|
|
|
|
}
|
|
|
|
|
2014-02-11 15:32:09 +01:00
|
|
|
public FileLoadOperation(TLRPC.Audio audioLocation) {
|
2014-06-11 01:05:54 +02:00
|
|
|
if (audioLocation instanceof TLRPC.TL_audioEncrypted) {
|
2014-02-11 15:32:09 +01:00
|
|
|
location = new TLRPC.TL_inputEncryptedFileLocation();
|
|
|
|
location.id = audioLocation.id;
|
|
|
|
location.access_hash = audioLocation.access_hash;
|
|
|
|
datacenter_id = audioLocation.dc_id;
|
|
|
|
iv = new byte[32];
|
|
|
|
System.arraycopy(audioLocation.iv, 0, iv, 0, iv.length);
|
|
|
|
key = audioLocation.key;
|
2014-06-11 01:05:54 +02:00
|
|
|
} else if (audioLocation instanceof TLRPC.TL_audio) {
|
|
|
|
location = new TLRPC.TL_inputAudioFileLocation();
|
|
|
|
datacenter_id = audioLocation.dc_id;
|
|
|
|
location.id = audioLocation.id;
|
|
|
|
location.access_hash = audioLocation.access_hash;
|
2014-02-11 15:32:09 +01:00
|
|
|
}
|
|
|
|
ext = ".m4a";
|
|
|
|
}
|
|
|
|
|
2013-12-26 12:43:37 +01:00
|
|
|
public FileLoadOperation(TLRPC.Document documentLocation) {
|
2014-06-20 02:18:13 +02:00
|
|
|
if (documentLocation instanceof TLRPC.TL_documentEncrypted) {
|
2013-12-26 12:43:37 +01:00
|
|
|
location = new TLRPC.TL_inputEncryptedFileLocation();
|
|
|
|
location.id = documentLocation.id;
|
|
|
|
location.access_hash = documentLocation.access_hash;
|
|
|
|
datacenter_id = documentLocation.dc_id;
|
|
|
|
iv = new byte[32];
|
|
|
|
System.arraycopy(documentLocation.iv, 0, iv, 0, iv.length);
|
|
|
|
key = documentLocation.key;
|
2014-06-20 02:18:13 +02:00
|
|
|
} else if (documentLocation instanceof TLRPC.TL_document) {
|
|
|
|
location = new TLRPC.TL_inputDocumentFileLocation();
|
|
|
|
datacenter_id = documentLocation.dc_id;
|
|
|
|
location.id = documentLocation.id;
|
|
|
|
location.access_hash = documentLocation.access_hash;
|
2013-12-26 12:43:37 +01:00
|
|
|
}
|
|
|
|
ext = documentLocation.file_name;
|
|
|
|
int idx = -1;
|
|
|
|
if (ext == null || (idx = ext.lastIndexOf(".")) == -1) {
|
|
|
|
ext = "";
|
|
|
|
} else {
|
|
|
|
ext = ext.substring(idx);
|
|
|
|
if (ext.length() <= 1) {
|
|
|
|
ext = "";
|
|
|
|
}
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public FileLoadOperation(String url) {
|
|
|
|
httpUrl = url;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void start() {
|
|
|
|
if (state != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
state = 1;
|
2013-12-20 20:25:49 +01:00
|
|
|
if (location == null && httpUrl == null) {
|
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
boolean ignoreCache = false;
|
|
|
|
boolean onlyCache = false;
|
2013-12-26 12:43:37 +01:00
|
|
|
boolean isLocalFile = false;
|
2014-06-12 17:53:20 +02:00
|
|
|
Long mediaId = null;
|
2013-12-20 20:25:49 +01:00
|
|
|
String fileNameFinal = null;
|
|
|
|
String fileNameTemp = null;
|
|
|
|
String fileNameIv = null;
|
2013-10-25 17:19:00 +02:00
|
|
|
if (httpUrl != null) {
|
2013-12-26 12:43:37 +01:00
|
|
|
if (!httpUrl.startsWith("http")) {
|
2014-06-12 17:53:20 +02:00
|
|
|
if (httpUrl.startsWith("thumb://")) {
|
|
|
|
int idx = httpUrl.indexOf(":", 8);
|
|
|
|
if (idx >= 0) {
|
|
|
|
String media = httpUrl.substring(8, idx);
|
|
|
|
mediaId = Long.parseLong(media);
|
|
|
|
fileNameFinal = httpUrl.substring(idx + 1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fileNameFinal = httpUrl;
|
|
|
|
}
|
2013-12-26 12:43:37 +01:00
|
|
|
onlyCache = true;
|
|
|
|
isLocalFile = true;
|
|
|
|
} else {
|
|
|
|
fileNameFinal = Utilities.MD5(httpUrl);
|
|
|
|
fileNameTemp = fileNameFinal + "_temp.jpg";
|
|
|
|
fileNameFinal += ".jpg";
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
} else if (location.volume_id != 0 && location.local_id != 0) {
|
|
|
|
fileNameTemp = location.volume_id + "_" + location.local_id + "_temp.jpg";
|
|
|
|
fileNameFinal = location.volume_id + "_" + location.local_id + ".jpg";
|
2013-12-20 20:25:49 +01:00
|
|
|
if (key != null) {
|
|
|
|
fileNameIv = location.volume_id + "_" + location.local_id + ".iv";
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
if (datacenter_id == Integer.MIN_VALUE || location.volume_id == Integer.MIN_VALUE) {
|
|
|
|
onlyCache = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ignoreCache = true;
|
|
|
|
needBitmapCreate = false;
|
2013-12-26 12:43:37 +01:00
|
|
|
fileNameTemp = datacenter_id + "_" + location.id + "_temp" + ext;
|
|
|
|
fileNameFinal = datacenter_id + "_" + location.id + ext;
|
2013-12-20 20:25:49 +01:00
|
|
|
if (key != null) {
|
|
|
|
fileNameIv = datacenter_id + "_" + location.id + ".iv";
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
boolean exist;
|
2013-12-26 12:43:37 +01:00
|
|
|
if (isLocalFile) {
|
|
|
|
cacheFileFinal = new File(fileNameFinal);
|
|
|
|
} else {
|
|
|
|
cacheFileFinal = new File(Utilities.getCacheDir(), fileNameFinal);
|
|
|
|
}
|
|
|
|
final boolean dontDelete = isLocalFile;
|
2014-06-12 17:53:20 +02:00
|
|
|
final Long mediaIdFinal = mediaId;
|
2013-10-25 17:19:00 +02:00
|
|
|
if ((exist = cacheFileFinal.exists()) && !ignoreCache) {
|
2014-03-31 16:14:49 +02:00
|
|
|
FileLoader.cacheOutQueue.postRunnable(new Runnable() {
|
2013-10-25 17:19:00 +02:00
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
try {
|
|
|
|
int delay = 20;
|
2014-03-22 23:31:55 +01:00
|
|
|
if (FileLoader.getInstance().runtimeHack != null) {
|
2013-10-25 17:19:00 +02:00
|
|
|
delay = 60;
|
|
|
|
}
|
2014-06-12 17:53:20 +02:00
|
|
|
if (mediaIdFinal != null) {
|
|
|
|
delay = 0;
|
|
|
|
}
|
|
|
|
if (delay != 0 && FileLoader.lastCacheOutTime != 0 && FileLoader.lastCacheOutTime > System.currentTimeMillis() - delay) {
|
2013-10-25 17:19:00 +02:00
|
|
|
Thread.sleep(delay);
|
|
|
|
}
|
|
|
|
FileLoader.lastCacheOutTime = System.currentTimeMillis();
|
|
|
|
if (state != 1) {
|
|
|
|
return;
|
|
|
|
}
|
2014-06-12 17:53:20 +02:00
|
|
|
|
2013-10-25 17:19:00 +02:00
|
|
|
if (needBitmapCreate) {
|
|
|
|
BitmapFactory.Options opts = new BitmapFactory.Options();
|
|
|
|
|
|
|
|
float w_filter = 0;
|
2014-05-17 01:05:49 +02:00
|
|
|
float h_filter = 0;
|
2013-10-25 17:19:00 +02:00
|
|
|
if (filter != null) {
|
|
|
|
String args[] = filter.split("_");
|
2013-12-26 17:46:13 +01:00
|
|
|
w_filter = Float.parseFloat(args[0]) * Utilities.density;
|
|
|
|
h_filter = Float.parseFloat(args[1]) * Utilities.density;
|
2013-10-25 17:19:00 +02:00
|
|
|
opts.inJustDecodeBounds = true;
|
2014-06-12 17:53:20 +02:00
|
|
|
|
|
|
|
if (mediaIdFinal != null) {
|
|
|
|
MediaStore.Images.Thumbnails.getThumbnail(ApplicationLoader.applicationContext.getContentResolver(), mediaIdFinal, MediaStore.Images.Thumbnails.MINI_KIND, opts);
|
|
|
|
} else {
|
|
|
|
BitmapFactory.decodeFile(cacheFileFinal.getAbsolutePath(), opts);
|
|
|
|
}
|
|
|
|
|
2013-10-25 17:19:00 +02:00
|
|
|
float photoW = opts.outWidth;
|
|
|
|
float photoH = opts.outHeight;
|
|
|
|
float scaleFactor = Math.max(photoW / w_filter, photoH / h_filter);
|
|
|
|
if (scaleFactor < 1) {
|
|
|
|
scaleFactor = 1;
|
|
|
|
}
|
|
|
|
opts.inJustDecodeBounds = false;
|
|
|
|
opts.inSampleSize = (int)scaleFactor;
|
|
|
|
}
|
|
|
|
|
2014-02-28 23:28:25 +01:00
|
|
|
if (filter == null) {
|
|
|
|
opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
|
|
|
} else {
|
|
|
|
opts.inPreferredConfig = Bitmap.Config.RGB_565;
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
opts.inDither = false;
|
2014-06-12 17:53:20 +02:00
|
|
|
if (mediaIdFinal != null) {
|
2014-06-12 21:55:13 +02:00
|
|
|
image = MediaStore.Images.Thumbnails.getThumbnail(ApplicationLoader.applicationContext.getContentResolver(), mediaIdFinal, MediaStore.Images.Thumbnails.MINI_KIND, null);
|
2014-06-12 17:53:20 +02:00
|
|
|
}
|
|
|
|
if (image == null) {
|
|
|
|
FileInputStream is = new FileInputStream(cacheFileFinal);
|
|
|
|
image = BitmapFactory.decodeStream(is, null, opts);
|
|
|
|
is.close();
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
if (image == null) {
|
2014-03-22 23:31:55 +01:00
|
|
|
if (!dontDelete && (cacheFileFinal.length() == 0 || filter == null)) {
|
2014-02-28 23:28:25 +01:00
|
|
|
cacheFileFinal.delete();
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
} else {
|
2014-06-12 21:55:13 +02:00
|
|
|
if (filter != null) {
|
2013-10-25 17:19:00 +02:00
|
|
|
float bitmapW = image.getWidth();
|
|
|
|
float bitmapH = image.getHeight();
|
|
|
|
if (bitmapW != w_filter && bitmapW > w_filter) {
|
|
|
|
float scaleFactor = bitmapW / w_filter;
|
2014-05-17 01:05:49 +02:00
|
|
|
Bitmap scaledBitmap = Bitmap.createScaledBitmap(image, (int)w_filter, (int)(bitmapH / scaleFactor), false);
|
2013-10-25 17:19:00 +02:00
|
|
|
if (image != scaledBitmap) {
|
2013-12-20 20:25:49 +01:00
|
|
|
if (Build.VERSION.SDK_INT < 11) {
|
|
|
|
image.recycle();
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
image = scaledBitmap;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2014-03-22 23:31:55 +01:00
|
|
|
if (FileLoader.getInstance().runtimeHack != null) {
|
|
|
|
FileLoader.getInstance().runtimeHack.trackFree(image.getRowBytes() * image.getHeight());
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2014-02-11 15:32:09 +01:00
|
|
|
if (image == null) {
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
|
|
|
} else {
|
|
|
|
delegate.didFinishLoadingFile(FileLoadOperation.this);
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
} catch (Exception e) {
|
2014-02-28 23:28:25 +01:00
|
|
|
if (!dontDelete && cacheFileFinal.length() == 0) {
|
|
|
|
cacheFileFinal.delete();
|
|
|
|
}
|
2014-05-17 01:05:49 +02:00
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
|
|
|
}
|
|
|
|
});
|
2013-12-20 20:25:49 +01:00
|
|
|
FileLog.e("tmessages", e);
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
if (onlyCache) {
|
2013-12-20 20:25:49 +01:00
|
|
|
cleanup();
|
2013-10-25 17:19:00 +02:00
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
cacheFileTemp = new File(Utilities.getCacheDir(), fileNameTemp);
|
|
|
|
if (cacheFileTemp.exists()) {
|
|
|
|
downloadedBytes = (int)cacheFileTemp.length();
|
2014-06-20 21:34:16 +02:00
|
|
|
nextDownloadOffset = downloadedBytes = downloadedBytes / 1024 * 1024;
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
2013-12-20 20:25:49 +01:00
|
|
|
if (fileNameIv != null) {
|
|
|
|
cacheIvTemp = new File(Utilities.getCacheDir(), fileNameIv);
|
|
|
|
try {
|
|
|
|
fiv = new RandomAccessFile(cacheIvTemp, "rws");
|
|
|
|
long len = cacheIvTemp.length();
|
|
|
|
if (len > 0 && len % 32 == 0) {
|
|
|
|
fiv.read(iv, 0, 32);
|
|
|
|
} else {
|
|
|
|
downloadedBytes = 0;
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
downloadedBytes = 0;
|
|
|
|
}
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
if (exist) {
|
|
|
|
cacheFileFinal.delete();
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
fileOutputStream = new RandomAccessFile(cacheFileTemp, "rws");
|
|
|
|
if (downloadedBytes != 0) {
|
|
|
|
fileOutputStream.seek(downloadedBytes);
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
2013-12-20 20:25:49 +01:00
|
|
|
FileLog.e("tmessages", e);
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
if (fileOutputStream == null) {
|
2013-12-20 20:25:49 +01:00
|
|
|
cleanup();
|
2013-10-25 17:19:00 +02:00
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
|
|
|
}
|
|
|
|
});
|
2013-12-20 20:25:49 +01:00
|
|
|
return;
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
if (httpUrl != null) {
|
|
|
|
startDownloadHTTPRequest();
|
|
|
|
} else {
|
2014-06-21 23:46:11 +02:00
|
|
|
if (totalBytesCount >= 1024 * 1024) {
|
|
|
|
downloadChunkSize = 1024 * 256;
|
|
|
|
} else {
|
|
|
|
downloadChunkSize = 1024 * 32;
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
startDownloadRequest();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void cancel() {
|
|
|
|
if (state != 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
state = 2;
|
2013-12-20 20:25:49 +01:00
|
|
|
cleanup();
|
2014-06-20 21:34:16 +02:00
|
|
|
if (httpUrl == null) {
|
2014-03-22 23:31:55 +01:00
|
|
|
ConnectionsManager.getInstance().cancelRpc(requestToken, true);
|
2014-06-20 21:34:16 +02:00
|
|
|
ConnectionsManager.getInstance().cancelRpc(requestToken2, true);
|
2013-12-20 20:25:49 +01:00
|
|
|
}
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void cleanup() {
|
2013-10-25 17:19:00 +02:00
|
|
|
if (httpUrl != null) {
|
|
|
|
try {
|
2013-12-26 12:43:37 +01:00
|
|
|
if (httpConnectionStream != null) {
|
|
|
|
httpConnectionStream.close();
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
httpConnection = null;
|
|
|
|
httpConnectionStream = null;
|
|
|
|
} catch (Exception e) {
|
2013-12-20 20:25:49 +01:00
|
|
|
FileLog.e("tmessages", e);
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
} else {
|
2013-12-20 20:25:49 +01:00
|
|
|
try {
|
|
|
|
if (fileOutputStream != null) {
|
2013-10-25 17:19:00 +02:00
|
|
|
fileOutputStream.close();
|
|
|
|
fileOutputStream = null;
|
|
|
|
}
|
2013-12-20 20:25:49 +01:00
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
2013-12-20 20:25:49 +01:00
|
|
|
|
|
|
|
try {
|
|
|
|
if (fiv != null) {
|
|
|
|
fiv.close();
|
|
|
|
fiv = null;
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
2014-06-20 21:34:16 +02:00
|
|
|
|
|
|
|
if (delayedRes != null) {
|
|
|
|
delayedRes.disableFree = false;
|
|
|
|
delayedRes.freeResources();
|
|
|
|
delayedRes = null;
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void onFinishLoadingFile() throws Exception {
|
|
|
|
if (state != 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
state = 3;
|
2013-12-20 20:25:49 +01:00
|
|
|
cleanup();
|
|
|
|
if (cacheIvTemp != null) {
|
|
|
|
cacheIvTemp.delete();
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
final boolean renamed = cacheFileTemp.renameTo(cacheFileFinal);
|
|
|
|
|
|
|
|
if (needBitmapCreate) {
|
2014-03-31 16:14:49 +02:00
|
|
|
FileLoader.cacheOutQueue.postRunnable(new Runnable() {
|
2013-10-25 17:19:00 +02:00
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
int delay = 20;
|
2014-03-22 23:31:55 +01:00
|
|
|
if (FileLoader.getInstance().runtimeHack != null) {
|
2013-10-25 17:19:00 +02:00
|
|
|
delay = 60;
|
|
|
|
}
|
|
|
|
if (FileLoader.lastCacheOutTime != 0 && FileLoader.lastCacheOutTime > System.currentTimeMillis() - delay) {
|
|
|
|
try {
|
|
|
|
Thread.sleep(delay);
|
|
|
|
} catch (Exception e) {
|
2013-12-20 20:25:49 +01:00
|
|
|
FileLog.e("tmessages", e);
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
BitmapFactory.Options opts = new BitmapFactory.Options();
|
|
|
|
|
|
|
|
float w_filter = 0;
|
|
|
|
float h_filter;
|
|
|
|
if (filter != null) {
|
|
|
|
String args[] = filter.split("_");
|
2013-12-26 17:46:13 +01:00
|
|
|
w_filter = Float.parseFloat(args[0]) * Utilities.density;
|
|
|
|
h_filter = Float.parseFloat(args[1]) * Utilities.density;
|
2013-10-25 17:19:00 +02:00
|
|
|
|
|
|
|
opts.inJustDecodeBounds = true;
|
|
|
|
BitmapFactory.decodeFile(cacheFileFinal.getAbsolutePath(), opts);
|
|
|
|
float photoW = opts.outWidth;
|
|
|
|
float photoH = opts.outHeight;
|
|
|
|
float scaleFactor = Math.max(photoW / w_filter, photoH / h_filter);
|
|
|
|
if (scaleFactor < 1) {
|
|
|
|
scaleFactor = 1;
|
|
|
|
}
|
|
|
|
opts.inJustDecodeBounds = false;
|
|
|
|
opts.inSampleSize = (int) scaleFactor;
|
|
|
|
}
|
|
|
|
|
2014-02-28 23:28:25 +01:00
|
|
|
if (filter == null) {
|
|
|
|
opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
|
|
|
} else {
|
|
|
|
opts.inPreferredConfig = Bitmap.Config.RGB_565;
|
|
|
|
}
|
|
|
|
|
2013-10-25 17:19:00 +02:00
|
|
|
opts.inDither = false;
|
|
|
|
try {
|
|
|
|
if (renamed) {
|
|
|
|
image = BitmapFactory.decodeStream(new FileInputStream(cacheFileFinal), null, opts);
|
|
|
|
} else {
|
2014-02-04 19:36:55 +01:00
|
|
|
try {
|
|
|
|
image = BitmapFactory.decodeStream(new FileInputStream(cacheFileTemp), null, opts);
|
|
|
|
} catch (Exception e) {
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
image = BitmapFactory.decodeStream(new FileInputStream(cacheFileFinal), null, opts);
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
if (filter != null && image != null) {
|
|
|
|
float bitmapW = image.getWidth();
|
|
|
|
float bitmapH = image.getHeight();
|
|
|
|
if (bitmapW != w_filter && bitmapW > w_filter) {
|
|
|
|
float scaleFactor = bitmapW / w_filter;
|
2014-05-17 01:05:49 +02:00
|
|
|
Bitmap scaledBitmap = Bitmap.createScaledBitmap(image, (int) w_filter, (int) (bitmapH / scaleFactor), false);
|
2013-10-25 17:19:00 +02:00
|
|
|
if (image != scaledBitmap) {
|
2013-12-20 20:25:49 +01:00
|
|
|
if (Build.VERSION.SDK_INT < 11) {
|
|
|
|
image.recycle();
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
image = scaledBitmap;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2014-03-22 23:31:55 +01:00
|
|
|
if (image != null && FileLoader.getInstance().runtimeHack != null) {
|
|
|
|
FileLoader.getInstance().runtimeHack.trackFree(image.getRowBytes() * image.getHeight());
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
2014-02-11 15:32:09 +01:00
|
|
|
if (image != null) {
|
|
|
|
delegate.didFinishLoadingFile(FileLoadOperation.this);
|
|
|
|
} else {
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
} catch (Exception e) {
|
2013-12-20 20:25:49 +01:00
|
|
|
FileLog.e("tmessages", e);
|
2014-02-04 19:36:55 +01:00
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
delegate.didFinishLoadingFile(FileLoadOperation.this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void startDownloadHTTPRequest() {
|
|
|
|
if (state != 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (httpConnection == null) {
|
|
|
|
try {
|
|
|
|
URL downloadUrl = new URL(httpUrl);
|
|
|
|
httpConnection = downloadUrl.openConnection();
|
|
|
|
httpConnection.setConnectTimeout(5000);
|
|
|
|
httpConnection.setReadTimeout(5000);
|
|
|
|
httpConnection.connect();
|
|
|
|
httpConnectionStream = httpConnection.getInputStream();
|
|
|
|
} catch (Exception e) {
|
2013-12-20 20:25:49 +01:00
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
cleanup();
|
2013-10-25 17:19:00 +02:00
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
byte[] data = new byte[1024 * 2];
|
|
|
|
int readed = httpConnectionStream.read(data);
|
|
|
|
if (readed > 0) {
|
|
|
|
fileOutputStream.write(data, 0, readed);
|
2014-03-31 16:14:49 +02:00
|
|
|
FileLoader.fileLoaderQueue.postRunnable(new Runnable() {
|
2013-10-25 17:19:00 +02:00
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
startDownloadHTTPRequest();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else if (readed == -1) {
|
2013-12-20 20:25:49 +01:00
|
|
|
cleanup();
|
2013-10-25 17:19:00 +02:00
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
try {
|
|
|
|
onFinishLoadingFile();
|
|
|
|
} catch (Exception e) {
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
} else {
|
2013-12-20 20:25:49 +01:00
|
|
|
cleanup();
|
2013-10-25 17:19:00 +02:00
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
2013-12-20 20:25:49 +01:00
|
|
|
cleanup();
|
|
|
|
FileLog.e("tmessages", e);
|
2013-10-25 17:19:00 +02:00
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-20 21:34:16 +02:00
|
|
|
private void processRequestResult(TLRPC.TL_upload_file res, TLRPC.TL_error error, int dowloadOffset, int tokenNum) {
|
|
|
|
if (error == null) {
|
|
|
|
try {
|
|
|
|
if (downloadedBytes != dowloadOffset) {
|
|
|
|
if (delayedRes != null) {
|
|
|
|
FileLog.e("tmessages", "something went wrong!");
|
|
|
|
}
|
|
|
|
delayedRes = res;
|
|
|
|
delayedRes.disableFree = true;
|
|
|
|
delayedResOffset = dowloadOffset;
|
|
|
|
delayedResTokenNum = tokenNum;
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
if (tokenNum == 0) {
|
|
|
|
requestToken = 0;
|
|
|
|
} else if (tokenNum == 1) {
|
|
|
|
requestToken2 = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res.bytes.limit() == 0) {
|
|
|
|
onFinishLoadingFile();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (key != null) {
|
|
|
|
Utilities.aesIgeEncryption2(res.bytes.buffer, key, iv, false, true, res.bytes.limit());
|
|
|
|
}
|
|
|
|
if (fileOutputStream != null) {
|
|
|
|
FileChannel channel = fileOutputStream.getChannel();
|
|
|
|
channel.write(res.bytes.buffer);
|
|
|
|
}
|
|
|
|
if (fiv != null) {
|
|
|
|
fiv.seek(0);
|
|
|
|
fiv.write(iv);
|
|
|
|
}
|
|
|
|
downloadedBytes += res.bytes.limit();
|
|
|
|
if (totalBytesCount > 0 && state == 1) {
|
|
|
|
delegate.didChangedLoadProgress(FileLoadOperation.this, Math.min(1.0f, (float)downloadedBytes / (float)totalBytesCount));
|
|
|
|
}
|
|
|
|
|
|
|
|
if(delayedRes != null && res != delayedRes) {
|
|
|
|
TLRPC.TL_upload_file temp = delayedRes;
|
|
|
|
processRequestResult(temp, null, delayedResOffset, delayedResTokenNum);
|
|
|
|
if (delayedRes != null) {
|
|
|
|
delayedRes.disableFree = false;
|
|
|
|
delayedRes.freeResources();
|
|
|
|
delayedRes = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (downloadedBytes % downloadChunkSize == 0 || totalBytesCount > 0 && totalBytesCount != downloadedBytes) {
|
|
|
|
startDownloadRequest();
|
|
|
|
} else {
|
|
|
|
onFinishLoadingFile();
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
cleanup();
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
|
|
|
FileLog.e("tmessages", e);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (error.text.contains("FILE_MIGRATE_")) {
|
|
|
|
String errorMsg = error.text.replace("FILE_MIGRATE_", "");
|
|
|
|
Scanner scanner = new Scanner(errorMsg);
|
|
|
|
scanner.useDelimiter("");
|
|
|
|
Integer val;
|
|
|
|
try {
|
|
|
|
val = scanner.nextInt();
|
|
|
|
} catch (Exception e) {
|
|
|
|
val = null;
|
|
|
|
}
|
|
|
|
if (val == null) {
|
|
|
|
cleanup();
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
|
|
|
} else {
|
|
|
|
datacenter_id = val;
|
|
|
|
nextDownloadOffset = 0;
|
|
|
|
startDownloadRequest();
|
|
|
|
}
|
|
|
|
} else if (error.text.contains("OFFSET_INVALID")) {
|
|
|
|
if (downloadedBytes % downloadChunkSize == 0) {
|
2013-10-25 17:19:00 +02:00
|
|
|
try {
|
2014-06-20 21:34:16 +02:00
|
|
|
onFinishLoadingFile();
|
2013-10-25 17:19:00 +02:00
|
|
|
} catch (Exception e) {
|
2014-06-20 21:34:16 +02:00
|
|
|
FileLog.e("tmessages", e);
|
2013-12-20 20:25:49 +01:00
|
|
|
cleanup();
|
2013-10-25 17:19:00 +02:00
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
|
|
|
}
|
|
|
|
} else {
|
2014-06-20 21:34:16 +02:00
|
|
|
cleanup();
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (location != null) {
|
|
|
|
FileLog.e("tmessages", "" + location + " id = " + location.id + " access_hash = " + location.access_hash + " volume_id = " + location.local_id + " secret = " + location.secret);
|
|
|
|
}
|
|
|
|
cleanup();
|
|
|
|
delegate.didFailedLoadingFile(FileLoadOperation.this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void processRequestProgress() {
|
|
|
|
delegate.didChangedLoadProgress(FileLoadOperation.this, Math.min(1.0f, (float) (downloadedBytes + requestProgress + requestProgress2) / (float) totalBytesCount));
|
|
|
|
}
|
|
|
|
|
|
|
|
private void startDownloadRequest() {
|
|
|
|
if (state != 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (requestToken == 0) {
|
|
|
|
requestProgress = 0;
|
|
|
|
if (totalBytesCount > 0 && nextDownloadOffset >= totalBytesCount) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
final TLRPC.TL_upload_getFile req = new TLRPC.TL_upload_getFile();
|
|
|
|
req.location = location;
|
|
|
|
req.offset = nextDownloadOffset;
|
|
|
|
req.limit = downloadChunkSize;
|
|
|
|
nextDownloadOffset += downloadChunkSize;
|
|
|
|
final long time = System.currentTimeMillis();
|
|
|
|
requestToken = ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() {
|
|
|
|
@Override
|
|
|
|
public void run(TLObject response, TLRPC.TL_error error) {
|
|
|
|
processRequestResult((TLRPC.TL_upload_file) response, error, req.offset, 0);
|
|
|
|
}
|
|
|
|
}, new RPCRequest.RPCProgressDelegate() {
|
|
|
|
@Override
|
|
|
|
public void progress(int length, int progress) {
|
|
|
|
if (state == 1) {
|
|
|
|
requestProgress = progress;
|
|
|
|
if (totalBytesCount == -1) {
|
|
|
|
delegate.didChangedLoadProgress(FileLoadOperation.this, Math.min(1.0f, (float) (progress) / (float) length));
|
|
|
|
} else if (totalBytesCount > 0) {
|
|
|
|
processRequestProgress();
|
2014-06-20 02:18:13 +02:00
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
}
|
2014-06-20 21:34:16 +02:00
|
|
|
}, null, true, RPCRequest.RPCRequestClassDownloadMedia, datacenter_id);
|
|
|
|
}
|
|
|
|
if (totalBytesCount > 0 && requestToken2 == 0) {
|
|
|
|
requestProgress2 = 0;
|
|
|
|
if (totalBytesCount > 0 && nextDownloadOffset >= totalBytesCount) {
|
|
|
|
return;
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
2014-06-20 21:34:16 +02:00
|
|
|
final long time = System.currentTimeMillis();
|
|
|
|
final TLRPC.TL_upload_getFile req = new TLRPC.TL_upload_getFile();
|
|
|
|
req.location = location;
|
|
|
|
req.offset = nextDownloadOffset;
|
|
|
|
req.limit = downloadChunkSize;
|
|
|
|
nextDownloadOffset += downloadChunkSize;
|
|
|
|
requestToken2 = ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() {
|
|
|
|
@Override
|
|
|
|
public void run(TLObject response, TLRPC.TL_error error) {
|
|
|
|
processRequestResult((TLRPC.TL_upload_file) response, error, req.offset, 1);
|
2013-12-20 20:25:49 +01:00
|
|
|
}
|
2014-06-20 21:34:16 +02:00
|
|
|
}, new RPCRequest.RPCProgressDelegate() {
|
|
|
|
@Override
|
|
|
|
public void progress(int length, int progress) {
|
|
|
|
if (state == 1) {
|
|
|
|
requestProgress2 = progress;
|
|
|
|
processRequestProgress();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, null, true, RPCRequest.RPCRequestClassDownloadMedia | RPCRequest.RPCRequestClassDownloadMedia2, datacenter_id);
|
|
|
|
}
|
2013-10-25 17:19:00 +02:00
|
|
|
}
|
|
|
|
}
|