mirror of https://github.com/NekoX-Dev/NekoX.git
2034 lines
83 KiB
Java
2034 lines
83 KiB
Java
/*
|
|
* This is the source code of Telegram for Android v. 1.7.x.
|
|
* 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-2014.
|
|
*/
|
|
|
|
package org.telegram.android;
|
|
|
|
import android.app.ActivityManager;
|
|
import android.content.BroadcastReceiver;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.IntentFilter;
|
|
import android.graphics.Bitmap;
|
|
import android.graphics.BitmapFactory;
|
|
import android.graphics.Matrix;
|
|
import android.graphics.drawable.BitmapDrawable;
|
|
import android.media.ExifInterface;
|
|
import android.media.ThumbnailUtils;
|
|
import android.net.Uri;
|
|
import android.os.AsyncTask;
|
|
import android.os.Build;
|
|
import android.os.Environment;
|
|
import android.os.ParcelFileDescriptor;
|
|
import android.provider.MediaStore;
|
|
|
|
import org.telegram.messenger.DispatchQueue;
|
|
import org.telegram.messenger.FileLoader;
|
|
import org.telegram.messenger.FileLog;
|
|
import org.telegram.messenger.TLObject;
|
|
import org.telegram.messenger.TLRPC;
|
|
import org.telegram.messenger.UserConfig;
|
|
import org.telegram.messenger.Utilities;
|
|
import org.telegram.messenger.ApplicationLoader;
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.File;
|
|
import java.io.FileDescriptor;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.io.InputStream;
|
|
import java.io.RandomAccessFile;
|
|
import java.lang.reflect.Method;
|
|
import java.net.HttpURLConnection;
|
|
import java.net.URL;
|
|
import java.net.URLConnection;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.channels.FileChannel;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.LinkedList;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
public class ImageLoader {
|
|
|
|
private HashMap<String, Integer> bitmapUseCounts = new HashMap<>();
|
|
private LruCache memCache;
|
|
private HashMap<String, CacheImage> imageLoadingByUrl = new HashMap<>();
|
|
private HashMap<String, CacheImage> imageLoadingByKeys = new HashMap<>();
|
|
private HashMap<Integer, CacheImage> imageLoadingByTag = new HashMap<>();
|
|
private HashMap<String, ThumbGenerateInfo> waitingForQualityThumb = new HashMap<>();
|
|
private HashMap<Integer, String> waitingForQualityThumbByTag = new HashMap<>();
|
|
private LinkedList<HttpImageTask> httpTasks = new LinkedList<>();
|
|
private DispatchQueue cacheOutQueue = new DispatchQueue("cacheOutQueue");
|
|
private DispatchQueue cacheThumbOutQueue = new DispatchQueue("cacheThumbOutQueue");
|
|
private DispatchQueue thumbGeneratingQueue = new DispatchQueue("thumbGeneratingQueue");
|
|
private DispatchQueue imageLoadQueue = new DispatchQueue("imageLoadQueue");
|
|
private DispatchQueue recycleQueue = new DispatchQueue("recycleQueue");
|
|
private ConcurrentHashMap<String, Float> fileProgresses = new ConcurrentHashMap<>();
|
|
private HashMap<String, ThumbGenerateTask> thumbGenerateTasks = new HashMap<>();
|
|
private int currentHttpTasksCount = 0;
|
|
|
|
private LinkedList<HttpFileTask> httpFileLoadTasks = new LinkedList<>();
|
|
private HashMap<String, HttpFileTask> httpFileLoadTasksByKeys = new HashMap<>();
|
|
private HashMap<String, Runnable> retryHttpsTasks = new HashMap<>();
|
|
private int currentHttpFileLoadTasksCount = 0;
|
|
|
|
protected VMRuntimeHack runtimeHack = null;
|
|
private String ignoreRemoval = null;
|
|
|
|
private volatile long lastCacheOutTime = 0;
|
|
private int lastImageNum = 0;
|
|
private long lastProgressUpdateTime = 0;
|
|
|
|
private File telegramPath = null;
|
|
|
|
private class ThumbGenerateInfo {
|
|
private int count;
|
|
private TLRPC.FileLocation fileLocation;
|
|
private String filter;
|
|
}
|
|
|
|
private class HttpFileTask extends AsyncTask<Void, Void, Boolean> {
|
|
|
|
private String url;
|
|
private File tempFile;
|
|
private String ext;
|
|
private RandomAccessFile fileOutputStream = null;
|
|
private boolean canRetry = true;
|
|
|
|
public HttpFileTask(String url, File tempFile, String ext) {
|
|
this.url = url;
|
|
this.tempFile = tempFile;
|
|
this.ext = ext;
|
|
}
|
|
|
|
protected Boolean doInBackground(Void... voids) {
|
|
InputStream httpConnectionStream = null;
|
|
boolean done = false;
|
|
|
|
URLConnection httpConnection = null;
|
|
try {
|
|
URL downloadUrl = new URL(url);
|
|
httpConnection = downloadUrl.openConnection();
|
|
httpConnection.setConnectTimeout(5000);
|
|
httpConnection.setReadTimeout(5000);
|
|
httpConnection.connect();
|
|
httpConnectionStream = httpConnection.getInputStream();
|
|
|
|
fileOutputStream = new RandomAccessFile(tempFile, "rws");
|
|
} catch (Throwable e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
|
|
try {
|
|
if (httpConnection != null && httpConnection instanceof HttpURLConnection) {
|
|
int code = ((HttpURLConnection) httpConnection).getResponseCode();
|
|
if (code != HttpURLConnection.HTTP_OK && code != HttpURLConnection.HTTP_ACCEPTED && code != HttpURLConnection.HTTP_NOT_MODIFIED) {
|
|
canRetry = false;
|
|
}
|
|
}
|
|
} catch (Exception e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
|
|
try {
|
|
byte[] data = new byte[1024 * 4];
|
|
while (true) {
|
|
if (isCancelled()) {
|
|
break;
|
|
}
|
|
try {
|
|
int readed = httpConnectionStream.read(data);
|
|
if (readed > 0) {
|
|
fileOutputStream.write(data, 0, readed);
|
|
} else if (readed == -1) {
|
|
done = true;
|
|
break;
|
|
} else {
|
|
break;
|
|
}
|
|
} catch (Exception e) {
|
|
FileLog.e("tmessages", e);
|
|
break;
|
|
}
|
|
}
|
|
} catch (Throwable e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
|
|
try {
|
|
if (fileOutputStream != null) {
|
|
fileOutputStream.close();
|
|
fileOutputStream = null;
|
|
}
|
|
} catch (Throwable e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
|
|
try {
|
|
if (httpConnectionStream != null) {
|
|
httpConnectionStream.close();
|
|
}
|
|
httpConnectionStream = null;
|
|
} catch (Throwable e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
|
|
return done;
|
|
}
|
|
|
|
@Override
|
|
protected void onPostExecute(Boolean result) {
|
|
runHttpFileLoadTasks(this, result ? 2 : 1);
|
|
}
|
|
|
|
@Override
|
|
protected void onCancelled() {
|
|
runHttpFileLoadTasks(this, 2);
|
|
}
|
|
}
|
|
|
|
private class HttpImageTask extends AsyncTask<Void, Void, Boolean> {
|
|
|
|
private CacheImage cacheImage = null;
|
|
private RandomAccessFile fileOutputStream = null;
|
|
private int imageSize;
|
|
private long lastProgressTime;
|
|
private boolean canRetry = true;
|
|
private URLConnection httpConnection = null;
|
|
|
|
public HttpImageTask(CacheImage cacheImage, int size) {
|
|
this.cacheImage = cacheImage;
|
|
imageSize = size;
|
|
}
|
|
|
|
private void reportProgress(final float progress) {
|
|
long currentTime = System.currentTimeMillis();
|
|
if (progress == 1 || lastProgressTime == 0 || lastProgressTime < currentTime - 500) {
|
|
lastProgressTime = currentTime;
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
fileProgresses.put(cacheImage.url, progress);
|
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileLoadProgressChanged, cacheImage.url, progress);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
protected Boolean doInBackground(Void... voids) {
|
|
InputStream httpConnectionStream = null;
|
|
boolean done = false;
|
|
|
|
if (!isCancelled()) {
|
|
try {
|
|
URL downloadUrl = new URL(cacheImage.httpUrl);
|
|
httpConnection = downloadUrl.openConnection();
|
|
httpConnection.setConnectTimeout(5000);
|
|
httpConnection.setReadTimeout(5000);
|
|
if (!isCancelled()) {
|
|
httpConnection.connect();
|
|
httpConnectionStream = httpConnection.getInputStream();
|
|
|
|
fileOutputStream = new RandomAccessFile(cacheImage.tempFilePath, "rws");
|
|
}
|
|
} catch (Throwable e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
}
|
|
|
|
if (!isCancelled()) {
|
|
try {
|
|
if (httpConnection != null && httpConnection instanceof HttpURLConnection) {
|
|
int code = ((HttpURLConnection) httpConnection).getResponseCode();
|
|
if (code != HttpURLConnection.HTTP_OK && code != HttpURLConnection.HTTP_ACCEPTED && code != HttpURLConnection.HTTP_NOT_MODIFIED) {
|
|
canRetry = false;
|
|
}
|
|
}
|
|
} catch (Exception e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
|
|
try {
|
|
byte[] data = new byte[1024 * 2];
|
|
int totalLoaded = 0;
|
|
while (true) {
|
|
if (isCancelled()) {
|
|
break;
|
|
}
|
|
try {
|
|
int readed = httpConnectionStream.read(data);
|
|
if (readed > 0) {
|
|
totalLoaded += readed;
|
|
fileOutputStream.write(data, 0, readed);
|
|
if (imageSize != 0) {
|
|
reportProgress(totalLoaded / (float) imageSize);
|
|
}
|
|
} else if (readed == -1) {
|
|
done = true;
|
|
if (imageSize != 0) {
|
|
reportProgress(1.0f);
|
|
}
|
|
break;
|
|
} else {
|
|
break;
|
|
}
|
|
} catch (Exception e) {
|
|
FileLog.e("tmessages", e);
|
|
break;
|
|
}
|
|
}
|
|
} catch (Throwable e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
}
|
|
|
|
try {
|
|
if (fileOutputStream != null) {
|
|
fileOutputStream.close();
|
|
fileOutputStream = null;
|
|
}
|
|
} catch (Throwable e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
|
|
try {
|
|
if (httpConnectionStream != null) {
|
|
httpConnectionStream.close();
|
|
}
|
|
httpConnectionStream = null;
|
|
} catch (Throwable e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
|
|
if (done) {
|
|
if (cacheImage.tempFilePath != null) {
|
|
if (!cacheImage.tempFilePath.renameTo(cacheImage.finalFilePath)) {
|
|
cacheImage.finalFilePath = cacheImage.tempFilePath;
|
|
}
|
|
}
|
|
}
|
|
|
|
return done;
|
|
}
|
|
|
|
@Override
|
|
protected void onPostExecute(final Boolean result) {
|
|
if (result || !canRetry) {
|
|
fileDidLoaded(cacheImage.url, cacheImage.finalFilePath, FileLoader.MEDIA_DIR_IMAGE);
|
|
} else {
|
|
httpFileLoadError(cacheImage.url);
|
|
}
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
fileProgresses.remove(cacheImage.url);
|
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (result) {
|
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileDidLoaded, cacheImage.url);
|
|
} else {
|
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileDidFailedLoad, cacheImage.url, 2);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
imageLoadQueue.postRunnable(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
runHttpTasks(true);
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
protected void onCancelled() {
|
|
imageLoadQueue.postRunnable(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
runHttpTasks(true);
|
|
}
|
|
});
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
fileProgresses.remove(cacheImage.url);
|
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileDidFailedLoad, cacheImage.url, 1);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
private class ThumbGenerateTask implements Runnable {
|
|
|
|
private File originalPath;
|
|
private int mediaType;
|
|
private TLRPC.FileLocation thumbLocation;
|
|
private String filter;
|
|
|
|
public ThumbGenerateTask(int type, File path, TLRPC.FileLocation location, String f) {
|
|
mediaType = type;
|
|
originalPath = path;
|
|
thumbLocation = location;
|
|
filter = f;
|
|
}
|
|
|
|
private void removeTask() {
|
|
if (thumbLocation == null) {
|
|
return;
|
|
}
|
|
final String name = FileLoader.getAttachFileName(thumbLocation);
|
|
imageLoadQueue.postRunnable(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
thumbGenerateTasks.remove(name);
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
if (thumbLocation == null) {
|
|
removeTask();
|
|
return;
|
|
}
|
|
final String key = thumbLocation.volume_id + "_" + thumbLocation.local_id;
|
|
File thumbFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), "q_" + key + ".jpg");
|
|
if (thumbFile.exists() || !originalPath.exists()) {
|
|
removeTask();
|
|
return;
|
|
}
|
|
int size = Math.min(180, Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) / 4);
|
|
Bitmap originalBitmap = null;
|
|
if (mediaType == FileLoader.MEDIA_DIR_IMAGE) {
|
|
originalBitmap = ImageLoader.loadBitmap(originalPath.toString(), null, size, size, false);
|
|
} else if (mediaType == FileLoader.MEDIA_DIR_VIDEO) {
|
|
originalBitmap = ThumbnailUtils.createVideoThumbnail(originalPath.toString(), MediaStore.Video.Thumbnails.MINI_KIND);
|
|
} else if (mediaType == FileLoader.MEDIA_DIR_DOCUMENT) {
|
|
String path = originalPath.toString().toLowerCase();
|
|
if (!path.endsWith(".jpg") && !path.endsWith(".jpeg") && !path.endsWith(".png") && !path.endsWith(".gif")) {
|
|
removeTask();
|
|
return;
|
|
}
|
|
originalBitmap = ImageLoader.loadBitmap(path, null, size, size, false);
|
|
}
|
|
if (originalBitmap == null) {
|
|
removeTask();
|
|
return;
|
|
}
|
|
|
|
int w = originalBitmap.getWidth();
|
|
int h = originalBitmap.getHeight();
|
|
if (w == 0 || h == 0) {
|
|
removeTask();
|
|
return;
|
|
}
|
|
float scaleFactor = Math.min((float) w / size, (float) h / size);
|
|
Bitmap scaledBitmap = Bitmap.createScaledBitmap(originalBitmap, (int) (w / scaleFactor), (int) (h / scaleFactor), true);
|
|
if (scaledBitmap != originalBitmap) {
|
|
originalBitmap.recycle();
|
|
callGC();
|
|
}
|
|
originalBitmap = scaledBitmap;
|
|
FileOutputStream stream = new FileOutputStream(thumbFile);
|
|
originalBitmap.compress(Bitmap.CompressFormat.JPEG, 60, stream);
|
|
try {
|
|
stream.close();
|
|
} catch (Exception e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
final BitmapDrawable bitmapDrawable = new BitmapDrawable(originalBitmap);
|
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
removeTask();
|
|
|
|
String kf = key;
|
|
if (filter != null) {
|
|
kf += "@" + filter;
|
|
}
|
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageThumbGenerated, bitmapDrawable, kf);
|
|
/*BitmapDrawable old = memCache.get(kf);
|
|
if (old != null) {
|
|
Bitmap image = old.getBitmap();
|
|
if (runtimeHack != null) {
|
|
runtimeHack.trackAlloc(image.getRowBytes() * image.getHeight());
|
|
}
|
|
if (!image.isRecycled()) {
|
|
image.recycle();
|
|
}
|
|
}*/
|
|
memCache.put(kf, bitmapDrawable);
|
|
}
|
|
});
|
|
} catch (Throwable e) {
|
|
FileLog.e("tmessages", e);
|
|
removeTask();
|
|
}
|
|
}
|
|
}
|
|
|
|
private class CacheOutTask implements Runnable {
|
|
private Thread runningThread;
|
|
private final Object sync = new Object();
|
|
|
|
private CacheImage cacheImage;
|
|
private boolean isCancelled;
|
|
|
|
public CacheOutTask(CacheImage image) {
|
|
cacheImage = image;
|
|
}
|
|
|
|
@Override
|
|
public void run() {
|
|
synchronized (sync) {
|
|
runningThread = Thread.currentThread();
|
|
Thread.interrupted();
|
|
if (isCancelled) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
Long mediaId = null;
|
|
Bitmap image = null;
|
|
File cacheFileFinal = cacheImage.finalFilePath;
|
|
boolean canDeleteFile = true;
|
|
boolean isWebp = false;
|
|
|
|
if (cacheFileFinal.toString().endsWith("webp")) {
|
|
isWebp = true;
|
|
}
|
|
|
|
if (cacheImage.thumb) {
|
|
|
|
int blurType = 0;
|
|
if (cacheImage.filter != null) {
|
|
if (cacheImage.filter.contains("b2")) {
|
|
blurType = 3;
|
|
} else if (cacheImage.filter.contains("b1")) {
|
|
blurType = 2;
|
|
} else if (cacheImage.filter.contains("b")) {
|
|
blurType = 1;
|
|
}
|
|
}
|
|
|
|
try {
|
|
lastCacheOutTime = System.currentTimeMillis();
|
|
synchronized (sync) {
|
|
if (isCancelled) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (image == null) {
|
|
if (isWebp) {
|
|
RandomAccessFile file = new RandomAccessFile(cacheFileFinal, "r");
|
|
ByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, cacheFileFinal.length());
|
|
image = Utilities.loadWebpImage(buffer, buffer.limit(), null);
|
|
file.close();
|
|
} else {
|
|
FileInputStream is = new FileInputStream(cacheFileFinal);
|
|
image = BitmapFactory.decodeStream(is, null, null);
|
|
is.close();
|
|
}
|
|
}
|
|
if (image == null) {
|
|
if (canDeleteFile && (cacheFileFinal.length() == 0 || cacheImage.filter == null)) {
|
|
cacheFileFinal.delete();
|
|
}
|
|
} else {
|
|
if (image != null) {
|
|
if (blurType == 1) {
|
|
Utilities.blurBitmap(image, 3);
|
|
} else if (blurType == 2) {
|
|
Utilities.blurBitmap(image, 1);
|
|
} else if (blurType == 3) {
|
|
Utilities.blurBitmap(image, 7);
|
|
Utilities.blurBitmap(image, 7);
|
|
Utilities.blurBitmap(image, 7);
|
|
}
|
|
}
|
|
if (runtimeHack != null) {
|
|
runtimeHack.trackFree(image.getRowBytes() * image.getHeight());
|
|
}
|
|
}
|
|
} catch (Throwable e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
} else {
|
|
try {
|
|
if (cacheImage.httpUrl != null) {
|
|
if (cacheImage.httpUrl.startsWith("thumb://")) {
|
|
int idx = cacheImage.httpUrl.indexOf(":", 8);
|
|
if (idx >= 0) {
|
|
mediaId = Long.parseLong(cacheImage.httpUrl.substring(8, idx));
|
|
}
|
|
canDeleteFile = false;
|
|
} else if (!cacheImage.httpUrl.startsWith("http")) {
|
|
canDeleteFile = false;
|
|
}
|
|
}
|
|
|
|
int delay = 20;
|
|
if (runtimeHack != null) {
|
|
delay = 60;
|
|
}
|
|
if (mediaId != null) {
|
|
delay = 0;
|
|
}
|
|
if (delay != 0 && lastCacheOutTime != 0 && lastCacheOutTime > System.currentTimeMillis() - delay && Build.VERSION.SDK_INT < 21) {
|
|
Thread.sleep(delay);
|
|
}
|
|
lastCacheOutTime = System.currentTimeMillis();
|
|
synchronized (sync) {
|
|
if (isCancelled) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
BitmapFactory.Options opts = new BitmapFactory.Options();
|
|
|
|
float w_filter = 0;
|
|
float h_filter = 0;
|
|
boolean blur = false;
|
|
if (cacheImage.filter != null) {
|
|
String args[] = cacheImage.filter.split("_");
|
|
w_filter = Float.parseFloat(args[0]) * AndroidUtilities.density;
|
|
h_filter = Float.parseFloat(args[1]) * AndroidUtilities.density;
|
|
if (args.length > 2) {
|
|
blur = true;
|
|
}
|
|
opts.inJustDecodeBounds = true;
|
|
|
|
if (mediaId != null) {
|
|
MediaStore.Images.Thumbnails.getThumbnail(ApplicationLoader.applicationContext.getContentResolver(), mediaId, MediaStore.Images.Thumbnails.MINI_KIND, opts);
|
|
} else {
|
|
FileInputStream is = new FileInputStream(cacheFileFinal);
|
|
image = BitmapFactory.decodeStream(is, null, opts);
|
|
is.close();
|
|
}
|
|
|
|
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;
|
|
}
|
|
synchronized (sync) {
|
|
if (isCancelled) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (cacheImage.filter == null || blur || cacheImage.httpUrl != null) {
|
|
opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
|
|
} else {
|
|
opts.inPreferredConfig = Bitmap.Config.RGB_565;
|
|
}
|
|
opts.inDither = false;
|
|
if (mediaId != null) {
|
|
image = MediaStore.Images.Thumbnails.getThumbnail(ApplicationLoader.applicationContext.getContentResolver(), mediaId, MediaStore.Images.Thumbnails.MINI_KIND, null);
|
|
}
|
|
if (image == null) {
|
|
if (isWebp) {
|
|
RandomAccessFile file = new RandomAccessFile(cacheFileFinal, "r");
|
|
ByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, cacheFileFinal.length());
|
|
image = Utilities.loadWebpImage(buffer, buffer.limit(), null);
|
|
file.close();
|
|
} else {
|
|
FileInputStream is = new FileInputStream(cacheFileFinal);
|
|
image = BitmapFactory.decodeStream(is, null, opts);
|
|
is.close();
|
|
}
|
|
}
|
|
if (image == null) {
|
|
if (canDeleteFile && (cacheFileFinal.length() == 0 || cacheImage.filter == null)) {
|
|
cacheFileFinal.delete();
|
|
}
|
|
} else {
|
|
if (cacheImage.filter != null) {
|
|
float bitmapW = image.getWidth();
|
|
float bitmapH = image.getHeight();
|
|
if (bitmapW != w_filter && bitmapW > w_filter) {
|
|
float scaleFactor = bitmapW / w_filter;
|
|
Bitmap scaledBitmap = Bitmap.createScaledBitmap(image, (int)w_filter, (int)(bitmapH / scaleFactor), true);
|
|
if (image != scaledBitmap) {
|
|
image.recycle();
|
|
callGC();
|
|
image = scaledBitmap;
|
|
}
|
|
}
|
|
if (image != null && blur && bitmapH < 100 && bitmapW < 100) {
|
|
Utilities.blurBitmap(image, 3);
|
|
}
|
|
}
|
|
if (runtimeHack != null) {
|
|
runtimeHack.trackFree(image.getRowBytes() * image.getHeight());
|
|
}
|
|
}
|
|
} catch (Throwable e) {
|
|
//don't promt
|
|
}
|
|
}
|
|
Thread.interrupted();
|
|
onPostExecute(image != null ? new BitmapDrawable(image) : null);
|
|
}
|
|
|
|
private void onPostExecute(final BitmapDrawable bitmapDrawable) {
|
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
BitmapDrawable toSet = null;
|
|
if (bitmapDrawable != null) {
|
|
toSet = memCache.get(cacheImage.key);
|
|
if (toSet == null) {
|
|
memCache.put(cacheImage.key, bitmapDrawable);
|
|
toSet = bitmapDrawable;
|
|
} else {
|
|
Bitmap image = bitmapDrawable.getBitmap();
|
|
if (runtimeHack != null) {
|
|
runtimeHack.trackAlloc(image.getRowBytes() * image.getHeight());
|
|
}
|
|
image.recycle();
|
|
callGC();
|
|
}
|
|
}
|
|
final BitmapDrawable toSetFinal = toSet;
|
|
imageLoadQueue.postRunnable(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
cacheImage.setImageAndClear(toSetFinal);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
public void cancel() {
|
|
synchronized (sync) {
|
|
try {
|
|
isCancelled = true;
|
|
if (runningThread != null) {
|
|
runningThread.interrupt();
|
|
}
|
|
} catch (Exception e) {
|
|
//don't promt
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public class VMRuntimeHack {
|
|
private Object runtime = null;
|
|
private Method trackAllocation = null;
|
|
private Method trackFree = null;
|
|
|
|
public boolean trackAlloc(long size) {
|
|
if (runtime == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
Object res = trackAllocation.invoke(runtime, size);
|
|
return (res instanceof Boolean) ? (Boolean)res : true;
|
|
} catch (Exception e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public boolean trackFree(long size) {
|
|
if (runtime == null) {
|
|
return false;
|
|
}
|
|
try {
|
|
Object res = trackFree.invoke(runtime, size);
|
|
return (res instanceof Boolean) ? (Boolean)res : true;
|
|
} catch (Exception e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public VMRuntimeHack() {
|
|
try {
|
|
Class cl = Class.forName("dalvik.system.VMRuntime");
|
|
Method getRt = cl.getMethod("getRuntime", new Class[0]);
|
|
Object[] objects = new Object[0];
|
|
runtime = getRt.invoke(null, objects);
|
|
trackAllocation = cl.getMethod("trackExternalAllocation", new Class[] {long.class});
|
|
trackFree = cl.getMethod("trackExternalFree", new Class[] {long.class});
|
|
} catch (Exception e) {
|
|
FileLog.e("tmessages", e);
|
|
runtime = null;
|
|
trackAllocation = null;
|
|
trackFree = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
private class CacheImage {
|
|
protected String key;
|
|
protected String url;
|
|
protected String filter;
|
|
protected TLObject location;
|
|
|
|
protected File finalFilePath;
|
|
protected File tempFilePath;
|
|
protected boolean thumb;
|
|
|
|
protected String httpUrl;
|
|
protected HttpImageTask httpTask;
|
|
protected CacheOutTask cacheTask;
|
|
|
|
protected ArrayList<ImageReceiver> imageReceiverArray = new ArrayList<>();
|
|
|
|
public void addImageReceiver(ImageReceiver imageReceiver) {
|
|
boolean exist = false;
|
|
for (ImageReceiver v : imageReceiverArray) {
|
|
if (v == imageReceiver) {
|
|
exist = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!exist) {
|
|
imageReceiverArray.add(imageReceiver);
|
|
imageLoadingByTag.put(imageReceiver.getTag(thumb), this);
|
|
}
|
|
}
|
|
|
|
public void removeImageReceiver(ImageReceiver imageReceiver) {
|
|
for (int a = 0; a < imageReceiverArray.size(); a++) {
|
|
ImageReceiver obj = imageReceiverArray.get(a);
|
|
if (obj == null || obj == imageReceiver) {
|
|
imageReceiverArray.remove(a);
|
|
if (obj != null) {
|
|
imageLoadingByTag.remove(obj.getTag(thumb));
|
|
}
|
|
a--;
|
|
}
|
|
}
|
|
if (imageReceiverArray.size() == 0) {
|
|
for (ImageReceiver receiver : imageReceiverArray) {
|
|
imageLoadingByTag.remove(receiver.getTag(thumb));
|
|
}
|
|
imageReceiverArray.clear();
|
|
if (location != null) {
|
|
if (location instanceof TLRPC.FileLocation) {
|
|
FileLoader.getInstance().cancelLoadFile((TLRPC.FileLocation) location);
|
|
} else if (location instanceof TLRPC.Document) {
|
|
FileLoader.getInstance().cancelLoadFile((TLRPC.Document) location);
|
|
}
|
|
}
|
|
if (cacheTask != null) {
|
|
if (thumb) {
|
|
cacheThumbOutQueue.cancelRunnable(cacheTask);
|
|
} else {
|
|
cacheOutQueue.cancelRunnable(cacheTask);
|
|
}
|
|
cacheTask.cancel();
|
|
cacheTask = null;
|
|
}
|
|
if (httpTask != null) {
|
|
httpTasks.remove(httpTask);
|
|
httpTask.cancel(true);
|
|
httpTask = null;
|
|
}
|
|
if (url != null) {
|
|
imageLoadingByUrl.remove(url);
|
|
}
|
|
if (key != null) {
|
|
imageLoadingByKeys.remove(key);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void setImageAndClear(final BitmapDrawable image) {
|
|
if (image != null) {
|
|
final ArrayList<ImageReceiver> finalImageReceiverArray = new ArrayList<>(imageReceiverArray);
|
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
for (ImageReceiver imgView : finalImageReceiverArray) {
|
|
imgView.setImageBitmapByKey(image, key, thumb);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
for (ImageReceiver imageReceiver : imageReceiverArray) {
|
|
imageLoadingByTag.remove(imageReceiver.getTag(thumb));
|
|
}
|
|
imageReceiverArray.clear();
|
|
if (url != null) {
|
|
imageLoadingByUrl.remove(url);
|
|
}
|
|
if (key != null) {
|
|
imageLoadingByKeys.remove(key);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static volatile ImageLoader Instance = null;
|
|
public static ImageLoader getInstance() {
|
|
ImageLoader localInstance = Instance;
|
|
if (localInstance == null) {
|
|
synchronized (ImageLoader.class) {
|
|
localInstance = Instance;
|
|
if (localInstance == null) {
|
|
Instance = localInstance = new ImageLoader();
|
|
}
|
|
}
|
|
}
|
|
return localInstance;
|
|
}
|
|
|
|
public ImageLoader() {
|
|
int cacheSize = Math.min(15, ((ActivityManager) ApplicationLoader.applicationContext.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass() / 7) * 1024 * 1024;
|
|
|
|
if (Build.VERSION.SDK_INT < 11) {
|
|
runtimeHack = new VMRuntimeHack();
|
|
cacheSize = 1024 * 1024 * 3;
|
|
}
|
|
memCache = new LruCache(cacheSize) {
|
|
@Override
|
|
protected int sizeOf(String key, BitmapDrawable bitmap) {
|
|
Bitmap b = bitmap.getBitmap();
|
|
if(Build.VERSION.SDK_INT < 12) {
|
|
return b.getRowBytes() * b.getHeight();
|
|
} else {
|
|
return b.getByteCount();
|
|
}
|
|
}
|
|
@Override
|
|
protected void entryRemoved(boolean evicted, String key, final BitmapDrawable oldBitmap, BitmapDrawable newBitmap) {
|
|
if (ignoreRemoval != null && key != null && ignoreRemoval.equals(key)) {
|
|
return;
|
|
}
|
|
final Integer count = bitmapUseCounts.get(key);
|
|
if (count == null || count == 0) {
|
|
Bitmap b = oldBitmap.getBitmap();
|
|
if (runtimeHack != null) {
|
|
runtimeHack.trackAlloc(b.getRowBytes() * b.getHeight());
|
|
}
|
|
if (!b.isRecycled()) {
|
|
b.recycle();
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
FileLoader.getInstance().setDelegate(new FileLoader.FileLoaderDelegate() {
|
|
@Override
|
|
public void fileUploadProgressChanged(final String location, final float progress, final boolean isEncrypted) {
|
|
fileProgresses.put(location, progress);
|
|
long currentTime = System.currentTimeMillis();
|
|
if (lastProgressUpdateTime == 0 || lastProgressUpdateTime < currentTime - 500) {
|
|
lastProgressUpdateTime = currentTime;
|
|
|
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileUploadProgressChanged, location, progress, isEncrypted);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void fileDidUploaded(final String location, final TLRPC.InputFile inputFile, final TLRPC.InputEncryptedFile inputEncryptedFile) {
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileDidUpload, location, inputFile, inputEncryptedFile);
|
|
fileProgresses.remove(location);
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void fileDidFailedUpload(final String location, final boolean isEncrypted) {
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileDidFailUpload, location, isEncrypted);
|
|
fileProgresses.remove(location);
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void fileDidLoaded(final String location, final File finalFile, final int type) {
|
|
fileProgresses.remove(location);
|
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (location != null) {
|
|
if (MediaController.getInstance().canSaveToGallery() && telegramPath != null && finalFile != null && finalFile.exists() && (location.endsWith(".mp4") || location.endsWith(".jpg"))) {
|
|
if (finalFile.toString().startsWith(telegramPath.toString())) {
|
|
Utilities.addMediaToGallery(finalFile.toString());
|
|
}
|
|
}
|
|
}
|
|
ImageLoader.this.fileDidLoaded(location, finalFile, type);
|
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileDidLoaded, location);
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void fileDidFailedLoad(final String location, final int canceled) {
|
|
fileProgresses.remove(location);
|
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
ImageLoader.this.fileDidFailedLoad(location, canceled);
|
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileDidFailedLoad, location, canceled);
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public void fileLoadProgressChanged(final String location, final float progress) {
|
|
fileProgresses.put(location, progress);
|
|
long currentTime = System.currentTimeMillis();
|
|
if (lastProgressUpdateTime == 0 || lastProgressUpdateTime < currentTime - 500) {
|
|
lastProgressUpdateTime = currentTime;
|
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileLoadProgressChanged, location, progress);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
BroadcastReceiver receiver = new BroadcastReceiver() {
|
|
@Override
|
|
public void onReceive(Context arg0, Intent intent) {
|
|
FileLog.e("tmessages", "file system changed");
|
|
Runnable r = new Runnable() {
|
|
public void run() {
|
|
FileLoader.getInstance().setMediaDirs(createMediaPaths());
|
|
}
|
|
};
|
|
if (Intent.ACTION_MEDIA_UNMOUNTED.equals(intent.getAction())) {
|
|
AndroidUtilities.runOnUIThread(r, 1000);
|
|
} else {
|
|
r.run();
|
|
}
|
|
}
|
|
};
|
|
|
|
IntentFilter filter = new IntentFilter();
|
|
filter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL);
|
|
filter.addAction(Intent.ACTION_MEDIA_CHECKING);
|
|
filter.addAction(Intent.ACTION_MEDIA_EJECT);
|
|
filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
|
|
filter.addAction(Intent.ACTION_MEDIA_NOFS);
|
|
filter.addAction(Intent.ACTION_MEDIA_REMOVED);
|
|
filter.addAction(Intent.ACTION_MEDIA_SHARED);
|
|
filter.addAction(Intent.ACTION_MEDIA_UNMOUNTABLE);
|
|
filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
|
|
filter.addDataScheme("file");
|
|
ApplicationLoader.applicationContext.registerReceiver(receiver, filter);
|
|
|
|
FileLoader.getInstance().setMediaDirs(createMediaPaths());
|
|
}
|
|
|
|
private HashMap<Integer, File> createMediaPaths() {
|
|
HashMap<Integer, File> mediaDirs = new HashMap<>();
|
|
File cachePath = AndroidUtilities.getCacheDir();
|
|
if (!cachePath.isDirectory()) {
|
|
try {
|
|
cachePath.mkdirs();
|
|
} catch (Exception e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
}
|
|
try {
|
|
new File(cachePath, ".nomedia").createNewFile();
|
|
} catch (Exception e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
|
|
mediaDirs.put(FileLoader.MEDIA_DIR_CACHE, cachePath);
|
|
FileLog.e("tmessages", "cache path = " + cachePath);
|
|
|
|
try {
|
|
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
|
|
telegramPath = new File(Environment.getExternalStorageDirectory(), "Telegram");
|
|
telegramPath.mkdirs();
|
|
|
|
boolean canRename = false;
|
|
|
|
try {
|
|
for (int a = 0; a < 5; a++) {
|
|
File srcFile = new File(cachePath, "temp.file");
|
|
srcFile.createNewFile();
|
|
File dstFile = new File(telegramPath, "temp.file");
|
|
canRename = srcFile.renameTo(dstFile);
|
|
srcFile.delete();
|
|
dstFile.delete();
|
|
if (canRename) {
|
|
break;
|
|
}
|
|
}
|
|
} catch (Exception e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
|
|
if (canRename) {
|
|
if (telegramPath.isDirectory()) {
|
|
try {
|
|
File imagePath = new File(telegramPath, "Telegram Images");
|
|
imagePath.mkdir();
|
|
if (imagePath.isDirectory()) {
|
|
mediaDirs.put(FileLoader.MEDIA_DIR_IMAGE, imagePath);
|
|
FileLog.e("tmessages", "image path = " + imagePath);
|
|
}
|
|
} catch (Exception e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
|
|
try {
|
|
File videoPath = new File(telegramPath, "Telegram Video");
|
|
videoPath.mkdir();
|
|
if (videoPath.isDirectory()) {
|
|
mediaDirs.put(FileLoader.MEDIA_DIR_VIDEO, videoPath);
|
|
FileLog.e("tmessages", "video path = " + videoPath);
|
|
}
|
|
} catch (Exception e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
|
|
try {
|
|
File audioPath = new File(telegramPath, "Telegram Audio");
|
|
audioPath.mkdir();
|
|
if (audioPath.isDirectory()) {
|
|
new File(audioPath, ".nomedia").createNewFile();
|
|
mediaDirs.put(FileLoader.MEDIA_DIR_AUDIO, audioPath);
|
|
FileLog.e("tmessages", "audio path = " + audioPath);
|
|
}
|
|
} catch (Exception e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
|
|
try {
|
|
File documentPath = new File(telegramPath, "Telegram Documents");
|
|
documentPath.mkdir();
|
|
if (documentPath.isDirectory()) {
|
|
new File(documentPath, ".nomedia").createNewFile();
|
|
mediaDirs.put(FileLoader.MEDIA_DIR_DOCUMENT, documentPath);
|
|
FileLog.e("tmessages", "documents path = " + documentPath);
|
|
}
|
|
} catch (Exception e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
}
|
|
} else {
|
|
FileLog.e("tmessages", "this Android can't rename files");
|
|
}
|
|
}
|
|
MediaController.getInstance().checkSaveToGalleryFiles();
|
|
} catch (Exception e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
|
|
return mediaDirs;
|
|
}
|
|
|
|
public Float getFileProgress(String location) {
|
|
return fileProgresses.get(location);
|
|
}
|
|
|
|
private void performReplace(String oldKey, String newKey) {
|
|
BitmapDrawable b = memCache.get(oldKey);
|
|
if (b != null) {
|
|
ignoreRemoval = oldKey;
|
|
memCache.remove(oldKey);
|
|
memCache.put(newKey, b);
|
|
ignoreRemoval = null;
|
|
}
|
|
Integer val = bitmapUseCounts.get(oldKey);
|
|
if (val != null) {
|
|
bitmapUseCounts.put(newKey, val);
|
|
bitmapUseCounts.remove(oldKey);
|
|
}
|
|
}
|
|
|
|
public void incrementUseCount(String key) {
|
|
Integer count = bitmapUseCounts.get(key);
|
|
if (count == null) {
|
|
bitmapUseCounts.put(key, 1);
|
|
} else {
|
|
bitmapUseCounts.put(key, count + 1);
|
|
}
|
|
}
|
|
|
|
public void callGC() {
|
|
if (Build.VERSION.SDK_INT > 13) {
|
|
recycleQueue.postRunnable(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
System.gc();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
public boolean decrementUseCount(String key) {
|
|
Integer count = bitmapUseCounts.get(key);
|
|
if (count == null) {
|
|
return true;
|
|
}
|
|
if (count == 1) {
|
|
bitmapUseCounts.remove(key);
|
|
return true;
|
|
} else {
|
|
bitmapUseCounts.put(key, count - 1);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void removeImage(String key) {
|
|
bitmapUseCounts.remove(key);
|
|
memCache.remove(key);
|
|
}
|
|
|
|
public boolean isInCache(String key) {
|
|
return memCache.get(key) != null;
|
|
}
|
|
|
|
public void clearMemory() {
|
|
memCache.evictAll();
|
|
}
|
|
|
|
private void removeFromWaitingForThumb(Integer TAG) {
|
|
String location = waitingForQualityThumbByTag.get(TAG);
|
|
if (location != null) {
|
|
ThumbGenerateInfo info = waitingForQualityThumb.get(location);
|
|
if (info != null) {
|
|
info.count--;
|
|
if (info.count == 0) {
|
|
waitingForQualityThumb.remove(location);
|
|
}
|
|
}
|
|
waitingForQualityThumbByTag.remove(TAG);
|
|
}
|
|
}
|
|
|
|
public void cancelLoadingForImageReceiver(final ImageReceiver imageReceiver, final int type) {
|
|
if (imageReceiver == null) {
|
|
return;
|
|
}
|
|
imageLoadQueue.postRunnable(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
int start = 0;
|
|
int count = 2;
|
|
if (type == 1) {
|
|
count = 1;
|
|
} else if (type == 2) {
|
|
start = 1;
|
|
}
|
|
for (int a = start; a < count; a++) {
|
|
Integer TAG = imageReceiver.getTag(a == 0);
|
|
if (a == 0) {
|
|
removeFromWaitingForThumb(TAG);
|
|
}
|
|
if (TAG != null) {
|
|
CacheImage ei = imageLoadingByTag.get(TAG);
|
|
if (ei != null) {
|
|
ei.removeImageReceiver(imageReceiver);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public BitmapDrawable getImageFromMemory(String key) {
|
|
return memCache.get(key);
|
|
}
|
|
|
|
public BitmapDrawable getImageFromMemory(TLObject fileLocation, String httpUrl, String filter) {
|
|
if (fileLocation == null && httpUrl == null) {
|
|
return null;
|
|
}
|
|
String key = null;
|
|
if (httpUrl != null) {
|
|
key = Utilities.MD5(httpUrl);
|
|
} else {
|
|
if (fileLocation instanceof TLRPC.FileLocation) {
|
|
TLRPC.FileLocation location = (TLRPC.FileLocation) fileLocation;
|
|
key = location.volume_id + "_" + location.local_id;
|
|
} else if (fileLocation instanceof TLRPC.Document) {
|
|
TLRPC.Document location = (TLRPC.Document) fileLocation;
|
|
key = location.dc_id + "_" + location.id;
|
|
}
|
|
}
|
|
if (filter != null) {
|
|
key += "@" + filter;
|
|
}
|
|
return memCache.get(key);
|
|
}
|
|
|
|
public void replaceImageInCache(final String oldKey, final String newKey) {
|
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
ArrayList<String> arr = memCache.getFilterKeys(oldKey);
|
|
if (arr != null) {
|
|
for (String filter : arr) {
|
|
performReplace(oldKey + "@" + filter, newKey + "@" + filter);
|
|
}
|
|
} else {
|
|
performReplace(oldKey, newKey);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public void putImageToCache(BitmapDrawable bitmap, String key) {
|
|
memCache.put(key, bitmap);
|
|
}
|
|
|
|
private void generateThumb(int mediaType, File originalPath, TLRPC.FileLocation thumbLocation, String filter) {
|
|
if (mediaType != FileLoader.MEDIA_DIR_IMAGE && mediaType != FileLoader.MEDIA_DIR_VIDEO && mediaType != FileLoader.MEDIA_DIR_DOCUMENT || originalPath == null || thumbLocation == null) {
|
|
return;
|
|
}
|
|
String name = FileLoader.getAttachFileName(thumbLocation);
|
|
ThumbGenerateTask task = thumbGenerateTasks.get(name);
|
|
if (task == null) {
|
|
task = new ThumbGenerateTask(mediaType, originalPath, thumbLocation, filter);
|
|
thumbGeneratingQueue.postRunnable(task);
|
|
}
|
|
}
|
|
|
|
private void createLoadOperationForImageReceiver(final ImageReceiver imageReceiver, final String key, final String url, final TLObject imageLocation, final String httpLocation, final String filter, final int size, final boolean cacheOnly, final int thumb) {
|
|
if (imageReceiver == null || url == null || key == null) {
|
|
return;
|
|
}
|
|
Integer TAG = imageReceiver.getTag(thumb != 0);
|
|
if (TAG == null) {
|
|
imageReceiver.setTag(TAG = lastImageNum, thumb != 0);
|
|
lastImageNum++;
|
|
if (lastImageNum == Integer.MAX_VALUE) {
|
|
lastImageNum = 0;
|
|
}
|
|
}
|
|
|
|
final Integer finalTag = TAG;
|
|
final boolean finalIsNeedsQualityThumb = imageReceiver.isNeedsQualityThumb();
|
|
final MessageObject parentMessageObject = imageReceiver.getParentMessageObject();
|
|
final boolean shouldGenerateQualityThumb = imageReceiver.isShouldGenerateQualityThumb();
|
|
imageLoadQueue.postRunnable(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
boolean added = false;
|
|
if (thumb != 2) {
|
|
CacheImage alreadyLoadingUrl = imageLoadingByUrl.get(url);
|
|
CacheImage alreadyLoadingCache = imageLoadingByKeys.get(key);
|
|
CacheImage alreadyLoadingImage = imageLoadingByTag.get(finalTag);
|
|
if (alreadyLoadingImage != null) {
|
|
if (alreadyLoadingImage == alreadyLoadingUrl || alreadyLoadingImage == alreadyLoadingCache) {
|
|
added = true;
|
|
} else {
|
|
alreadyLoadingImage.removeImageReceiver(imageReceiver);
|
|
}
|
|
}
|
|
|
|
if (!added && alreadyLoadingCache != null) {
|
|
alreadyLoadingCache.addImageReceiver(imageReceiver);
|
|
added = true;
|
|
}
|
|
if (!added && alreadyLoadingUrl != null) {
|
|
alreadyLoadingUrl.addImageReceiver(imageReceiver);
|
|
added = true;
|
|
}
|
|
}
|
|
|
|
if (!added) {
|
|
boolean onlyCache = false;
|
|
boolean isQuality = false;
|
|
File cacheFile = null;
|
|
|
|
if (httpLocation != null) {
|
|
if (!httpLocation.startsWith("http")) {
|
|
onlyCache = true;
|
|
if (httpLocation.startsWith("thumb://")) {
|
|
int idx = httpLocation.indexOf(":", 8);
|
|
if (idx >= 0) {
|
|
cacheFile = new File(httpLocation.substring(idx + 1));
|
|
}
|
|
} else {
|
|
cacheFile = new File(httpLocation);
|
|
}
|
|
}
|
|
} else if (thumb != 0) {
|
|
if (finalIsNeedsQualityThumb) {
|
|
cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), "q_" + url);
|
|
if (!cacheFile.exists()) {
|
|
cacheFile = null;
|
|
}
|
|
}
|
|
|
|
if (parentMessageObject != null) {
|
|
File attachPath = null;
|
|
if (parentMessageObject.messageOwner.attachPath != null && parentMessageObject.messageOwner.attachPath.length() > 0) {
|
|
attachPath = new File(parentMessageObject.messageOwner.attachPath);
|
|
if (!attachPath.exists()) {
|
|
attachPath = null;
|
|
}
|
|
}
|
|
if (attachPath == null) {
|
|
attachPath = FileLoader.getPathToMessage(parentMessageObject.messageOwner);
|
|
}
|
|
if (finalIsNeedsQualityThumb && cacheFile == null) {
|
|
String location = parentMessageObject.getFileName();
|
|
ThumbGenerateInfo info = waitingForQualityThumb.get(location);
|
|
if (info == null) {
|
|
info = new ThumbGenerateInfo();
|
|
info.fileLocation = (TLRPC.TL_fileLocation) imageLocation;
|
|
info.filter = filter;
|
|
waitingForQualityThumb.put(location, info);
|
|
}
|
|
info.count++;
|
|
waitingForQualityThumbByTag.put(finalTag, location);
|
|
}
|
|
if (attachPath.exists() && shouldGenerateQualityThumb) {
|
|
generateThumb(parentMessageObject.getFileType(), attachPath, (TLRPC.TL_fileLocation) imageLocation, filter);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (thumb != 2) {
|
|
if (cacheFile == null) {
|
|
if (cacheOnly || size == 0 || httpLocation != null) {
|
|
cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), url);
|
|
} else {
|
|
cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_IMAGE), url);
|
|
}
|
|
}
|
|
|
|
CacheImage img = new CacheImage();
|
|
img.thumb = thumb != 0;
|
|
img.key = key;
|
|
img.filter = filter;
|
|
img.httpUrl = httpLocation;
|
|
img.addImageReceiver(imageReceiver);
|
|
if (onlyCache || cacheFile.exists()) {
|
|
img.finalFilePath = cacheFile;
|
|
img.cacheTask = new CacheOutTask(img);
|
|
imageLoadingByKeys.put(key, img);
|
|
if (thumb != 0) {
|
|
cacheThumbOutQueue.postRunnable(img.cacheTask);
|
|
} else {
|
|
cacheOutQueue.postRunnable(img.cacheTask);
|
|
}
|
|
} else {
|
|
img.url = url;
|
|
img.location = imageLocation;
|
|
imageLoadingByUrl.put(url, img);
|
|
if (httpLocation == null) {
|
|
if (imageLocation instanceof TLRPC.FileLocation) {
|
|
TLRPC.FileLocation location = (TLRPC.FileLocation) imageLocation;
|
|
FileLoader.getInstance().loadFile(location, size, size == 0 || location.key != null || cacheOnly);
|
|
} else if (imageLocation instanceof TLRPC.Document) {
|
|
FileLoader.getInstance().loadFile((TLRPC.Document) imageLocation, true, true);
|
|
}
|
|
} else {
|
|
String file = Utilities.MD5(httpLocation);
|
|
File cacheDir = FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE);
|
|
img.tempFilePath = new File(cacheDir, file + "_temp.jpg");
|
|
img.finalFilePath = cacheFile;
|
|
img.httpTask = new HttpImageTask(img, size);
|
|
httpTasks.add(img.httpTask);
|
|
runHttpTasks(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public void loadImageForImageReceiver(ImageReceiver imageReceiver) {
|
|
if (imageReceiver == null) {
|
|
return;
|
|
}
|
|
|
|
String key = imageReceiver.getKey();
|
|
if (key != null) {
|
|
BitmapDrawable bitmapDrawable = memCache.get(key);
|
|
if (bitmapDrawable != null) {
|
|
cancelLoadingForImageReceiver(imageReceiver, 0);
|
|
if (!imageReceiver.isForcePreview()) {
|
|
imageReceiver.setImageBitmapByKey(bitmapDrawable, key, false);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
boolean thumbSet = false;
|
|
String thumbKey = imageReceiver.getThumbKey();
|
|
if (thumbKey != null) {
|
|
BitmapDrawable bitmapDrawable = memCache.get(thumbKey);
|
|
if (bitmapDrawable != null) {
|
|
imageReceiver.setImageBitmapByKey(bitmapDrawable, thumbKey, true);
|
|
cancelLoadingForImageReceiver(imageReceiver, 1);
|
|
thumbSet = true;
|
|
}
|
|
}
|
|
|
|
TLRPC.FileLocation thumbLocation = imageReceiver.getThumbLocation();
|
|
TLObject imageLocation = imageReceiver.getImageLocation();
|
|
String httpLocation = imageReceiver.getHttpImageLocation();
|
|
|
|
boolean saveImageToCache = false;
|
|
|
|
String url = null;
|
|
String thumbUrl = null;
|
|
key = null;
|
|
thumbKey = null;
|
|
String ext = null;
|
|
if (httpLocation != null) {
|
|
key = Utilities.MD5(httpLocation);
|
|
url = key + "." + getHttpUrlExtension(httpLocation);
|
|
} else if (imageLocation != null) {
|
|
if (imageLocation instanceof TLRPC.FileLocation) {
|
|
TLRPC.FileLocation location = (TLRPC.FileLocation) imageLocation;
|
|
key = location.volume_id + "_" + location.local_id;
|
|
ext = "." + (location.ext != null ? location.ext : "jpg");
|
|
url = key + ext;
|
|
if (location.ext != null || location.key != null || location.volume_id == Integer.MIN_VALUE && location.local_id < 0) {
|
|
saveImageToCache = true;
|
|
}
|
|
} else if (imageLocation instanceof TLRPC.Document) {
|
|
TLRPC.Document location = (TLRPC.Document) imageLocation;
|
|
if (location.id == 0 || location.dc_id == 0) {
|
|
return;
|
|
}
|
|
key = location.dc_id + "_" + location.id;
|
|
ext = ".webp";
|
|
url = key + ext;
|
|
if (thumbKey != null) {
|
|
thumbUrl = thumbKey + ext;
|
|
}
|
|
saveImageToCache = true;
|
|
}
|
|
if (imageLocation == thumbLocation) {
|
|
imageLocation = null;
|
|
key = null;
|
|
url = null;
|
|
}
|
|
}
|
|
|
|
if (thumbLocation != null) {
|
|
thumbKey = thumbLocation.volume_id + "_" + thumbLocation.local_id;
|
|
if (ext != null) {
|
|
thumbUrl = thumbKey + ext;
|
|
} else {
|
|
thumbUrl = thumbKey + "." + (thumbLocation.ext != null ? thumbLocation.ext : "jpg");
|
|
}
|
|
}
|
|
|
|
String filter = imageReceiver.getFilter();
|
|
String thumbFilter = imageReceiver.getThumbFilter();
|
|
if (key != null && filter != null) {
|
|
key += "@" + filter;
|
|
}
|
|
if (thumbKey != null && thumbFilter != null) {
|
|
thumbKey += "@" + thumbFilter;
|
|
}
|
|
|
|
if (httpLocation != null) {
|
|
createLoadOperationForImageReceiver(imageReceiver, key, url, null, httpLocation, filter, 0, true, 0);
|
|
} else {
|
|
createLoadOperationForImageReceiver(imageReceiver, thumbKey, thumbUrl, thumbLocation, null, thumbFilter, 0, true, thumbSet ? 2 : 1);
|
|
createLoadOperationForImageReceiver(imageReceiver, key, url, imageLocation, null, filter, imageReceiver.getSize(), saveImageToCache || imageReceiver.getCacheOnly(), 0);
|
|
}
|
|
}
|
|
|
|
private void httpFileLoadError(final String location) {
|
|
imageLoadQueue.postRunnable(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
CacheImage img = imageLoadingByUrl.get(location);
|
|
if (img == null) {
|
|
return;
|
|
}
|
|
HttpImageTask oldTask = img.httpTask;
|
|
img.httpTask = new HttpImageTask(oldTask.cacheImage, oldTask.imageSize);
|
|
httpTasks.add(img.httpTask);
|
|
runHttpTasks(false);
|
|
}
|
|
});
|
|
}
|
|
|
|
private void fileDidLoaded(final String location, final File finalFile, final int type) {
|
|
imageLoadQueue.postRunnable(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
ThumbGenerateInfo info = waitingForQualityThumb.get(location);
|
|
if (info != null) {
|
|
generateThumb(type, finalFile, info.fileLocation, info.filter);
|
|
waitingForQualityThumb.remove(location);
|
|
}
|
|
CacheImage img = imageLoadingByUrl.get(location);
|
|
if (img == null) {
|
|
return;
|
|
}
|
|
imageLoadingByUrl.remove(location);
|
|
CacheOutTask task = null;
|
|
for (ImageReceiver imageReceiver : img.imageReceiverArray) {
|
|
CacheImage cacheImage = imageLoadingByKeys.get(img.key);
|
|
if (cacheImage == null) {
|
|
cacheImage = new CacheImage();
|
|
cacheImage.finalFilePath = finalFile;
|
|
cacheImage.key = img.key;
|
|
cacheImage.httpUrl = img.httpUrl;
|
|
cacheImage.thumb = img.thumb;
|
|
cacheImage.cacheTask = task = new CacheOutTask(cacheImage);
|
|
cacheImage.filter = img.filter;
|
|
imageLoadingByKeys.put(cacheImage.key, cacheImage);
|
|
}
|
|
cacheImage.addImageReceiver(imageReceiver);
|
|
}
|
|
if (task != null) {
|
|
if (img.thumb) {
|
|
cacheThumbOutQueue.postRunnable(task);
|
|
} else {
|
|
cacheOutQueue.postRunnable(task);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private void fileDidFailedLoad(final String location, int canceled) {
|
|
if (canceled == 1) {
|
|
return;
|
|
}
|
|
imageLoadQueue.postRunnable(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
CacheImage img = imageLoadingByUrl.get(location);
|
|
if (img != null) {
|
|
img.setImageAndClear(null);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private void runHttpTasks(boolean complete) {
|
|
if (complete) {
|
|
currentHttpTasksCount--;
|
|
}
|
|
while (currentHttpTasksCount < 1 && !httpTasks.isEmpty()) {
|
|
HttpImageTask task = httpTasks.poll();
|
|
if (android.os.Build.VERSION.SDK_INT >= 11) {
|
|
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null);
|
|
} else {
|
|
task.execute(null, null, null);
|
|
}
|
|
currentHttpTasksCount++;
|
|
}
|
|
}
|
|
|
|
public void loadHttpFile(String url, String extension) {
|
|
if (url == null || url.length() == 0 || httpFileLoadTasksByKeys.containsKey(url)) {
|
|
return;
|
|
}
|
|
String ext = extension;
|
|
if (ext == null) {
|
|
int idx = url.lastIndexOf(".");
|
|
if (idx != -1) {
|
|
ext = url.substring(idx + 1);
|
|
}
|
|
if (ext == null || ext.length() == 0 || ext.length() > 4) {
|
|
ext = "jpg";
|
|
}
|
|
}
|
|
File file = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(url) + "_temp." + ext);
|
|
file.delete();
|
|
|
|
HttpFileTask task = new HttpFileTask(url, file, ext);
|
|
httpFileLoadTasks.add(task);
|
|
httpFileLoadTasksByKeys.put(url, task);
|
|
runHttpFileLoadTasks(null, 0);
|
|
}
|
|
|
|
public void cancelLoadHttpFile(String url) {
|
|
HttpFileTask task = httpFileLoadTasksByKeys.get(url);
|
|
if (task != null) {
|
|
task.cancel(true);
|
|
httpFileLoadTasksByKeys.remove(url);
|
|
httpFileLoadTasks.remove(task);
|
|
}
|
|
Runnable runnable = retryHttpsTasks.get(url);
|
|
if (runnable != null) {
|
|
AndroidUtilities.cancelRunOnUIThread(runnable);
|
|
}
|
|
runHttpFileLoadTasks(null, 0);
|
|
}
|
|
|
|
private void runHttpFileLoadTasks(final HttpFileTask oldTask, final int reason) {
|
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (oldTask != null) {
|
|
currentHttpFileLoadTasksCount--;
|
|
}
|
|
if (oldTask != null) {
|
|
if (reason == 1) {
|
|
if (oldTask.canRetry) {
|
|
final HttpFileTask newTask = new HttpFileTask(oldTask.url, oldTask.tempFile, oldTask.ext);
|
|
Runnable runnable = new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
httpFileLoadTasks.add(newTask);
|
|
runHttpFileLoadTasks(null, 0);
|
|
}
|
|
};
|
|
retryHttpsTasks.put(oldTask.url, runnable);
|
|
AndroidUtilities.runOnUIThread(runnable, 1000);
|
|
} else {
|
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.httpFileDidFailedLoad, oldTask.url);
|
|
}
|
|
} else if (reason == 2) {
|
|
httpFileLoadTasksByKeys.remove(oldTask.url);
|
|
File file = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(oldTask.url) + "." + oldTask.ext);
|
|
String result = oldTask.tempFile.renameTo(file) ? file.toString() : oldTask.tempFile.toString();
|
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.httpFileDidLoaded, oldTask.url, result);
|
|
}
|
|
}
|
|
while (currentHttpFileLoadTasksCount < 2 && !httpFileLoadTasks.isEmpty()) {
|
|
HttpFileTask task = httpFileLoadTasks.poll();
|
|
if (android.os.Build.VERSION.SDK_INT >= 11) {
|
|
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null);
|
|
} else {
|
|
task.execute(null, null, null);
|
|
}
|
|
currentHttpFileLoadTasksCount++;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public static Bitmap loadBitmap(String path, Uri uri, float maxWidth, float maxHeight, boolean useMaxScale) {
|
|
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
|
|
bmOptions.inJustDecodeBounds = true;
|
|
FileDescriptor fileDescriptor = null;
|
|
ParcelFileDescriptor parcelFD = null;
|
|
|
|
if (path == null && uri != null && uri.getScheme() != null) {
|
|
String imageFilePath = null;
|
|
if (uri.getScheme().contains("file")) {
|
|
path = uri.getPath();
|
|
} else {
|
|
try {
|
|
path = Utilities.getPath(uri);
|
|
} catch (Throwable e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (path != null) {
|
|
BitmapFactory.decodeFile(path, bmOptions);
|
|
} else if (uri != null) {
|
|
boolean error = false;
|
|
try {
|
|
parcelFD = ApplicationLoader.applicationContext.getContentResolver().openFileDescriptor(uri, "r");
|
|
fileDescriptor = parcelFD.getFileDescriptor();
|
|
BitmapFactory.decodeFileDescriptor(fileDescriptor, null, bmOptions);
|
|
} catch (Throwable e) {
|
|
FileLog.e("tmessages", e);
|
|
try {
|
|
if (parcelFD != null) {
|
|
parcelFD.close();
|
|
}
|
|
} catch (Throwable e2) {
|
|
FileLog.e("tmessages", e2);
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
float photoW = bmOptions.outWidth;
|
|
float photoH = bmOptions.outHeight;
|
|
float scaleFactor = useMaxScale ? Math.max(photoW / maxWidth, photoH / maxHeight) : Math.min(photoW / maxWidth, photoH / maxHeight);
|
|
if (scaleFactor < 1) {
|
|
scaleFactor = 1;
|
|
}
|
|
bmOptions.inJustDecodeBounds = false;
|
|
bmOptions.inSampleSize = (int)scaleFactor;
|
|
|
|
String exifPath = null;
|
|
if (path != null) {
|
|
exifPath = path;
|
|
} else if (uri != null) {
|
|
exifPath = Utilities.getPath(uri);
|
|
}
|
|
|
|
Matrix matrix = null;
|
|
|
|
if (exifPath != null) {
|
|
ExifInterface exif;
|
|
try {
|
|
exif = new ExifInterface(exifPath);
|
|
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
|
|
matrix = new Matrix();
|
|
switch (orientation) {
|
|
case ExifInterface.ORIENTATION_ROTATE_90:
|
|
matrix.postRotate(90);
|
|
break;
|
|
case ExifInterface.ORIENTATION_ROTATE_180:
|
|
matrix.postRotate(180);
|
|
break;
|
|
case ExifInterface.ORIENTATION_ROTATE_270:
|
|
matrix.postRotate(270);
|
|
break;
|
|
}
|
|
} catch (Throwable e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
}
|
|
|
|
Bitmap b = null;
|
|
if (path != null) {
|
|
try {
|
|
b = BitmapFactory.decodeFile(path, bmOptions);
|
|
if (b != null) {
|
|
b = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, true);
|
|
}
|
|
} catch (Throwable e) {
|
|
FileLog.e("tmessages", e);
|
|
ImageLoader.getInstance().clearMemory();
|
|
try {
|
|
if (b == null) {
|
|
b = BitmapFactory.decodeFile(path, bmOptions);
|
|
}
|
|
if (b != null) {
|
|
b = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, true);
|
|
}
|
|
} catch (Throwable e2) {
|
|
FileLog.e("tmessages", e2);
|
|
}
|
|
}
|
|
} else if (uri != null) {
|
|
try {
|
|
b = BitmapFactory.decodeFileDescriptor(fileDescriptor, null, bmOptions);
|
|
if (b != null) {
|
|
b = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, true);
|
|
}
|
|
} catch (Throwable e) {
|
|
FileLog.e("tmessages", e);
|
|
} finally {
|
|
try {
|
|
if (parcelFD != null) {
|
|
parcelFD.close();
|
|
}
|
|
} catch (Throwable e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
private static TLRPC.PhotoSize scaleAndSaveImageInternal(Bitmap bitmap, int w, int h, float photoW, float photoH, float scaleFactor, int quality, boolean cache, boolean scaleAnyway) throws Exception {
|
|
Bitmap scaledBitmap = null;
|
|
if (scaleFactor > 1 || scaleAnyway) {
|
|
scaledBitmap = Bitmap.createScaledBitmap(bitmap, w, h, true);
|
|
} else {
|
|
scaledBitmap = bitmap;
|
|
}
|
|
|
|
TLRPC.TL_fileLocation location = new TLRPC.TL_fileLocation();
|
|
location.volume_id = Integer.MIN_VALUE;
|
|
location.dc_id = Integer.MIN_VALUE;
|
|
location.local_id = UserConfig.lastLocalId;
|
|
UserConfig.lastLocalId--;
|
|
TLRPC.PhotoSize size = new TLRPC.TL_photoSize();
|
|
size.location = location;
|
|
size.w = scaledBitmap.getWidth();
|
|
size.h = scaledBitmap.getHeight();
|
|
if (size.w <= 100 && size.h <= 100) {
|
|
size.type = "s";
|
|
} else if (size.w <= 320 && size.h <= 320) {
|
|
size.type = "m";
|
|
} else if (size.w <= 800 && size.h <= 800) {
|
|
size.type = "x";
|
|
} else if (size.w <= 1280 && size.h <= 1280) {
|
|
size.type = "y";
|
|
} else {
|
|
size.type = "w";
|
|
}
|
|
|
|
String fileName = location.volume_id + "_" + location.local_id + ".jpg";
|
|
final File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName);
|
|
FileOutputStream stream = new FileOutputStream(cacheFile);
|
|
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, quality, stream);
|
|
if (cache) {
|
|
ByteArrayOutputStream stream2 = new ByteArrayOutputStream();
|
|
scaledBitmap.compress(Bitmap.CompressFormat.JPEG, quality, stream2);
|
|
size.bytes = stream2.toByteArray();
|
|
size.size = size.bytes.length;
|
|
stream2.close();
|
|
} else {
|
|
size.size = (int)stream.getChannel().size();
|
|
}
|
|
stream.close();
|
|
if (scaledBitmap != bitmap) {
|
|
scaledBitmap.recycle();
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
public static TLRPC.PhotoSize scaleAndSaveImage(Bitmap bitmap, float maxWidth, float maxHeight, int quality, boolean cache) {
|
|
return scaleAndSaveImage(bitmap, maxWidth, maxHeight, quality, cache, 0, 0);
|
|
}
|
|
|
|
public static TLRPC.PhotoSize scaleAndSaveImage(Bitmap bitmap, float maxWidth, float maxHeight, int quality, boolean cache, int minWidth, int minHeight) {
|
|
if (bitmap == null) {
|
|
return null;
|
|
}
|
|
float photoW = bitmap.getWidth();
|
|
float photoH = bitmap.getHeight();
|
|
if (photoW == 0 || photoH == 0) {
|
|
return null;
|
|
}
|
|
boolean scaleAnyway = false;
|
|
float scaleFactor = Math.max(photoW / maxWidth, photoH / maxHeight);
|
|
if (minWidth != 0 && minHeight != 0 && (photoW < minWidth || photoH < minHeight)) {
|
|
scaleFactor = Math.max(photoW / minWidth, photoH / minHeight);
|
|
scaleAnyway = true;
|
|
}
|
|
int w = (int)(photoW / scaleFactor);
|
|
int h = (int)(photoH / scaleFactor);
|
|
if (h == 0 || w == 0) {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
return scaleAndSaveImageInternal(bitmap, w, h, photoW, photoH, scaleFactor, quality, cache, scaleAnyway);
|
|
} catch (Throwable e) {
|
|
FileLog.e("tmessages", e);
|
|
ImageLoader.getInstance().clearMemory();
|
|
System.gc();
|
|
try {
|
|
return scaleAndSaveImageInternal(bitmap, w, h, photoW, photoH, scaleFactor, quality, cache, scaleAnyway);
|
|
} catch (Throwable e2) {
|
|
FileLog.e("tmessages", e2);
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static String getHttpUrlExtension(String url) {
|
|
String ext = null;
|
|
int idx = url.lastIndexOf(".");
|
|
if (idx != -1) {
|
|
ext = url.substring(idx + 1);
|
|
}
|
|
if (ext == null || ext.length() == 0 || ext.length() > 4) {
|
|
ext = "jpg";
|
|
}
|
|
return ext;
|
|
}
|
|
|
|
public static void saveMessageThumbs(TLRPC.Message message) {
|
|
TLRPC.PhotoSize photoSize = null;
|
|
if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
|
|
for (TLRPC.PhotoSize size : message.media.photo.sizes) {
|
|
if (size instanceof TLRPC.TL_photoCachedSize) {
|
|
photoSize = size;
|
|
break;
|
|
}
|
|
}
|
|
} else if (message.media instanceof TLRPC.TL_messageMediaVideo) {
|
|
if (message.media.video.thumb instanceof TLRPC.TL_photoCachedSize) {
|
|
photoSize = message.media.video.thumb;
|
|
}
|
|
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
|
|
if (message.media.document.thumb instanceof TLRPC.TL_photoCachedSize) {
|
|
photoSize = message.media.document.thumb;
|
|
for (TLRPC.DocumentAttribute attribute : message.media.document.attributes) {
|
|
if (attribute instanceof TLRPC.TL_documentAttributeSticker) {
|
|
photoSize.location.ext = "webp";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (photoSize != null && photoSize.bytes != null && photoSize.bytes.length != 0) {
|
|
if (photoSize.location instanceof TLRPC.TL_fileLocationUnavailable) {
|
|
photoSize.location = new TLRPC.TL_fileLocation();
|
|
photoSize.location.volume_id = Integer.MIN_VALUE;
|
|
photoSize.location.dc_id = Integer.MIN_VALUE;
|
|
photoSize.location.local_id = UserConfig.lastLocalId;
|
|
UserConfig.lastLocalId--;
|
|
}
|
|
File file = FileLoader.getPathToAttach(photoSize, true);
|
|
if (!file.exists()) {
|
|
try {
|
|
RandomAccessFile writeFile = new RandomAccessFile(file, "rws");
|
|
writeFile.write(photoSize.bytes);
|
|
writeFile.close();
|
|
} catch (Exception e) {
|
|
FileLog.e("tmessages", e);
|
|
}
|
|
}
|
|
TLRPC.TL_photoSize newPhotoSize = new TLRPC.TL_photoSize();
|
|
newPhotoSize.w = photoSize.w;
|
|
newPhotoSize.h = photoSize.h;
|
|
newPhotoSize.location = photoSize.location;
|
|
newPhotoSize.size = photoSize.size;
|
|
newPhotoSize.type = photoSize.type;
|
|
|
|
if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
|
|
for (int a = 0; a < message.media.photo.sizes.size(); a++) {
|
|
if (message.media.photo.sizes.get(a) instanceof TLRPC.TL_photoCachedSize) {
|
|
message.media.photo.sizes.set(a, newPhotoSize);
|
|
break;
|
|
}
|
|
}
|
|
} else if (message.media instanceof TLRPC.TL_messageMediaVideo) {
|
|
message.media.video.thumb = newPhotoSize;
|
|
} else if (message.media instanceof TLRPC.TL_messageMediaDocument) {
|
|
message.media.document.thumb = newPhotoSize;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void saveMessagesThumbs(ArrayList<TLRPC.Message> messages) {
|
|
if (messages == null || messages.isEmpty()) {
|
|
return;
|
|
}
|
|
for (TLRPC.Message message : messages) {
|
|
saveMessageThumbs(message);
|
|
}
|
|
}
|
|
}
|