NekoX/TMessagesProj/src/main/java/org/telegram/android/ImageReceiver.java

662 lines
24 KiB
Java

/*
* This is the source code of Telegram for Android v. 1.3.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.
*/
package org.telegram.android;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.view.View;
import org.telegram.messenger.TLObject;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.Utilities;
public class ImageReceiver implements NotificationCenter.NotificationCenterDelegate {
public static interface ImageReceiverDelegate {
public void didSetImage(ImageReceiver imageReceiver, boolean set, boolean thumb);
}
private View parentView;
private Integer tag;
private Integer thumbTag;
private MessageObject parentMessageObject;
private boolean canceledLoading;
private TLObject currentImageLocation;
private String currentKey;
private String currentThumbKey;
private String currentHttpUrl;
private String currentFilter;
private String currentThumbFilter;
private TLRPC.FileLocation currentThumbLocation;
private int currentSize;
private boolean currentCacheOnly;
private BitmapDrawable currentImage;
private BitmapDrawable currentThumb;
private Drawable staticThumb;
private boolean needsQualityThumb;
private boolean shouldGenerateQualityThumb;
private int imageX, imageY, imageW, imageH;
private Rect drawRegion = new Rect();
private boolean isVisible = true;
private boolean isAspectFit;
private boolean forcePreview;
private int roundRadius;
private BitmapShader bitmapShader;
private Paint roundPaint;
private RectF roundRect;
private RectF bitmapRect;
private Matrix shaderMatrix;
private int alpha = 255;
private boolean isPressed;
private boolean disableRecycle;
private ImageReceiverDelegate delegate;
public ImageReceiver() {
}
public ImageReceiver(View view) {
parentView = view;
}
public void cancelLoadImage() {
ImageLoader.getInstance().cancelLoadingForImageReceiver(this, 0);
canceledLoading = true;
}
public void setImage(TLObject path, String filter, Drawable thumb, boolean cacheOnly) {
setImage(path, null, filter, thumb, null, null, 0, cacheOnly);
}
public void setImage(TLObject path, String filter, Drawable thumb, int size, boolean cacheOnly) {
setImage(path, null, filter, thumb, null, null, size, cacheOnly);
}
public void setImage(String httpUrl, String filter, Drawable thumb, int size) {
setImage(null, httpUrl, filter, thumb, null, null, size, true);
}
public void setImage(TLObject fileLocation, String filter, TLRPC.FileLocation thumbLocation, String thumbFilter, boolean cacheOnly) {
setImage(fileLocation, null, filter, null, thumbLocation, thumbFilter, 0, cacheOnly);
}
public void setImage(TLObject fileLocation, String filter, TLRPC.FileLocation thumbLocation, String thumbFilter, int size, boolean cacheOnly) {
setImage(fileLocation, null, filter, null, thumbLocation, thumbFilter, size, cacheOnly);
}
public void setImage(TLObject fileLocation, String httpUrl, String filter, Drawable thumb, TLRPC.FileLocation thumbLocation, String thumbFilter, int size, boolean cacheOnly) {
if ((fileLocation == null && httpUrl == null && thumbLocation == null)
|| (fileLocation != null && !(fileLocation instanceof TLRPC.TL_fileLocation)
&& !(fileLocation instanceof TLRPC.TL_fileEncryptedLocation)
&& !(fileLocation instanceof TLRPC.TL_document))) {
recycleBitmap(null, false);
recycleBitmap(null, true);
currentKey = null;
currentThumbKey = null;
currentThumbFilter = null;
currentImageLocation = null;
currentHttpUrl = null;
currentFilter = null;
currentCacheOnly = false;
staticThumb = thumb;
currentThumbLocation = null;
currentSize = 0;
currentImage = null;
bitmapShader = null;
ImageLoader.getInstance().cancelLoadingForImageReceiver(this, 0);
if (parentView != null) {
parentView.invalidate();
}
if (delegate != null) {
delegate.didSetImage(this, currentImage != null || currentThumb != null || staticThumb != null, currentImage == null);
}
return;
}
if (!(thumbLocation instanceof TLRPC.TL_fileLocation)) {
thumbLocation = null;
}
String key = null;
if (fileLocation != null) {
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;
}
} else if (httpUrl != null) {
key = Utilities.MD5(httpUrl);
}
if (key != null) {
if (filter != null) {
key += "@" + filter;
}
}
if (currentKey != null && key != null && currentKey.equals(key)) {
if (delegate != null) {
delegate.didSetImage(this, currentImage != null || currentThumb != null || staticThumb != null, currentImage == null);
}
if (!canceledLoading && !forcePreview) {
return;
}
}
String thumbKey = null;
if (thumbLocation != null) {
thumbKey = thumbLocation.volume_id + "_" + thumbLocation.local_id;
if (thumbFilter != null) {
thumbKey += "@" + thumbFilter;
}
}
recycleBitmap(key, false);
recycleBitmap(thumbKey, true);
currentThumbKey = thumbKey;
currentKey = key;
currentImageLocation = fileLocation;
currentHttpUrl = httpUrl;
currentFilter = filter;
currentThumbFilter = thumbFilter;
currentSize = size;
currentCacheOnly = cacheOnly;
currentThumbLocation = thumbLocation;
staticThumb = thumb;
bitmapShader = null;
if (delegate != null) {
delegate.didSetImage(this, currentImage != null || currentThumb != null || staticThumb != null, currentImage == null);
}
ImageLoader.getInstance().loadImageForImageReceiver(this);
if (parentView != null) {
parentView.invalidate();
}
}
public void setDelegate(ImageReceiverDelegate delegate) {
this.delegate = delegate;
}
public void setPressed(boolean value) {
isPressed = value;
}
public boolean getPressed() {
return isPressed;
}
public void setImageBitmap(Bitmap bitmap) {
setImageBitmap(bitmap != null ? new BitmapDrawable(null, bitmap) : null);
}
public void setDisableRecycle(boolean value) {
disableRecycle = value;
}
public void setImageBitmap(Drawable bitmap) {
ImageLoader.getInstance().cancelLoadingForImageReceiver(this, 0);
recycleBitmap(null, false);
recycleBitmap(null, true);
staticThumb = bitmap;
currentThumbLocation = null;
currentKey = null;
currentThumbKey = null;
currentImage = null;
currentThumbFilter = null;
currentImageLocation = null;
currentHttpUrl = null;
currentFilter = null;
currentSize = 0;
currentCacheOnly = false;
bitmapShader = null;
if (delegate != null) {
delegate.didSetImage(this, currentImage != null || currentThumb != null || staticThumb != null, currentImage == null);
}
if (parentView != null) {
parentView.invalidate();
}
}
public void clearImage() {
recycleBitmap(null, false);
recycleBitmap(null, true);
if (needsQualityThumb) {
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messageThumbGenerated);
ImageLoader.getInstance().cancelLoadingForImageReceiver(this, 0);
}
}
public boolean draw(Canvas canvas) {
try {
BitmapDrawable bitmapDrawable = null;
if (!forcePreview && currentImage != null) {
bitmapDrawable = currentImage;
} else if (staticThumb instanceof BitmapDrawable) {
bitmapDrawable = (BitmapDrawable) staticThumb;
} else if (currentThumb != null) {
bitmapDrawable = currentThumb;
}
if (bitmapDrawable != null) {
Paint paint = bitmapDrawable.getPaint();
boolean hasFilter = paint != null && paint.getColorFilter() != null;
if (hasFilter && !isPressed) {
bitmapDrawable.setColorFilter(null);
hasFilter = false;
} else if (!hasFilter && isPressed) {
bitmapDrawable.setColorFilter(new PorterDuffColorFilter(0xffdddddd, PorterDuff.Mode.MULTIPLY));
hasFilter = true;
}
if (bitmapShader != null) {
drawRegion.set(imageX, imageY, imageX + imageW, imageY + imageH);
if (isVisible) {
roundRect.set(drawRegion);
shaderMatrix.reset();
shaderMatrix.setRectToRect(bitmapRect, roundRect, Matrix.ScaleToFit.FILL);
bitmapShader.setLocalMatrix(shaderMatrix);
canvas.drawRoundRect(roundRect, roundRadius, roundRadius, roundPaint);
}
} else {
int bitmapW = bitmapDrawable.getIntrinsicWidth();
int bitmapH = bitmapDrawable.getIntrinsicHeight();
float scaleW = bitmapW / (float) imageW;
float scaleH = bitmapH / (float) imageH;
if (isAspectFit) {
float scale = Math.max(scaleW, scaleH);
canvas.save();
bitmapW /= scale;
bitmapH /= scale;
drawRegion.set(imageX + (imageW - bitmapW) / 2, imageY + (imageH - bitmapH) / 2, imageX + (imageW + bitmapW) / 2, imageY + (imageH + bitmapH) / 2);
bitmapDrawable.setBounds(drawRegion);
try {
bitmapDrawable.setAlpha(alpha);
bitmapDrawable.draw(canvas);
} catch (Exception e) {
if (bitmapDrawable == currentImage && currentKey != null) {
ImageLoader.getInstance().removeImage(currentKey);
currentKey = null;
} else if (bitmapDrawable == currentThumb && currentThumbKey != null) {
ImageLoader.getInstance().removeImage(currentThumbKey);
currentThumbKey = null;
}
setImage(currentImageLocation, currentHttpUrl, currentFilter, currentThumb, currentThumbLocation, currentThumbFilter, currentSize, currentCacheOnly);
FileLog.e("tmessages", e);
}
canvas.restore();
} else {
if (Math.abs(scaleW - scaleH) > 0.00001f) {
canvas.save();
canvas.clipRect(imageX, imageY, imageX + imageW, imageY + imageH);
if (bitmapW / scaleH > imageW) {
bitmapW /= scaleH;
drawRegion.set(imageX - (bitmapW - imageW) / 2, imageY, imageX + (bitmapW + imageW) / 2, imageY + imageH);
} else {
bitmapH /= scaleW;
drawRegion.set(imageX, imageY - (bitmapH - imageH) / 2, imageX + imageW, imageY + (bitmapH + imageH) / 2);
}
bitmapDrawable.setBounds(drawRegion);
if (isVisible) {
try {
bitmapDrawable.setAlpha(alpha);
bitmapDrawable.draw(canvas);
} catch (Exception e) {
if (bitmapDrawable == currentImage && currentKey != null) {
ImageLoader.getInstance().removeImage(currentKey);
currentKey = null;
} else if (bitmapDrawable == currentThumb && currentThumbKey != null) {
ImageLoader.getInstance().removeImage(currentThumbKey);
currentThumbKey = null;
}
setImage(currentImageLocation, currentHttpUrl, currentFilter, currentThumb, currentThumbLocation, currentThumbFilter, currentSize, currentCacheOnly);
FileLog.e("tmessages", e);
}
}
canvas.restore();
} else {
drawRegion.set(imageX, imageY, imageX + imageW, imageY + imageH);
bitmapDrawable.setBounds(drawRegion);
if (isVisible) {
try {
bitmapDrawable.setAlpha(alpha);
bitmapDrawable.draw(canvas);
} catch (Exception e) {
if (bitmapDrawable == currentImage && currentKey != null) {
ImageLoader.getInstance().removeImage(currentKey);
currentKey = null;
} else if (bitmapDrawable == currentThumb && currentThumbKey != null) {
ImageLoader.getInstance().removeImage(currentThumbKey);
currentThumbKey = null;
}
setImage(currentImageLocation, currentHttpUrl, currentFilter, currentThumb, currentThumbLocation, currentThumbFilter, currentSize, currentCacheOnly);
FileLog.e("tmessages", e);
}
}
}
}
}
return true;
} else if (staticThumb != null) {
drawRegion.set(imageX, imageY, imageX + imageW, imageY + imageH);
staticThumb.setBounds(drawRegion);
if (isVisible) {
try {
staticThumb.setAlpha(alpha);
staticThumb.draw(canvas);
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
return true;
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
return false;
}
public Bitmap getBitmap() {
if (currentImage != null) {
return currentImage.getBitmap();
} else if (currentThumb != null) {
return currentThumb.getBitmap();
} else if (staticThumb instanceof BitmapDrawable) {
return ((BitmapDrawable) staticThumb).getBitmap();
}
return null;
}
public void setVisible(boolean value, boolean invalidate) {
if (isVisible == value) {
return;
}
isVisible = value;
if (invalidate && parentView != null) {
parentView.invalidate();
}
}
public boolean getVisible() {
return isVisible;
}
public void setAlpha(float value) {
alpha = (int)(value * 255.0f);
}
public boolean hasImage() {
return currentImage != null || currentThumb != null || currentKey != null || currentHttpUrl != null || staticThumb != null;
}
public void setAspectFit(boolean value) {
isAspectFit = value;
}
public void setParentView(View view) {
parentView = view;
}
public void setImageCoords(int x, int y, int width, int height) {
imageX = x;
imageY = y;
imageW = width;
imageH = height;
}
public int getImageX() {
return imageX;
}
public int getImageY() {
return imageY;
}
public int getImageWidth() {
return imageW;
}
public int getImageHeight() {
return imageH;
}
public boolean isInsideImage(float x, float y) {
return x >= imageX && x <= imageX + imageW && y >= imageY && y <= imageY + imageH;
}
public Rect getDrawRegion() {
return drawRegion;
}
public String getFilter() {
return currentFilter;
}
public String getThumbFilter() {
return currentThumbFilter;
}
public String getKey() {
return currentKey;
}
public String getThumbKey() {
return currentThumbKey;
}
public int getSize() {
return currentSize;
}
public TLObject getImageLocation() {
return currentImageLocation;
}
public TLRPC.FileLocation getThumbLocation() {
return currentThumbLocation;
}
public String getHttpImageLocation() {
return currentHttpUrl;
}
public boolean getCacheOnly() {
return currentCacheOnly;
}
public void setForcePreview(boolean value) {
forcePreview = value;
}
public boolean isForcePreview() {
return forcePreview;
}
public void setRoundRadius(int value) {
roundRadius = value;
if (roundRadius != 0) {
if (roundPaint == null) {
roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
roundRect = new RectF();
shaderMatrix = new Matrix();
bitmapRect = new RectF();
}
} else {
roundPaint = null;
roundRect = null;
shaderMatrix = null;
bitmapRect = null;
}
}
public int getRoundRadius() {
return roundRadius;
}
public void setParentMessageObject(MessageObject messageObject) {
parentMessageObject = messageObject;
}
public MessageObject getParentMessageObject() {
return parentMessageObject;
}
public void setNeedsQualityThumb(boolean value) {
needsQualityThumb = value;
if (needsQualityThumb) {
NotificationCenter.getInstance().addObserver(this, NotificationCenter.messageThumbGenerated);
} else {
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messageThumbGenerated);
}
}
public boolean isNeedsQualityThumb() {
return needsQualityThumb;
}
public void setShouldGenerateQualityThumb(boolean value) {
shouldGenerateQualityThumb = value;
}
public boolean isShouldGenerateQualityThumb() {
return shouldGenerateQualityThumb;
}
protected Integer getTag(boolean thumb) {
if (thumb) {
return thumbTag;
} else {
return tag;
}
}
protected void setTag(Integer value, boolean thumb) {
if (thumb) {
thumbTag = value;
} else {
tag = value;
}
}
protected void setImageBitmapByKey(BitmapDrawable bitmap, String key, boolean thumb) {
if (bitmap == null || key == null) {
return;
}
if (!thumb) {
if (currentKey == null || !key.equals(currentKey)) {
return;
}
ImageLoader.getInstance().incrementUseCount(currentKey);
currentImage = bitmap;
if (roundRadius != 0 && bitmap instanceof BitmapDrawable) {
Bitmap object = bitmap.getBitmap();
bitmapShader = new BitmapShader(object, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
roundPaint.setShader(bitmapShader);
bitmapRect.set(0, 0, object.getWidth(), object.getHeight());
}
if (parentView != null) {
parentView.invalidate();
}
} else if (currentThumb == null && (currentImage == null || forcePreview)) {
if (currentThumbKey == null || !key.equals(currentThumbKey)) {
return;
}
ImageLoader.getInstance().incrementUseCount(currentThumbKey);
currentThumb = bitmap;
if (!(staticThumb instanceof BitmapDrawable) && parentView != null) {
parentView.invalidate();
}
}
if (delegate != null) {
delegate.didSetImage(this, currentImage != null || currentThumb != null || staticThumb != null, currentImage == null);
}
}
private void recycleBitmap(String newKey, boolean thumb) {
String key;
BitmapDrawable image;
if (thumb) {
if (currentThumb == null) {
return;
}
key = currentThumbKey;
image = currentThumb;
} else {
if (currentImage == null) {
return;
}
key = currentKey;
image = currentImage;
}
BitmapDrawable newBitmap = null;
if (newKey != null) {
newBitmap = ImageLoader.getInstance().getImageFromMemory(newKey);
}
if (key == null || image == null || image == newBitmap || disableRecycle) {
return;
}
Bitmap bitmap = image.getBitmap();
boolean canDelete = ImageLoader.getInstance().decrementUseCount(key);
if (!ImageLoader.getInstance().isInCache(key)) {
if (ImageLoader.getInstance().runtimeHack != null) {
ImageLoader.getInstance().runtimeHack.trackAlloc(bitmap.getRowBytes() * bitmap.getHeight());
}
if (canDelete) {
bitmap.recycle();
ImageLoader.getInstance().callGC();
}
}
if (thumb) {
currentThumb = null;
currentThumbKey = null;
} else {
currentImage = null;
currentKey = null;
}
}
@Override
public void didReceivedNotification(int id, Object... args) {
if (id == NotificationCenter.messageThumbGenerated) {
String key = (String) args[1];
if (currentThumbKey != null && currentThumbKey.equals(key)) {
if (currentThumb == null) {
ImageLoader.getInstance().incrementUseCount(currentThumbKey);
}
currentThumb = (BitmapDrawable) args[0];
if (staticThumb instanceof BitmapDrawable) {
staticThumb = null;
}
if (parentView != null) {
parentView.invalidate();
}
}
}
}
}