mirror of https://github.com/NekoX-Dev/NekoX.git
426 lines
16 KiB
Java
426 lines
16 KiB
Java
package org.telegram.ui.Components;
|
|
|
|
import android.graphics.Bitmap;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Color;
|
|
import android.graphics.Paint;
|
|
import android.graphics.Rect;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.view.View;
|
|
|
|
import org.telegram.messenger.AndroidUtilities;
|
|
import org.telegram.messenger.DispatchQueue;
|
|
import org.telegram.messenger.FileLog;
|
|
import org.telegram.messenger.Utilities;
|
|
import org.telegram.ui.ActionBar.Theme;
|
|
import org.telegram.ui.ChatActivity;
|
|
|
|
import static android.graphics.Canvas.ALL_SAVE_FLAG;
|
|
|
|
public class BlurBehindDrawable {
|
|
|
|
DispatchQueue queue;
|
|
|
|
private final int type;
|
|
public static final int TAG_DRAWING_AS_BACKGROUND = (1 << 26) + 3;
|
|
|
|
public static final int STATIC_CONTENT = 0;
|
|
public static final int ADJUST_PAN_TRANSLATION_CONTENT = 1;
|
|
|
|
private View behindView;
|
|
private View parentView;
|
|
|
|
private Bitmap[] blurredBitmapTmp;
|
|
private Bitmap[] backgroundBitmap;
|
|
private Bitmap[] renderingBitmap;
|
|
private Canvas[] renderingBitmapCanvas;
|
|
private Canvas[] backgroundBitmapCanvas;
|
|
private Canvas[] blurCanvas;
|
|
|
|
private boolean processingNextFrame;
|
|
private boolean invalidate = true;
|
|
|
|
private float blurAlpha;
|
|
private boolean show;
|
|
private boolean error;
|
|
private boolean animateAlpha = true;
|
|
|
|
private final float DOWN_SCALE = 6f;
|
|
private int lastH;
|
|
private int lastW;
|
|
private int toolbarH;
|
|
|
|
private boolean wasDraw;
|
|
private boolean skipDraw;
|
|
|
|
private float panTranslationY;
|
|
|
|
BlurBackgroundTask blurBackgroundTask = new BlurBackgroundTask();
|
|
|
|
Paint emptyPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
|
|
Paint errorBlackoutPaint = new Paint();
|
|
private final Theme.ResourcesProvider resourcesProvider;
|
|
|
|
public BlurBehindDrawable(View behindView, View parentView, int type, Theme.ResourcesProvider resourcesProvider) {
|
|
this.type = type;
|
|
this.behindView = behindView;
|
|
this.parentView = parentView;
|
|
this.resourcesProvider = resourcesProvider;
|
|
errorBlackoutPaint.setColor(Color.BLACK);
|
|
}
|
|
|
|
public void draw(Canvas canvas) {
|
|
if (type == 1 && !wasDraw && !animateAlpha) {
|
|
generateBlurredBitmaps();
|
|
invalidate = false;
|
|
}
|
|
final Bitmap[] bitmap = renderingBitmap;
|
|
if ((bitmap != null || error) && animateAlpha) {
|
|
if (show && blurAlpha != 1f) {
|
|
blurAlpha += 0.09f;
|
|
if (blurAlpha > 1f) {
|
|
blurAlpha = 1f;
|
|
}
|
|
parentView.invalidate();
|
|
} else if (!show && blurAlpha != 0) {
|
|
blurAlpha -= 0.09f;
|
|
if (blurAlpha < 0) {
|
|
blurAlpha = 0f;
|
|
}
|
|
parentView.invalidate();
|
|
}
|
|
}
|
|
|
|
float alpha = animateAlpha ? blurAlpha : 1f;
|
|
if (bitmap == null && error) {
|
|
errorBlackoutPaint.setAlpha((int) (50 * alpha));
|
|
canvas.drawPaint(errorBlackoutPaint);
|
|
return;
|
|
}
|
|
|
|
if (alpha == 1f) {
|
|
canvas.save();
|
|
} else {
|
|
canvas.saveLayerAlpha(0, 0, parentView.getMeasuredWidth(), parentView.getMeasuredHeight(), (int) (alpha * 255), ALL_SAVE_FLAG);
|
|
}
|
|
if (bitmap != null) {
|
|
emptyPaint.setAlpha((int) (255 * alpha));
|
|
if (type == 1) {
|
|
canvas.translate(0, panTranslationY);
|
|
}
|
|
canvas.save();
|
|
canvas.scale( parentView.getMeasuredWidth() / (float) bitmap[1].getWidth(), parentView.getMeasuredHeight() / (float) bitmap[1].getHeight());
|
|
canvas.drawBitmap(bitmap[1], 0, 0, emptyPaint);
|
|
canvas.restore();
|
|
canvas.save();
|
|
if (type == 0) {
|
|
canvas.translate(0, panTranslationY);
|
|
}
|
|
canvas.scale(parentView.getMeasuredWidth() / (float) bitmap[0].getWidth(),toolbarH / (float) bitmap[0].getHeight());
|
|
canvas.drawBitmap(bitmap[0], 0, 0, emptyPaint);
|
|
canvas.restore();
|
|
wasDraw = true;
|
|
canvas.drawColor(0x1a000000);
|
|
}
|
|
canvas.restore();
|
|
|
|
if (show && !processingNextFrame && (renderingBitmap == null || invalidate)) {
|
|
processingNextFrame = true;
|
|
invalidate = false;
|
|
if (blurredBitmapTmp == null) {
|
|
blurredBitmapTmp = new Bitmap[2];
|
|
blurCanvas = new Canvas[2];
|
|
}
|
|
for (int i = 0; i < 2; i++) {
|
|
if (blurredBitmapTmp[i] == null || parentView.getMeasuredWidth() != lastW || parentView.getMeasuredHeight() != lastH) {
|
|
int lastH = parentView.getMeasuredHeight();
|
|
int lastW = parentView.getMeasuredWidth();
|
|
toolbarH = AndroidUtilities.statusBarHeight + AndroidUtilities.dp(200);
|
|
try {
|
|
int h = i == 0 ? toolbarH : lastH;
|
|
blurredBitmapTmp[i] = Bitmap.createBitmap((int) (lastW / DOWN_SCALE), (int) (h / DOWN_SCALE), Bitmap.Config.ARGB_8888);
|
|
blurCanvas[i] = new Canvas(blurredBitmapTmp[i]);
|
|
} catch (Exception e) {
|
|
FileLog.e(e);
|
|
AndroidUtilities.runOnUIThread(() -> {
|
|
error = true;
|
|
parentView.invalidate();
|
|
});
|
|
return;
|
|
}
|
|
} else {
|
|
blurredBitmapTmp[i].eraseColor(Color.TRANSPARENT);
|
|
}
|
|
if (i == 1) {
|
|
blurredBitmapTmp[i].eraseColor(getThemedColor(Theme.key_windowBackgroundWhite));
|
|
}
|
|
blurCanvas[i].save();
|
|
blurCanvas[i].scale(1f / DOWN_SCALE, 1f / DOWN_SCALE, 0, 0);
|
|
Drawable backDrawable = behindView.getBackground();
|
|
if (backDrawable == null) {
|
|
backDrawable = getBackgroundDrawable();
|
|
}
|
|
behindView.setTag(TAG_DRAWING_AS_BACKGROUND, i);
|
|
if (i == STATIC_CONTENT) {
|
|
blurCanvas[i].translate(0, -panTranslationY);
|
|
behindView.draw(blurCanvas[i]);
|
|
}
|
|
|
|
if (backDrawable != null && i == ADJUST_PAN_TRANSLATION_CONTENT) {
|
|
Rect oldBounds = backDrawable.getBounds();
|
|
backDrawable.setBounds(0, 0, behindView.getMeasuredWidth(), behindView.getMeasuredHeight());
|
|
backDrawable.draw(blurCanvas[i]);
|
|
backDrawable.setBounds(oldBounds);
|
|
behindView.draw(blurCanvas[i]);
|
|
}
|
|
|
|
behindView.setTag(TAG_DRAWING_AS_BACKGROUND, null);
|
|
blurCanvas[i].restore();
|
|
}
|
|
|
|
lastH = parentView.getMeasuredHeight();
|
|
lastW = parentView.getMeasuredWidth();
|
|
|
|
blurBackgroundTask.width = parentView.getMeasuredWidth();
|
|
blurBackgroundTask.height = parentView.getMeasuredHeight();
|
|
if (blurBackgroundTask.width == 0 || blurBackgroundTask.height == 0) {
|
|
processingNextFrame = false;
|
|
return;
|
|
}
|
|
if (queue == null) {
|
|
queue = new DispatchQueue("blur_thread_" + this);
|
|
}
|
|
queue.postRunnable(blurBackgroundTask);
|
|
}
|
|
}
|
|
|
|
private int getBlurRadius() {
|
|
return Math.max(7, Math.max(lastH, lastW) / 180);
|
|
}
|
|
|
|
public void clear() {
|
|
invalidate = true;
|
|
wasDraw = false;
|
|
error = false;
|
|
blurAlpha = 0;
|
|
lastW = 0;
|
|
lastH = 0;
|
|
if (queue != null) {
|
|
queue.cleanupQueue();
|
|
queue.postRunnable(() -> {
|
|
if (renderingBitmap != null) {
|
|
if (renderingBitmap[0] != null) {
|
|
renderingBitmap[0].recycle();
|
|
}
|
|
if (renderingBitmap[1] != null) {
|
|
renderingBitmap[1].recycle();
|
|
}
|
|
renderingBitmap = null;
|
|
}
|
|
if (backgroundBitmap != null) {
|
|
if (backgroundBitmap[0] != null) {
|
|
backgroundBitmap[0].recycle();
|
|
}
|
|
if (backgroundBitmap[1] != null) {
|
|
backgroundBitmap[1].recycle();
|
|
}
|
|
backgroundBitmap = null;
|
|
}
|
|
renderingBitmapCanvas = null;
|
|
skipDraw = false;
|
|
AndroidUtilities.runOnUIThread(() -> {
|
|
if (queue != null) {
|
|
queue.recycle();
|
|
queue = null;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
public void invalidate() {
|
|
invalidate = true;
|
|
if (parentView != null) {
|
|
parentView.invalidate();
|
|
}
|
|
}
|
|
|
|
public boolean isFullyDrawing() {
|
|
return !skipDraw && wasDraw && (blurAlpha == 1f || !animateAlpha) && show && parentView.getAlpha() == 1f;
|
|
}
|
|
|
|
public void checkSizes() {
|
|
final Bitmap[] bitmap = renderingBitmap;
|
|
if (bitmap == null || parentView.getMeasuredHeight() == 0 || parentView.getMeasuredWidth() == 0) {
|
|
return;
|
|
}
|
|
generateBlurredBitmaps();
|
|
|
|
lastH = parentView.getMeasuredHeight();
|
|
lastW = parentView.getMeasuredWidth();
|
|
}
|
|
|
|
private void generateBlurredBitmaps() {
|
|
Bitmap[] bitmap = renderingBitmap;
|
|
if (bitmap == null) {
|
|
bitmap = renderingBitmap = new Bitmap[2];
|
|
renderingBitmapCanvas = new Canvas[2];
|
|
}
|
|
if (blurredBitmapTmp == null) {
|
|
blurredBitmapTmp = new Bitmap[2];
|
|
blurCanvas = new Canvas[2];
|
|
}
|
|
blurBackgroundTask.canceled = true;
|
|
blurBackgroundTask = new BlurBackgroundTask();
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
int lastH = parentView.getMeasuredHeight();
|
|
int lastW = parentView.getMeasuredWidth();
|
|
toolbarH = AndroidUtilities.statusBarHeight + AndroidUtilities.dp(200);
|
|
int h = i == 0 ? toolbarH : lastH;
|
|
|
|
if (bitmap[i] == null || bitmap[i].getHeight() != h || bitmap[i].getWidth() != parentView.getMeasuredWidth()) {
|
|
if (queue != null) {
|
|
queue.cleanupQueue();
|
|
}
|
|
|
|
blurredBitmapTmp[i] = Bitmap.createBitmap((int) (lastW / DOWN_SCALE), (int) (h / DOWN_SCALE), Bitmap.Config.ARGB_8888);
|
|
if (i == 1) {
|
|
blurredBitmapTmp[i].eraseColor(getThemedColor(Theme.key_windowBackgroundWhite));
|
|
}
|
|
blurCanvas[i] = new Canvas(blurredBitmapTmp[i]);
|
|
|
|
int bitmapH = (int) ((i == 0 ? toolbarH : lastH) / DOWN_SCALE);
|
|
int bitmapW = (int) (lastW / DOWN_SCALE);
|
|
renderingBitmap[i] = Bitmap.createBitmap(bitmapW, bitmapH, Bitmap.Config.ARGB_8888);
|
|
renderingBitmapCanvas[i] = new Canvas(renderingBitmap[i]);
|
|
renderingBitmapCanvas[i].scale((float) renderingBitmap[i].getWidth() / (float) blurredBitmapTmp[i].getWidth(), (float) renderingBitmap[i].getHeight() / (float) blurredBitmapTmp[i].getHeight());
|
|
|
|
blurCanvas[i].save();
|
|
blurCanvas[i].scale(1f / DOWN_SCALE, 1f / DOWN_SCALE, 0, 0);
|
|
Drawable backDrawable = behindView.getBackground();
|
|
if (backDrawable == null) {
|
|
backDrawable = getBackgroundDrawable();
|
|
}
|
|
behindView.setTag(TAG_DRAWING_AS_BACKGROUND, i);
|
|
if (i == STATIC_CONTENT) {
|
|
blurCanvas[i].translate(0, -panTranslationY);
|
|
behindView.draw(blurCanvas[i]);
|
|
}
|
|
|
|
if (i == ADJUST_PAN_TRANSLATION_CONTENT) {
|
|
Rect oldBounds = backDrawable.getBounds();
|
|
backDrawable.setBounds(0, 0, behindView.getMeasuredWidth(), behindView.getMeasuredHeight());
|
|
backDrawable.draw(blurCanvas[i]);
|
|
backDrawable.setBounds(oldBounds);
|
|
behindView.draw(blurCanvas[i]);
|
|
}
|
|
|
|
behindView.setTag(TAG_DRAWING_AS_BACKGROUND, null);
|
|
blurCanvas[i].restore();
|
|
|
|
Utilities.stackBlurBitmap(blurredBitmapTmp[i], getBlurRadius());
|
|
emptyPaint.setAlpha(255);
|
|
if (i == 1) {
|
|
renderingBitmap[i].eraseColor(getThemedColor(Theme.key_windowBackgroundWhite));
|
|
}
|
|
renderingBitmapCanvas[i].drawBitmap(blurredBitmapTmp[i], 0, 0, emptyPaint);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void show(boolean show) {
|
|
this.show = show;
|
|
}
|
|
|
|
public void setAnimateAlpha(boolean animateAlpha) {
|
|
this.animateAlpha = animateAlpha;
|
|
}
|
|
|
|
public void onPanTranslationUpdate(float y) {
|
|
panTranslationY = y;
|
|
parentView.invalidate();
|
|
}
|
|
|
|
public class BlurBackgroundTask implements Runnable {
|
|
|
|
boolean canceled;
|
|
int width;
|
|
int height;
|
|
|
|
@Override
|
|
public void run() {
|
|
if (backgroundBitmap == null) {
|
|
backgroundBitmap = new Bitmap[2];
|
|
backgroundBitmapCanvas = new Canvas[2];
|
|
}
|
|
int bitmapWidth = (int) (width / DOWN_SCALE);
|
|
for (int i = 0; i < 2; i++) {
|
|
int h = (int) ((i == 0 ? toolbarH : height) / DOWN_SCALE);
|
|
|
|
if (backgroundBitmap[i] != null && (backgroundBitmap[i].getHeight() != h || backgroundBitmap[i].getWidth() != bitmapWidth)) {
|
|
if (backgroundBitmap[i] != null) {
|
|
backgroundBitmap[i].recycle();
|
|
backgroundBitmap[i] = null;
|
|
}
|
|
}
|
|
long t = System.currentTimeMillis();
|
|
if (backgroundBitmap[i] == null) {
|
|
int w = bitmapWidth;
|
|
try {
|
|
backgroundBitmap[i] = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
|
|
backgroundBitmapCanvas[i] = new Canvas(backgroundBitmap[i]);
|
|
backgroundBitmapCanvas[i].scale(bitmapWidth / (float) blurredBitmapTmp[i].getWidth(), h / (float) blurredBitmapTmp[i].getHeight());
|
|
} catch (Throwable e) {
|
|
FileLog.e(e);
|
|
}
|
|
}
|
|
if (i == 1) {
|
|
backgroundBitmap[i].eraseColor(getThemedColor(Theme.key_windowBackgroundWhite));
|
|
} else {
|
|
backgroundBitmap[i].eraseColor(Color.TRANSPARENT);
|
|
}
|
|
emptyPaint.setAlpha(255);
|
|
Utilities.stackBlurBitmap(blurredBitmapTmp[i], getBlurRadius());
|
|
|
|
if (backgroundBitmapCanvas[i] != null) {
|
|
backgroundBitmapCanvas[i].drawBitmap(blurredBitmapTmp[i], 0, 0, emptyPaint);
|
|
}
|
|
|
|
if (canceled) {
|
|
return;
|
|
}
|
|
}
|
|
AndroidUtilities.runOnUIThread(() -> {
|
|
if (canceled) {
|
|
return;
|
|
}
|
|
Bitmap[] bitmap = renderingBitmap;
|
|
Canvas[] canvas = renderingBitmapCanvas;
|
|
|
|
renderingBitmap = backgroundBitmap;
|
|
renderingBitmapCanvas = backgroundBitmapCanvas;
|
|
|
|
backgroundBitmap = bitmap;
|
|
backgroundBitmapCanvas = canvas;
|
|
|
|
processingNextFrame = false;
|
|
if (parentView != null) {
|
|
parentView.invalidate();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
private Drawable getBackgroundDrawable() {
|
|
return (resourcesProvider instanceof ChatActivity.ThemeDelegate)
|
|
? ((ChatActivity.ThemeDelegate) resourcesProvider).getWallpaperDrawable()
|
|
: Theme.getCachedWallpaperNonBlocking();
|
|
}
|
|
|
|
private int getThemedColor(String key) {
|
|
Integer color = resourcesProvider != null ? resourcesProvider.getColor(key) : null;
|
|
return color != null ? color : Theme.getColor(key);
|
|
}
|
|
}
|