NekoX/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java

809 lines
32 KiB
Java
Raw Normal View History

2015-05-21 23:27:27 +02:00
/*
2019-01-23 18:03:33 +01:00
* This is the source code of Telegram for Android v. 5.x.x.
2015-05-21 23:27:27 +02:00
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
2019-01-23 18:03:33 +01:00
* Copyright Nikolai Kudashov, 2013-2018.
2015-05-21 23:27:27 +02:00
*/
package org.telegram.ui.Components;
2022-01-18 21:51:58 +01:00
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
2015-05-21 23:27:27 +02:00
import android.content.Context;
2022-01-18 21:51:58 +01:00
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
2015-05-21 23:27:27 +02:00
import android.graphics.Canvas;
2022-01-18 21:51:58 +01:00
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
2015-05-21 23:27:27 +02:00
import android.graphics.Rect;
2016-10-11 13:57:01 +02:00
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
2015-05-21 23:27:27 +02:00
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
2019-09-10 12:56:11 +02:00
import android.graphics.drawable.GradientDrawable;
2017-03-31 01:58:05 +02:00
import android.os.Build;
2015-05-21 23:27:27 +02:00
import android.view.View;
2020-09-30 15:48:47 +02:00
import android.widget.FrameLayout;
2015-05-21 23:27:27 +02:00
2015-09-24 22:52:02 +02:00
import org.telegram.messenger.AndroidUtilities;
2022-01-18 21:51:58 +01:00
import org.telegram.messenger.DispatchQueue;
import org.telegram.messenger.FileLog;
2021-12-30 11:52:40 +01:00
import org.telegram.messenger.SharedConfig;
2022-01-18 21:51:58 +01:00
import org.telegram.messenger.Utilities;
2017-03-31 01:58:05 +02:00
import org.telegram.ui.ActionBar.ActionBar;
2019-12-31 14:08:08 +01:00
import org.telegram.ui.ActionBar.ActionBarLayout;
2020-09-30 15:48:47 +02:00
import org.telegram.ui.ActionBar.AdjustPanLayoutHelper;
2019-12-31 14:08:08 +01:00
import org.telegram.ui.ActionBar.Theme;
2022-03-11 17:49:54 +01:00
import org.telegram.ui.BlurSettingsBottomSheet;
2015-05-21 23:27:27 +02:00
2022-01-18 21:51:58 +01:00
import java.util.ArrayList;
2020-09-30 15:48:47 +02:00
public class SizeNotifierFrameLayout extends FrameLayout {
2015-05-21 23:27:27 +02:00
private Rect rect = new Rect();
private Drawable backgroundDrawable;
protected int keyboardHeight;
2015-06-29 19:12:11 +02:00
private int bottomClip;
private SizeNotifierFrameLayoutDelegate delegate;
2018-07-30 04:07:02 +02:00
private boolean occupyStatusBar = true;
2019-01-23 18:03:33 +01:00
private WallpaperParallaxEffect parallaxEffect;
private float translationX;
private float translationY;
2021-06-25 02:43:10 +02:00
private float bgAngle;
2019-01-23 18:03:33 +01:00
private float parallaxScale = 1.0f;
2020-02-13 19:26:53 +01:00
private int backgroundTranslationY;
2019-02-08 03:30:32 +01:00
private boolean paused = true;
2019-12-31 14:08:08 +01:00
private Drawable oldBackgroundDrawable;
private ActionBarLayout parentLayout;
2020-09-30 15:48:47 +02:00
protected AdjustPanLayoutHelper adjustPanLayoutHelper;
2021-06-25 02:43:10 +02:00
private int emojiHeight;
private float emojiOffset;
private boolean animationInProgress;
2021-08-31 21:06:39 +02:00
private boolean skipBackgroundDrawing;
2021-12-30 11:52:40 +01:00
SnowflakesEffect snowflakesEffect;
2022-02-01 14:00:45 +01:00
protected View backgroundView;
2015-05-21 23:27:27 +02:00
2022-03-11 17:49:54 +01:00
//blur variables
public boolean needBlur;
public boolean needBlurBottom;
public boolean blurIsRunning;
public boolean blurGeneratingTuskIsRunning;
BlurBitmap currentBitmap;
BlurBitmap prevBitmap;
public ArrayList<BlurBitmap> unusedBitmaps = new ArrayList<>(10);
public ArrayList<View> blurBehindViews = new ArrayList<>();
Matrix matrix = new Matrix();
Matrix matrix2 = new Matrix();
public Paint blurPaintTop = new Paint();
public Paint blurPaintTop2 = new Paint();
public Paint blurPaintBottom = new Paint();
public Paint blurPaintBottom2 = new Paint();
2022-03-20 21:22:37 +01:00
private Paint selectedBlurPaint;
private Paint selectedBlurPaint2;
2022-03-11 17:49:54 +01:00
float saturation;
public float blurCrossfadeProgress;
private final float DOWN_SCALE = 12f;
private final int TOP_CLIP_OFFSET = (int) (10 + DOWN_SCALE * 2);
private static DispatchQueue blurQueue;
ValueAnimator blurCrossfade;
public boolean invalidateBlur;
int count;
int times;
int count2;
int times2;
//
2022-01-18 21:51:58 +01:00
public void invalidateBlur() {
invalidateBlur = true;
2022-03-11 17:49:54 +01:00
invalidate();
2022-01-18 21:51:58 +01:00
}
2015-06-29 19:12:11 +02:00
public interface SizeNotifierFrameLayoutDelegate {
void onSizeChanged(int keyboardHeight, boolean isWidthGreater);
2015-05-21 23:27:27 +02:00
}
2020-09-30 15:48:47 +02:00
public SizeNotifierFrameLayout(Context context) {
this(context, null);
2019-12-31 14:08:08 +01:00
}
2020-09-30 15:48:47 +02:00
public SizeNotifierFrameLayout(Context context, ActionBarLayout layout) {
2015-06-29 19:12:11 +02:00
super(context);
2015-05-21 23:27:27 +02:00
setWillNotDraw(false);
2019-12-31 14:08:08 +01:00
parentLayout = layout;
2020-09-30 15:48:47 +02:00
adjustPanLayoutHelper = createAdjustPanLayoutHelper();
2022-02-01 14:00:45 +01:00
backgroundView = new View(context) {
@Override
protected void onDraw(Canvas canvas) {
if (backgroundDrawable == null || skipBackgroundDrawing) {
return;
}
Drawable newDrawable = getNewDrawable();
if (newDrawable != backgroundDrawable && newDrawable != null) {
if (Theme.isAnimatingColor()) {
oldBackgroundDrawable = backgroundDrawable;
}
if (newDrawable instanceof MotionBackgroundDrawable) {
MotionBackgroundDrawable motionBackgroundDrawable = (MotionBackgroundDrawable) newDrawable;
motionBackgroundDrawable.setParentView(backgroundView);
}
backgroundDrawable = newDrawable;
}
float themeAnimationValue = parentLayout != null ? parentLayout.getThemeAnimationValue() : 1.0f;
for (int a = 0; a < 2; a++) {
Drawable drawable = a == 0 ? oldBackgroundDrawable : backgroundDrawable;
if (drawable == null) {
continue;
}
if (a == 1 && oldBackgroundDrawable != null && parentLayout != null) {
drawable.setAlpha((int) (255 * themeAnimationValue));
} else {
drawable.setAlpha(255);
}
if (drawable instanceof MotionBackgroundDrawable) {
MotionBackgroundDrawable motionBackgroundDrawable = (MotionBackgroundDrawable) drawable;
if (motionBackgroundDrawable.hasPattern()) {
int actionBarHeight = (isActionBarVisible() ? ActionBar.getCurrentActionBarHeight() : 0) + (Build.VERSION.SDK_INT >= 21 && occupyStatusBar ? AndroidUtilities.statusBarHeight : 0);
int viewHeight = getRootView().getMeasuredHeight() - actionBarHeight;
float scaleX = (float) getMeasuredWidth() / (float) drawable.getIntrinsicWidth();
float scaleY = (float) (viewHeight) / (float) drawable.getIntrinsicHeight();
float scale = Math.max(scaleX, scaleY);
int width = (int) Math.ceil(drawable.getIntrinsicWidth() * scale * parallaxScale);
int height = (int) Math.ceil(drawable.getIntrinsicHeight() * scale * parallaxScale);
int x = (getMeasuredWidth() - width) / 2 + (int) translationX;
int y = backgroundTranslationY + (viewHeight - height) / 2 + actionBarHeight + (int) translationY;
canvas.save();
canvas.clipRect(0, actionBarHeight, width, getMeasuredHeight() - bottomClip);
drawable.setBounds(x, y, x + width, y + height);
drawable.draw(canvas);
checkSnowflake(canvas);
canvas.restore();
} else {
if (bottomClip != 0) {
canvas.save();
canvas.clipRect(0, 0, getMeasuredWidth(), getRootView().getMeasuredHeight() - bottomClip);
}
motionBackgroundDrawable.setTranslationY(backgroundTranslationY);
2022-03-11 17:49:54 +01:00
int bottom = (int) (getRootView().getMeasuredHeight() - backgroundTranslationY + translationY);
2022-02-01 14:00:45 +01:00
if (animationInProgress) {
bottom -= emojiOffset;
} else if (emojiHeight != 0) {
bottom -= emojiHeight;
}
drawable.setBounds(0, 0, getMeasuredWidth(), bottom);
drawable.draw(canvas);
if (bottomClip != 0) {
canvas.restore();
}
}
} else if (drawable instanceof ColorDrawable) {
if (bottomClip != 0) {
canvas.save();
canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight() - bottomClip);
}
drawable.setBounds(0, 0, getMeasuredWidth(), getRootView().getMeasuredHeight());
drawable.draw(canvas);
checkSnowflake(canvas);
if (bottomClip != 0) {
canvas.restore();
}
} else if (drawable instanceof GradientDrawable) {
if (bottomClip != 0) {
canvas.save();
canvas.clipRect(0, 0, getMeasuredWidth(), getRootView().getMeasuredHeight() - bottomClip);
}
drawable.setBounds(0, backgroundTranslationY, getMeasuredWidth(), backgroundTranslationY + getRootView().getMeasuredHeight());
drawable.draw(canvas);
checkSnowflake(canvas);
if (bottomClip != 0) {
canvas.restore();
}
} else if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
if (bitmapDrawable.getTileModeX() == Shader.TileMode.REPEAT) {
canvas.save();
float scale = 2.0f / AndroidUtilities.density;
canvas.scale(scale, scale);
drawable.setBounds(0, 0, (int) Math.ceil(getMeasuredWidth() / scale), (int) Math.ceil(getRootView().getMeasuredHeight() / scale));
drawable.draw(canvas);
checkSnowflake(canvas);
canvas.restore();
} else {
int actionBarHeight = (isActionBarVisible() ? ActionBar.getCurrentActionBarHeight() : 0) + (Build.VERSION.SDK_INT >= 21 && occupyStatusBar ? AndroidUtilities.statusBarHeight : 0);
int viewHeight = getRootView().getMeasuredHeight() - actionBarHeight;
float scaleX = (float) getMeasuredWidth() / (float) drawable.getIntrinsicWidth();
float scaleY = (float) (viewHeight) / (float) drawable.getIntrinsicHeight();
float scale = Math.max(scaleX, scaleY);
int width = (int) Math.ceil(drawable.getIntrinsicWidth() * scale * parallaxScale);
int height = (int) Math.ceil(drawable.getIntrinsicHeight() * scale * parallaxScale);
int x = (getMeasuredWidth() - width) / 2 + (int) translationX;
int y = backgroundTranslationY + (viewHeight - height) / 2 + actionBarHeight + (int) translationY;
canvas.save();
canvas.clipRect(0, actionBarHeight, width, getMeasuredHeight() - bottomClip);
drawable.setBounds(x, y, x + width, y + height);
drawable.draw(canvas);
checkSnowflake(canvas);
canvas.restore();
}
}
if (a == 0 && oldBackgroundDrawable != null && themeAnimationValue >= 1.0f) {
oldBackgroundDrawable = null;
backgroundView.invalidate();
}
}
}
};
addView(backgroundView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT));
2022-08-12 17:23:51 +02:00
checkLayerType();
2015-05-21 23:27:27 +02:00
}
2019-01-23 18:03:33 +01:00
public void setBackgroundImage(Drawable bitmap, boolean motion) {
2021-06-25 02:43:10 +02:00
if (backgroundDrawable == bitmap) {
return;
}
if (bitmap instanceof MotionBackgroundDrawable) {
MotionBackgroundDrawable motionBackgroundDrawable = (MotionBackgroundDrawable) bitmap;
2022-02-01 14:00:45 +01:00
motionBackgroundDrawable.setParentView(backgroundView);
2021-06-25 02:43:10 +02:00
}
2015-05-21 23:27:27 +02:00
backgroundDrawable = bitmap;
2019-01-23 18:03:33 +01:00
if (motion) {
if (parallaxEffect == null) {
parallaxEffect = new WallpaperParallaxEffect(getContext());
2021-06-25 02:43:10 +02:00
parallaxEffect.setCallback((offsetX, offsetY, angle) -> {
2019-01-23 18:03:33 +01:00
translationX = offsetX;
translationY = offsetY;
2021-06-25 02:43:10 +02:00
bgAngle = angle;
2022-02-01 14:00:45 +01:00
backgroundView.invalidate();
2019-01-23 18:03:33 +01:00
});
if (getMeasuredWidth() != 0 && getMeasuredHeight() != 0) {
parallaxScale = parallaxEffect.getScale(getMeasuredWidth(), getMeasuredHeight());
}
}
2019-02-08 03:30:32 +01:00
if (!paused) {
parallaxEffect.setEnabled(true);
}
2019-01-23 18:03:33 +01:00
} else if (parallaxEffect != null) {
parallaxEffect.setEnabled(false);
parallaxEffect = null;
2019-02-08 03:30:32 +01:00
parallaxScale = 1.0f;
2019-01-23 18:03:33 +01:00
translationX = 0;
translationY = 0;
}
2022-02-01 14:00:45 +01:00
backgroundView.invalidate();
2022-08-12 17:23:51 +02:00
checkLayerType();
}
private void checkLayerType() {
2022-08-13 19:17:20 +02:00
// if (parallaxEffect == null && backgroundDrawable instanceof MotionBackgroundDrawable && SharedConfig.getDevicePerformanceClass() == SharedConfig.PERFORMANCE_CLASS_HIGH) {
// backgroundView.setLayerType(LAYER_TYPE_HARDWARE, null);
// } else {
// backgroundView.setLayerType(LAYER_TYPE_NONE, null);
// }
2022-02-01 14:00:45 +01:00
}
2015-05-21 23:27:27 +02:00
public Drawable getBackgroundImage() {
return backgroundDrawable;
}
2015-06-29 19:12:11 +02:00
public void setDelegate(SizeNotifierFrameLayoutDelegate delegate) {
2015-05-21 23:27:27 +02:00
this.delegate = delegate;
}
2018-07-30 04:07:02 +02:00
public void setOccupyStatusBar(boolean value) {
occupyStatusBar = value;
}
2019-01-23 18:03:33 +01:00
public void onPause() {
if (parallaxEffect != null) {
parallaxEffect.setEnabled(false);
}
2019-02-08 03:30:32 +01:00
paused = true;
2019-01-23 18:03:33 +01:00
}
public void onResume() {
if (parallaxEffect != null) {
parallaxEffect.setEnabled(true);
}
2019-02-08 03:30:32 +01:00
paused = false;
2019-01-23 18:03:33 +01:00
}
2015-05-21 23:27:27 +02:00
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
notifyHeightChanged();
}
public int measureKeyboardHeight() {
2015-06-29 19:12:11 +02:00
View rootView = getRootView();
getWindowVisibleDisplayFrame(rect);
2019-08-22 01:53:26 +02:00
if (rect.bottom == 0 && rect.top == 0) {
return 0;
}
2015-06-29 19:12:11 +02:00
int usableViewHeight = rootView.getHeight() - (rect.top != 0 ? AndroidUtilities.statusBarHeight : 0) - AndroidUtilities.getViewInset(rootView);
2020-04-24 11:21:58 +02:00
return keyboardHeight = Math.max(0, usableViewHeight - (rect.bottom - rect.top));
2015-06-29 19:12:11 +02:00
}
public int getKeyboardHeight() {
return keyboardHeight;
}
2015-05-21 23:27:27 +02:00
public void notifyHeightChanged() {
2019-07-18 15:01:39 +02:00
if (parallaxEffect != null) {
parallaxScale = parallaxEffect.getScale(getMeasuredWidth(), getMeasuredHeight());
}
2015-05-21 23:27:27 +02:00
if (delegate != null) {
keyboardHeight = measureKeyboardHeight();
2015-05-21 23:27:27 +02:00
final boolean isWidthGreater = AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y;
2019-01-23 18:03:33 +01:00
post(() -> {
if (delegate != null) {
delegate.onSizeChanged(keyboardHeight, isWidthGreater);
2015-05-21 23:27:27 +02:00
}
});
}
}
2015-06-29 19:12:11 +02:00
public void setBottomClip(int value) {
2022-02-01 14:00:45 +01:00
if (value != bottomClip) {
bottomClip = value;
backgroundView.invalidate();
}
2015-06-29 19:12:11 +02:00
}
2020-02-13 19:26:53 +01:00
public void setBackgroundTranslation(int translation) {
2022-02-01 14:00:45 +01:00
if (translation != backgroundTranslationY) {
backgroundTranslationY = translation;
backgroundView.invalidate();
}
2020-02-13 19:26:53 +01:00
}
2021-06-25 02:43:10 +02:00
public int getBackgroundTranslationY() {
if (backgroundDrawable instanceof MotionBackgroundDrawable) {
if (animationInProgress) {
return (int) emojiOffset;
} else if (emojiHeight != 0) {
return emojiHeight;
}
return backgroundTranslationY;
}
return 0;
}
public int getBackgroundSizeY() {
int offset = 0;
if (backgroundDrawable instanceof MotionBackgroundDrawable) {
MotionBackgroundDrawable motionBackgroundDrawable = (MotionBackgroundDrawable) backgroundDrawable;
if (!motionBackgroundDrawable.hasPattern()) {
if (animationInProgress) {
offset = (int) emojiOffset;
} else if (emojiHeight != 0) {
offset = emojiHeight;
} else {
offset = backgroundTranslationY;
}
} else {
offset = backgroundTranslationY != 0 ? 0 : -keyboardHeight;
}
}
return getMeasuredHeight() - offset;
}
2019-12-31 14:08:08 +01:00
public int getHeightWithKeyboard() {
2020-04-24 11:21:58 +02:00
return keyboardHeight + getMeasuredHeight();
2019-12-31 14:08:08 +01:00
}
2021-06-25 02:43:10 +02:00
public void setEmojiKeyboardHeight(int height) {
2022-03-11 17:49:54 +01:00
if (emojiHeight != height) {
emojiHeight = height;
backgroundView.invalidate();
}
2021-06-25 02:43:10 +02:00
}
public void setEmojiOffset(boolean animInProgress, float offset) {
2022-03-11 17:49:54 +01:00
if (emojiOffset != offset || animationInProgress != animInProgress) {
emojiOffset = offset;
animationInProgress = animInProgress;
backgroundView.invalidate();
}
2021-06-25 02:43:10 +02:00
}
2021-12-30 11:52:40 +01:00
private void checkSnowflake(Canvas canvas) {
2022-01-18 21:51:58 +01:00
if (Theme.canStartHolidayAnimation()) {
2021-12-30 11:52:40 +01:00
if (snowflakesEffect == null) {
snowflakesEffect = new SnowflakesEffect(1);
}
snowflakesEffect.onDraw(this, canvas);
}
}
2017-03-31 01:58:05 +02:00
protected boolean isActionBarVisible() {
return true;
}
2020-09-30 15:48:47 +02:00
protected AdjustPanLayoutHelper createAdjustPanLayoutHelper() {
return null;
}
2021-08-31 21:06:39 +02:00
public void setSkipBackgroundDrawing(boolean skipBackgroundDrawing) {
2022-02-01 14:00:45 +01:00
if (this.skipBackgroundDrawing != skipBackgroundDrawing) {
this.skipBackgroundDrawing = skipBackgroundDrawing;
backgroundView.invalidate();
}
2021-08-31 21:06:39 +02:00
}
2021-09-20 07:54:41 +02:00
protected Drawable getNewDrawable() {
return Theme.getCachedWallpaperNonBlocking();
}
@Override
protected boolean verifyDrawable(Drawable who) {
return who == getBackgroundImage() || super.verifyDrawable(who);
}
2022-01-18 21:51:58 +01:00
2022-02-01 14:00:45 +01:00
final BlurBackgroundTask blurBackgroundTask = new BlurBackgroundTask();
2022-01-18 21:51:58 +01:00
public void startBlur() {
if (!blurIsRunning || blurGeneratingTuskIsRunning || !invalidateBlur || !SharedConfig.chatBlurEnabled()) {
return;
}
2022-03-11 17:49:54 +01:00
2022-02-01 14:00:45 +01:00
int blurAlpha = Color.alpha(Theme.getColor(Theme.key_chat_BlurAlpha));
2022-03-11 17:49:54 +01:00
if (blurAlpha == 255) {
2022-02-01 14:00:45 +01:00
return;
}
2022-01-18 21:51:58 +01:00
int lastW = getMeasuredWidth();
int lastH = ActionBar.getCurrentActionBarHeight() + AndroidUtilities.statusBarHeight + AndroidUtilities.dp(100);
2022-03-11 17:49:54 +01:00
if (lastW == 0 || lastH == 0) {
return;
}
// TODO uncomment for support saturation in blur
// if (this.saturation != BlurSettingsBottomSheet.saturation) {
// this.saturation = BlurSettingsBottomSheet.saturation;
// ColorMatrix colorMatrix = new ColorMatrix();
// colorMatrix.setSaturation(saturation * 5);
// blurPaintTop.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
// blurPaintTop2.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
// blurPaintBottom.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
// blurPaintBottom2.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
// }
invalidateBlur = false;
blurGeneratingTuskIsRunning = true;
2022-01-18 21:51:58 +01:00
2022-03-11 17:49:54 +01:00
int bitmapH = (int) (lastH / DOWN_SCALE) + TOP_CLIP_OFFSET;
2022-01-18 21:51:58 +01:00
int bitmapW = (int) (lastW / DOWN_SCALE);
2022-02-01 14:00:45 +01:00
long time = System.currentTimeMillis();
2022-01-18 21:51:58 +01:00
BlurBitmap bitmap = null;
if (unusedBitmaps.size() > 0) {
bitmap = unusedBitmaps.remove(unusedBitmaps.size() - 1);
}
if (bitmap == null) {
bitmap = new BlurBitmap();
bitmap.topBitmap = Bitmap.createBitmap(bitmapW, bitmapH, Bitmap.Config.ARGB_8888);
bitmap.topCanvas = new Canvas(bitmap.topBitmap);
2022-03-11 17:49:54 +01:00
if (needBlurBottom) {
bitmap.bottomBitmap = Bitmap.createBitmap(bitmapW, bitmapH, Bitmap.Config.ARGB_8888);
bitmap.bottomCanvas = new Canvas(bitmap.bottomBitmap);
}
} else {
bitmap.topBitmap.eraseColor(Color.TRANSPARENT);
if (bitmap.bottomBitmap != null) {
bitmap.bottomBitmap.eraseColor(Color.TRANSPARENT);
}
2022-01-18 21:51:58 +01:00
}
BlurBitmap finalBitmap = bitmap;
float sX = (float) finalBitmap.topBitmap.getWidth() / (float) lastW;
2022-02-01 14:00:45 +01:00
float sY = (float) (finalBitmap.topBitmap.getHeight() - TOP_CLIP_OFFSET) / (float) lastH;
2022-01-18 21:51:58 +01:00
finalBitmap.topCanvas.save();
2022-03-11 17:49:54 +01:00
finalBitmap.pixelFixOffset = getScrollOffset() % (int) (DOWN_SCALE * 2);
2022-02-01 14:00:45 +01:00
2022-03-11 17:49:54 +01:00
finalBitmap.topCanvas.clipRect(1, 10 * sY, finalBitmap.topBitmap.getWidth(), finalBitmap.topBitmap.getHeight() - 1);
2022-01-18 21:51:58 +01:00
finalBitmap.topCanvas.scale(sX, sY);
2022-02-01 14:00:45 +01:00
finalBitmap.topCanvas.translate(0, 10 * sY + finalBitmap.pixelFixOffset);
2022-01-18 21:51:58 +01:00
finalBitmap.topScaleX = 1f / sX;
finalBitmap.topScaleY = 1f / sY;
drawList(finalBitmap.topCanvas, true);
finalBitmap.topCanvas.restore();
2022-03-11 17:49:54 +01:00
if (needBlurBottom) {
sX = (float) finalBitmap.bottomBitmap.getWidth() / (float) lastW;
sY = (float) (finalBitmap.bottomBitmap.getHeight() - TOP_CLIP_OFFSET) / (float) lastH;
finalBitmap.needBlurBottom = true;
finalBitmap.bottomOffset = getBottomOffset() - lastH;
finalBitmap.drawnLisetTranslationY = getBottomOffset();
finalBitmap.bottomCanvas.save();
finalBitmap.bottomCanvas.clipRect(1, 10 * sY, finalBitmap.bottomBitmap.getWidth(), finalBitmap.bottomBitmap.getHeight() - 1);
finalBitmap.bottomCanvas.scale(sX, sY);
finalBitmap.bottomCanvas.translate(0, 10 * sY - finalBitmap.bottomOffset + finalBitmap.pixelFixOffset);
finalBitmap.bottomScaleX = 1f / sX;
finalBitmap.bottomScaleY = 1f / sY;
drawList(finalBitmap.bottomCanvas, false);
finalBitmap.bottomCanvas.restore();
} else {
finalBitmap.needBlurBottom = false;
}
2022-01-18 21:51:58 +01:00
2022-02-01 14:00:45 +01:00
times2 += System.currentTimeMillis() - time;
count2++;
if (count2 >= 20) {
count2 = 0;
times2 = 0;
}
2022-01-18 21:51:58 +01:00
if (blurQueue == null) {
blurQueue = new DispatchQueue("BlurQueue");
}
2022-03-11 17:49:54 +01:00
blurBackgroundTask.radius = (int) ((int) (Math.max(6, Math.max(lastH, lastW) / 180) * 2.5f) * BlurSettingsBottomSheet.blurRadius);
2022-02-01 14:00:45 +01:00
blurBackgroundTask.finalBitmap = finalBitmap;
blurQueue.postRunnable(blurBackgroundTask);
}
private class BlurBackgroundTask implements Runnable {
int radius;
BlurBitmap finalBitmap;
@Override
public void run() {
long time = System.currentTimeMillis();
2022-03-11 17:49:54 +01:00
2022-02-01 14:00:45 +01:00
Utilities.stackBlurBitmap(finalBitmap.topBitmap, radius);
2022-03-11 17:49:54 +01:00
if (finalBitmap.needBlurBottom && finalBitmap.bottomBitmap != null) {
Utilities.stackBlurBitmap(finalBitmap.bottomBitmap, radius);
}
2022-02-01 14:00:45 +01:00
times += System.currentTimeMillis() - time;
count++;
if (count > 1000) {
FileLog.d("chat blur generating average time" + (times / (float) count));
count = 0;
times = 0;
}
2022-01-18 21:51:58 +01:00
2022-02-01 14:00:45 +01:00
AndroidUtilities.runOnUIThread(() -> {
2022-03-13 02:58:00 +01:00
if (!blurIsRunning) {
if (finalBitmap != null) {
finalBitmap.recycle();
}
blurGeneratingTuskIsRunning = false;
return;
}
2022-02-01 14:00:45 +01:00
prevBitmap = currentBitmap;
BlurBitmap oldBitmap = currentBitmap;
blurPaintTop2.setShader(blurPaintTop.getShader());
blurPaintBottom2.setShader(blurPaintBottom.getShader());
2022-01-18 21:51:58 +01:00
2022-02-01 14:00:45 +01:00
BitmapShader bitmapShader = new BitmapShader(finalBitmap.topBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
blurPaintTop.setShader(bitmapShader);
2022-01-18 21:51:58 +01:00
2022-03-11 17:49:54 +01:00
if (finalBitmap.needBlurBottom && finalBitmap.bottomBitmap != null) {
bitmapShader = new BitmapShader(finalBitmap.bottomBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
blurPaintBottom.setShader(bitmapShader);
}
2022-01-18 21:51:58 +01:00
2022-02-01 14:00:45 +01:00
if (blurCrossfade != null) {
blurCrossfade.cancel();
}
2022-03-11 17:49:54 +01:00
blurCrossfadeProgress = 0;
2022-02-01 14:00:45 +01:00
blurCrossfade = ValueAnimator.ofFloat(0, 1f);
blurCrossfade.addUpdateListener(valueAnimator -> {
blurCrossfadeProgress = (float) valueAnimator.getAnimatedValue();
2022-03-11 17:49:54 +01:00
invalidateBlurredViews();
2022-01-18 21:51:58 +01:00
});
2022-02-01 14:00:45 +01:00
blurCrossfade.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
blurCrossfadeProgress = 1f;
unusedBitmaps.add(oldBitmap);
2022-03-11 17:49:54 +01:00
blurPaintTop2.setShader(null);
blurPaintBottom2.setShader(null);
invalidateBlurredViews();
2022-02-01 14:00:45 +01:00
super.onAnimationEnd(animation);
}
});
blurCrossfade.setDuration(50);
blurCrossfade.start();
2022-03-11 17:49:54 +01:00
invalidateBlurredViews();
2022-02-01 14:00:45 +01:00
currentBitmap = finalBitmap;
AndroidUtilities.runOnUIThread(() -> {
blurGeneratingTuskIsRunning = false;
startBlur();
2022-03-11 17:49:54 +01:00
}, 16);
2022-02-01 14:00:45 +01:00
});
}
2022-03-11 17:49:54 +01:00
}
public void invalidateBlurredViews() {
for (int i = 0; i < blurBehindViews.size(); i++) {
blurBehindViews.get(i).invalidate();
}
}
2022-01-18 21:51:58 +01:00
protected float getBottomOffset() {
return getMeasuredHeight();
}
2022-03-11 17:49:54 +01:00
protected float getListTranslationY() {
return 0f;
}
2022-01-18 21:51:58 +01:00
protected Theme.ResourcesProvider getResourceProvider() {
return null;
}
protected void drawList(Canvas blurCanvas, boolean top) {
}
protected int getScrollOffset() {
return 0;
}
@Override
protected void dispatchDraw(Canvas canvas) {
if (blurIsRunning) {
startBlur();
}
super.dispatchDraw(canvas);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (needBlur && !blurIsRunning) {
blurIsRunning = true;
invalidateBlur = true;
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
blurPaintTop.setShader(null);
blurPaintTop2.setShader(null);
blurPaintBottom.setShader(null);
blurPaintBottom2.setShader(null);
if (blurCrossfade != null) {
blurCrossfade.cancel();
}
if (currentBitmap != null) {
currentBitmap.recycle();
currentBitmap = null;
}
for (int i = 0; i < unusedBitmaps.size(); i++) {
if (unusedBitmaps.get(i) != null) {
unusedBitmaps.get(i).recycle();
}
}
unusedBitmaps.clear();
blurIsRunning = false;
}
2022-03-20 21:22:37 +01:00
public void drawBlurRect(Canvas canvas, float y, Rect rectTmp, Paint blurScrimPaint, boolean top) {
2022-02-01 14:00:45 +01:00
int blurAlpha = Color.alpha(Theme.getColor(Theme.key_chat_BlurAlpha));
2022-03-11 17:49:54 +01:00
if (currentBitmap == null || !SharedConfig.chatBlurEnabled()) {
2022-01-18 21:51:58 +01:00
canvas.drawRect(rectTmp, blurScrimPaint);
return;
}
2022-03-20 21:22:37 +01:00
updateBlurShaderPosition(y, top);
blurScrimPaint.setAlpha(255);
if (blurCrossfadeProgress != 1f && selectedBlurPaint2.getShader() != null) {
canvas.drawRect(rectTmp, blurScrimPaint);
canvas.drawRect(rectTmp, selectedBlurPaint2);
canvas.saveLayerAlpha(rectTmp.left, rectTmp.top, rectTmp.right, rectTmp.bottom, (int) (blurCrossfadeProgress * 255), Canvas.ALL_SAVE_FLAG);
canvas.drawRect(rectTmp, blurScrimPaint);
canvas.drawRect(rectTmp, selectedBlurPaint);
canvas.restore();
} else {
canvas.drawRect(rectTmp, blurScrimPaint);
canvas.drawRect(rectTmp, selectedBlurPaint);
}
blurScrimPaint.setAlpha(blurAlpha);
canvas.drawRect(rectTmp, blurScrimPaint);
}
public void drawBlurCircle(Canvas canvas, float viewY, float cx, float cy, float radius, Paint blurScrimPaint, boolean top) {
int blurAlpha = Color.alpha(Theme.getColor(Theme.key_chat_BlurAlpha));
if (currentBitmap == null || !SharedConfig.chatBlurEnabled()) {
canvas.drawCircle(cx, cy, radius, blurScrimPaint);
return;
}
updateBlurShaderPosition(viewY, top);
blurScrimPaint.setAlpha(255);
if (blurCrossfadeProgress != 1f && selectedBlurPaint2.getShader() != null) {
canvas.drawCircle(cx, cy, radius, blurScrimPaint);
canvas.drawCircle(cx, cy, radius, selectedBlurPaint2);
canvas.saveLayerAlpha(cx - radius, cy - radius, cx + radius, cy + radius, (int) (blurCrossfadeProgress * 255), Canvas.ALL_SAVE_FLAG);
canvas.drawCircle(cx, cy, radius, blurScrimPaint);
canvas.drawCircle(cx, cy, radius, selectedBlurPaint);
canvas.restore();
} else {
canvas.drawCircle(cx, cy, radius, blurScrimPaint);
canvas.drawCircle(cx, cy, radius, selectedBlurPaint);
}
blurScrimPaint.setAlpha(blurAlpha);
canvas.drawCircle(cx, cy, radius, blurScrimPaint);
}
2022-01-18 21:51:58 +01:00
2022-03-20 21:22:37 +01:00
private void updateBlurShaderPosition(float viewY, boolean top) {
selectedBlurPaint = top ? blurPaintTop : blurPaintBottom;
selectedBlurPaint2 = top ? blurPaintTop2 : blurPaintBottom2;
if (top) {
viewY += getTranslationY();
}
if (selectedBlurPaint.getShader() != null) {
2022-01-18 21:51:58 +01:00
matrix.reset();
2022-02-01 14:00:45 +01:00
matrix2.reset();
2022-01-18 21:51:58 +01:00
if (!top) {
2022-03-20 21:22:37 +01:00
float y1 = -viewY + currentBitmap.bottomOffset - currentBitmap.pixelFixOffset - TOP_CLIP_OFFSET - (currentBitmap.drawnLisetTranslationY - (getBottomOffset() + getListTranslationY()));
2022-03-11 17:49:54 +01:00
matrix.setTranslate(0, y1);
2022-01-18 21:51:58 +01:00
matrix.preScale(currentBitmap.bottomScaleX, currentBitmap.bottomScaleY);
2022-02-01 14:00:45 +01:00
if (prevBitmap != null) {
2022-03-20 21:22:37 +01:00
y1 = -viewY + prevBitmap.bottomOffset - prevBitmap.pixelFixOffset - TOP_CLIP_OFFSET - (prevBitmap.drawnLisetTranslationY - (getBottomOffset() + getListTranslationY()));
2022-03-11 17:49:54 +01:00
matrix2.setTranslate(0, y1);
2022-02-01 14:00:45 +01:00
matrix2.preScale(prevBitmap.bottomScaleX, prevBitmap.bottomScaleY);
}
2022-01-18 21:51:58 +01:00
} else {
2022-03-20 21:22:37 +01:00
matrix.setTranslate(0, -viewY - currentBitmap.pixelFixOffset - TOP_CLIP_OFFSET);
2022-01-18 21:51:58 +01:00
matrix.preScale(currentBitmap.topScaleX, currentBitmap.topScaleY);
2022-02-01 14:00:45 +01:00
if (prevBitmap != null) {
2022-03-20 21:22:37 +01:00
matrix2.setTranslate(0, -viewY - prevBitmap.pixelFixOffset - TOP_CLIP_OFFSET);
2022-03-11 17:49:54 +01:00
matrix2.preScale(prevBitmap.topScaleX, prevBitmap.topScaleY);
2022-02-01 14:00:45 +01:00
}
}
2022-01-18 21:51:58 +01:00
2022-03-20 21:22:37 +01:00
selectedBlurPaint.getShader().setLocalMatrix(matrix);
if (selectedBlurPaint2.getShader() != null) {
selectedBlurPaint2.getShader().setLocalMatrix(matrix);
2022-01-18 21:51:58 +01:00
}
}
}
2022-03-11 17:49:54 +01:00
protected float getBottomTranslation() {
return 0;
}
2022-01-18 21:51:58 +01:00
private static class BlurBitmap {
2022-03-11 17:49:54 +01:00
public boolean needBlurBottom;
2022-01-18 21:51:58 +01:00
int pixelFixOffset;
Canvas topCanvas;
Bitmap topBitmap;
float topScaleX, topScaleY;
float bottomScaleX, bottomScaleY;
float bottomOffset;
2022-03-11 17:49:54 +01:00
float drawnLisetTranslationY;
2022-01-18 21:51:58 +01:00
Canvas bottomCanvas;
Bitmap bottomBitmap;
public void recycle() {
topBitmap.recycle();
2022-03-11 17:49:54 +01:00
if (bottomBitmap != null) {
bottomBitmap.recycle();
}
2022-01-18 21:51:58 +01:00
}
}
2015-05-21 23:27:27 +02:00
}