NekoX/TMessagesProj/src/main/java/org/telegram/ui/Components/voip/GroupCallMiniTextureView.java

1790 lines
82 KiB
Java

package org.telegram.ui.Components.voip;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffColorFilter;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.ColorUtils;
import org.telegram.messenger.AccountInstance;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.BuildVars;
import org.telegram.messenger.ChatObject;
import org.telegram.messenger.ImageLoader;
import org.telegram.messenger.ImageLocation;
import org.telegram.messenger.ImageReceiver;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MessageObject;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.R;
import org.telegram.messenger.UserConfig;
import org.telegram.messenger.UserObject;
import org.telegram.messenger.Utilities;
import org.telegram.messenger.voip.Instance;
import org.telegram.messenger.voip.VideoCapturerDevice;
import org.telegram.messenger.voip.VoIPService;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ActionBar.SimpleTextView;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Components.AvatarDrawable;
import org.telegram.ui.Components.BlobDrawable;
import org.telegram.ui.Components.CrossOutDrawable;
import org.telegram.ui.Components.CubicBezierInterpolator;
import org.telegram.ui.Components.GroupCallFullscreenAdapter;
import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.Components.MotionBackgroundDrawable;
import org.telegram.ui.Components.RLottieImageView;
import org.telegram.ui.Components.RecyclerListView;
import org.telegram.ui.GroupCallActivity;
import org.webrtc.GlGenericDrawer;
import org.webrtc.RendererCommon;
import java.util.ArrayList;
@SuppressLint("ViewConstructor")
public class GroupCallMiniTextureView extends FrameLayout implements GroupCallStatusIcon.Callback {
public final VoIPTextureView textureView;
public boolean showingInFullscreen;
public GroupCallGridCell primaryView;
public GroupCallFullscreenAdapter.GroupCallUserCell secondaryView;
public GroupCallGridCell tabletGridView;
public boolean animateToScrimView;
private boolean showingAsScrimView;
boolean isFullscreenMode;
public boolean animateToFullscreen;
private boolean updateNextLayoutAnimated;
boolean attached;
public ChatObject.VideoParticipant participant;
GroupCallRenderersContainer parentContainer;
ArrayList<GroupCallMiniTextureView> attachedRenderers;
Paint gradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
LinearGradient gradientShader;
boolean animateEnter;
ChatObject.Call call;
GroupCallActivity activity;
boolean useSpanSize;
float spanCount;
int gridItemsCount;
FrameLayout infoContainer;
int currentAccount;
private final SimpleTextView nameView;
private int lastSize;
private TextView stopSharingTextView;
public boolean forceDetached;
private boolean invalidateFromChild;
private boolean checkScale;
float progressToSpeaking;
Paint speakingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final RLottieImageView micIconView;
private final ImageView screencastIcon;
public boolean hasVideo;
public float progressToNoVideoStub = 1f;
private NoVideoStubLayout noVideoStubLayout;
ValueAnimator noVideoStubAnimator;
private boolean lastLandscapeMode;
float pinchScale;
float pinchCenterX;
float pinchCenterY;
float pinchTranslationX;
float pinchTranslationY;
boolean inPinchToZoom;
private float progressToBackground;
ImageReceiver imageReceiver = new ImageReceiver();
ArrayList<Runnable> onFirstFrameRunnables = new ArrayList<>();
private GroupCallStatusIcon statusIcon;
private boolean swipeToBack;
private float swipeToBackDy;
Bitmap thumb;
Paint thumbPaint;
private boolean videoIsPaused;
private float videoIsPausedProgress;
private CrossOutDrawable pausedVideoDrawable;
private Drawable castingScreenDrawable;
float overlayIconAlpha;
ImageView blurredFlippingStub;
public boolean drawFirst;
public GroupCallMiniTextureView(GroupCallRenderersContainer parentContainer, ArrayList<GroupCallMiniTextureView> attachedRenderers, ChatObject.Call call, GroupCallActivity activity) {
super(parentContainer.getContext());
this.call = call;
this.currentAccount = activity.getCurrentAccount();
pausedVideoDrawable = new CrossOutDrawable(parentContainer.getContext(), R.drawable.calls_video, null);
pausedVideoDrawable.setCrossOut(true, false);
pausedVideoDrawable.setOffsets(-AndroidUtilities.dp(4), AndroidUtilities.dp(6), AndroidUtilities.dp(6));
pausedVideoDrawable.setStrokeWidth(AndroidUtilities.dpf2(3.4f));
castingScreenDrawable = parentContainer.getContext().getResources().getDrawable(R.drawable.screencast_big).mutate();
TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
textPaint.setTextSize(AndroidUtilities.dp(13));
textPaint.setColor(Color.WHITE);
TextPaint textPaint2 = new TextPaint(Paint.ANTI_ALIAS_FLAG);
textPaint2.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
textPaint2.setTextSize(AndroidUtilities.dp(15));
textPaint2.setColor(Color.WHITE);
String videoOnPauseString = LocaleController.getString("VoipVideoOnPause", R.string.VoipVideoOnPause);
StaticLayout staticLayout = new StaticLayout(LocaleController.getString("VoipVideoScreenSharingTwoLines", R.string.VoipVideoScreenSharingTwoLines), textPaint, AndroidUtilities.dp(400), Layout.Alignment.ALIGN_CENTER, 1.0f, 0, false);
TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(call.chatId);
String text = LocaleController.formatPluralString("Participants", MessagesController.getInstance(currentAccount).groipCallVideoMaxParticipants);
StaticLayout noVideoLayout = new StaticLayout(LocaleController.formatString("VoipVideoNotAvailable", R.string.VoipVideoNotAvailable, text), textPaint, AndroidUtilities.dp(400), Layout.Alignment.ALIGN_CENTER, 1.0f, 0, false);
String sharingScreenString = LocaleController.getString("VoipVideoScreenSharing", R.string.VoipVideoScreenSharing);
float textW = textPaint.measureText(videoOnPauseString);
float textW3 = textPaint2.measureText(sharingScreenString);
this.textureView = new VoIPTextureView(parentContainer.getContext(), false, false, true, true) {
float overlayIconAlphaFrom;
@Override
public void animateToLayout() {
super.animateToLayout();
overlayIconAlphaFrom = overlayIconAlpha;
}
@Override
protected void updateRendererSize() {
super.updateRendererSize();
if (blurredFlippingStub != null && blurredFlippingStub.getParent() != null) {
blurredFlippingStub.getLayoutParams().width = textureView.renderer.getMeasuredWidth();
blurredFlippingStub.getLayoutParams().height = textureView.renderer.getMeasuredHeight();
}
}
@Override
protected void dispatchDraw(Canvas canvas) {
if (!renderer.isFirstFrameRendered() || (renderer.getAlpha() != 1f && blurRenderer.getAlpha() != 1f) || videoIsPaused) {
if (progressToBackground != 1f) {
progressToBackground += 16f / 150f;
if (progressToBackground > 1f) {
progressToBackground = 1f;
} else {
invalidate();
}
}
if (thumb != null) {
canvas.save();
canvas.scale(currentThumbScale, currentThumbScale, getMeasuredWidth() / 2f, getMeasuredHeight() / 2f);
if (thumbPaint == null) {
thumbPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
thumbPaint.setFilterBitmap(true);
}
canvas.drawBitmap(thumb, (getMeasuredWidth() - thumb.getWidth()) / 2f, (getMeasuredHeight() - thumb.getHeight()) / 2f, thumbPaint);
canvas.restore();
} else {
imageReceiver.setImageCoords(currentClipHorizontal, currentClipVertical, getMeasuredWidth() - currentClipHorizontal * 2, getMeasuredHeight() - currentClipVertical * 2);
imageReceiver.setAlpha(progressToBackground);
imageReceiver.draw(canvas);
}
if (participant == call.videoNotAvailableParticipant) {
if (showingInFullscreen || !parentContainer.inFullscreenMode) {
float iconSize = AndroidUtilities.dp(48);
float x = (getMeasuredWidth() - iconSize) / 2f;
float y = getMeasuredHeight() / 2 - iconSize;
textPaint.setAlpha(255);
canvas.save();
canvas.translate(x - AndroidUtilities.dp(400) / 2f + iconSize / 2f, y + iconSize + AndroidUtilities.dp(10));
noVideoLayout.draw(canvas);
canvas.restore();
}
if (stopSharingTextView.getVisibility() != INVISIBLE) {
stopSharingTextView.setVisibility(INVISIBLE);
}
} else if (participant.presentation && participant.participant.self) {
if (stopSharingTextView.getVisibility() != VISIBLE) {
stopSharingTextView.setVisibility(VISIBLE);
stopSharingTextView.setScaleX(1.0f);
stopSharingTextView.setScaleY(1.0f);
}
float progressToFullscreen = drawFirst ? 0 : parentContainer.progressToFullscreenMode;
int size = AndroidUtilities.dp(33);
if (animateToFullscreen || showingInFullscreen) {
size += (AndroidUtilities.dp(10) + AndroidUtilities.dp(39) * parentContainer.progressToFullscreenMode);
} else {
size += AndroidUtilities.dp(10) * (1.0f - parentContainer.progressToFullscreenMode);
}
int x = (getMeasuredWidth() - size) / 2;
float smallProgress;
float scrimProgress = (showingAsScrimView || animateToScrimView ? parentContainer.progressToScrimView : 0);
if (showingInFullscreen) {
smallProgress = progressToFullscreen;
} else {
smallProgress = animateToFullscreen ? parentContainer.progressToFullscreenMode : scrimProgress;
}
int y = (int) ((getMeasuredHeight() - size) / 2 - AndroidUtilities.dp(11) - (AndroidUtilities.dp(17) + AndroidUtilities.dp(74) * parentContainer.progressToFullscreenMode) * smallProgress);
castingScreenDrawable.setBounds(x, y, x + size, y + size);
castingScreenDrawable.draw(canvas);
if (parentContainer.progressToFullscreenMode > 0 || scrimProgress > 0) {
float alpha = Math.max(parentContainer.progressToFullscreenMode, scrimProgress) * smallProgress;
textPaint2.setAlpha((int) (255 * alpha));
if (animateToFullscreen || showingInFullscreen) {
stopSharingTextView.setAlpha(alpha * (1.0f - scrimProgress));
} else {
stopSharingTextView.setAlpha(0.0f);
}
canvas.drawText(sharingScreenString, x - textW3 / 2f + size / 2f, y + size + AndroidUtilities.dp(32), textPaint2);
} else {
stopSharingTextView.setAlpha(0.0f);
}
stopSharingTextView.setTranslationY(y + size + AndroidUtilities.dp(72) + swipeToBackDy - currentClipVertical);
stopSharingTextView.setTranslationX((getMeasuredWidth() - stopSharingTextView.getMeasuredWidth()) / 2 - currentClipHorizontal);
if (parentContainer.progressToFullscreenMode < 1 && scrimProgress < 1) {
textPaint.setAlpha((int) (255 * (1.0 - Math.max(parentContainer.progressToFullscreenMode, scrimProgress))));
canvas.save();
canvas.translate(x - AndroidUtilities.dp(400) / 2f + size / 2f, y + size + AndroidUtilities.dp(10));
staticLayout.draw(canvas);
canvas.restore();
}
} else {
if (stopSharingTextView.getVisibility() != INVISIBLE) {
stopSharingTextView.setVisibility(INVISIBLE);
}
activity.cellFlickerDrawable.draw(canvas, GroupCallMiniTextureView.this);
}
invalidate();
}
if (blurredFlippingStub != null && blurredFlippingStub.getParent() != null) {
blurredFlippingStub.setScaleX(textureView.renderer.getScaleX());
blurredFlippingStub.setScaleY(textureView.renderer.getScaleY());
}
super.dispatchDraw(canvas);
float y = getMeasuredHeight() - currentClipVertical - AndroidUtilities.dp(80);
if (participant != call.videoNotAvailableParticipant) {
canvas.save();
if ((showingInFullscreen || animateToFullscreen) && !GroupCallActivity.isLandscapeMode && !GroupCallActivity.isTabletMode) {
y -= AndroidUtilities.dp(90) * parentContainer.progressToFullscreenMode * (1f - parentContainer.progressToHideUi);
}
canvas.translate(0, y);
canvas.drawPaint(gradientPaint);
canvas.restore();
}
if (videoIsPaused || videoIsPausedProgress != 0) {
if (videoIsPaused && videoIsPausedProgress != 1f) {
videoIsPausedProgress += 16 / 250f;
if (videoIsPausedProgress > 1f) {
videoIsPausedProgress = 1f;
} else {
invalidate();
}
} else if (!videoIsPaused && videoIsPausedProgress != 0f) {
videoIsPausedProgress -= 16 / 250f;
if (videoIsPausedProgress < 0f) {
videoIsPausedProgress = 0f;
} else {
invalidate();
}
}
float a = videoIsPausedProgress;
a *= (isInAnimation() ? (overlayIconAlphaFrom * (1f - animationProgress) + overlayIconAlpha * animationProgress) : overlayIconAlpha);
if (a > 0) {
float iconSize = AndroidUtilities.dp(48);
float x = (getMeasuredWidth() - iconSize) / 2f;
y = (getMeasuredHeight() - iconSize) / 2f;
if (participant == call.videoNotAvailableParticipant) {
y -= iconSize / 2.5f;
}
AndroidUtilities.rectTmp.set((int) x, (int) y, (int) (x + iconSize), (int) (y + iconSize));
if (a != 1) {
canvas.saveLayerAlpha(AndroidUtilities.rectTmp, (int) (255 * a), Canvas.ALL_SAVE_FLAG);
} else {
canvas.save();
}
pausedVideoDrawable.setBounds((int) AndroidUtilities.rectTmp.left, (int) AndroidUtilities.rectTmp.top, (int) AndroidUtilities.rectTmp.right, (int) AndroidUtilities.rectTmp.bottom);
pausedVideoDrawable.draw(canvas);
canvas.restore();
a *= parentContainer.progressToFullscreenMode;
if (a > 0 && participant != call.videoNotAvailableParticipant) {
textPaint.setAlpha((int) (255 * a));
canvas.drawText(videoOnPauseString, x - textW / 2f + iconSize / 2f, y + iconSize + AndroidUtilities.dp(16), textPaint);
}
}
}
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
if (inPinchToZoom && child == textureView.renderer) {
canvas.save();
canvas.scale(pinchScale, pinchScale, pinchCenterX, pinchCenterY);
canvas.translate(pinchTranslationX, pinchTranslationY);
boolean b = super.drawChild(canvas, child, drawingTime);
canvas.restore();
return b;
}
return super.drawChild(canvas, child, drawingTime);
}
@Override
public void invalidate() {
super.invalidate();
invalidateFromChild = true;
GroupCallMiniTextureView.this.invalidate();
invalidateFromChild = false;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (attached && checkScale && renderer.rotatedFrameHeight != 0 && renderer.rotatedFrameWidth != 0) {
if (showingAsScrimView) {
textureView.scaleType = SCALE_TYPE_FIT;
} else if (showingInFullscreen) {
textureView.scaleType = SCALE_TYPE_FIT;
} else if (parentContainer.inFullscreenMode && !showingInFullscreen) {
textureView.scaleType = SCALE_TYPE_FILL;
} else if (!parentContainer.inFullscreenMode) {
textureView.scaleType = participant.presentation ? SCALE_TYPE_FIT : SCALE_TYPE_ADAPTIVE;
} else {
textureView.scaleType = SCALE_TYPE_FIT;
}
checkScale = false;
}
super.onLayout(changed, left, top, right, bottom);
if (renderer.rotatedFrameHeight != 0 && renderer.rotatedFrameWidth != 0 && participant != null) {
participant.setAspectRatio(renderer.rotatedFrameWidth / (float) renderer.rotatedFrameHeight, call);
}
}
@Override
public void requestLayout() {
GroupCallMiniTextureView.this.requestLayout();
super.requestLayout();
}
@Override
protected void onFirstFrameRendered() {
invalidate();
if (!videoIsPaused) {
if (renderer.getAlpha() != 1f) {
renderer.animate().setDuration(300).alpha(1f);
}
}
if (blurRenderer != null && blurRenderer.getAlpha() != 1f) {
blurRenderer.animate().setDuration(300).alpha(1f);
}
if (blurredFlippingStub != null && blurredFlippingStub.getParent() != null) {
if (blurredFlippingStub.getAlpha() == 1f) {
blurredFlippingStub.animate().alpha(0f).setDuration(300).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (blurredFlippingStub.getParent() != null) {
textureView.removeView(blurredFlippingStub);
}
}
}).start();
} else {
if (blurredFlippingStub.getParent() != null) {
textureView.removeView(blurredFlippingStub);
}
}
}
}
};
textureView.renderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT);
this.parentContainer = parentContainer;
this.attachedRenderers = attachedRenderers;
this.activity = activity;
textureView.renderer.init(VideoCapturerDevice.getEglBase().getEglBaseContext(), new RendererCommon.RendererEvents() {
@Override
public void onFirstFrameRendered() {
for (int i = 0; i < onFirstFrameRunnables.size(); i++) {
AndroidUtilities.cancelRunOnUIThread(onFirstFrameRunnables.get(i));
onFirstFrameRunnables.get(i).run();
}
onFirstFrameRunnables.clear();
}
@Override
public void onFrameResolutionChanged(int videoWidth, int videoHeight, int rotation) {
}
});
textureView.attachBackgroundRenderer();
setClipChildren(false);
textureView.renderer.setAlpha(0f);
addView(textureView);
noVideoStubLayout = new NoVideoStubLayout(getContext());
addView(noVideoStubLayout);
nameView = new SimpleTextView(parentContainer.getContext());
nameView.setTextSize(13);
nameView.setTextColor(ColorUtils.setAlphaComponent(Color.WHITE, (int) (255 * 0.9f)));
nameView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
nameView.setFullTextMaxLines(1);
nameView.setBuildFullLayout(true);
infoContainer = new FrameLayout(parentContainer.getContext());
infoContainer.addView(nameView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | Gravity.LEFT, 32, 0, 8, 0));
addView(infoContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 32));
speakingPaint.setStyle(Paint.Style.STROKE);
speakingPaint.setStrokeWidth(AndroidUtilities.dp(2));
speakingPaint.setColor(Theme.getColor(Theme.key_voipgroup_speakingText));
infoContainer.setClipChildren(false);
micIconView = new RLottieImageView(parentContainer.getContext());
addView(micIconView, LayoutHelper.createFrame(24, 24, 0, 4, 6, 4, 0));
screencastIcon = new ImageView(parentContainer.getContext());
addView(screencastIcon, LayoutHelper.createFrame(24, 24, 0, 4, 6, 4, 0));
screencastIcon.setPadding(AndroidUtilities.dp(4), AndroidUtilities.dp(4), AndroidUtilities.dp(4), AndroidUtilities.dp(4));
screencastIcon.setImageDrawable(ContextCompat.getDrawable(parentContainer.getContext(), R.drawable.voicechat_screencast));
screencastIcon.setColorFilter(new PorterDuffColorFilter(Color.WHITE, PorterDuff.Mode.MULTIPLY));
final Drawable rippleDrawable = Theme.createSimpleSelectorRoundRectDrawable(AndroidUtilities.dp(19), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Color.WHITE, 100));
stopSharingTextView = new TextView(parentContainer.getContext()) {
@Override
public boolean onTouchEvent(MotionEvent event) {
if (Math.abs(stopSharingTextView.getAlpha() - 1.0f) > 0.001f) {
return false;
}
return super.onTouchEvent(event);
}
};
stopSharingTextView.setText(LocaleController.getString("VoipVideoScreenStopSharing", R.string.VoipVideoScreenStopSharing));
stopSharingTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
stopSharingTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
stopSharingTextView.setPadding(AndroidUtilities.dp(21), 0, AndroidUtilities.dp(21), 0);
stopSharingTextView.setTextColor(0xffffffff);
stopSharingTextView.setBackground(rippleDrawable);
stopSharingTextView.setGravity(Gravity.CENTER);
stopSharingTextView.setOnClickListener(v -> {
if (VoIPService.getSharedInstance() != null) {
VoIPService.getSharedInstance().stopScreenCapture();
}
stopSharingTextView.animate().alpha(0.0f).scaleX(0.0f).scaleY(0.0f).setDuration(180).start();
});
addView(stopSharingTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 38, Gravity.LEFT | Gravity.TOP));
}
private Rect rect = new Rect();
public boolean isInsideStopScreenButton(float x, float y) {
stopSharingTextView.getHitRect(rect);
return rect.contains((int) x, (int) y);
}
@Override
protected void dispatchDraw(Canvas canvas) {
if (attached) {
float y = textureView.getY() + textureView.getMeasuredHeight() - textureView.currentClipVertical - infoContainer.getMeasuredHeight();
y += swipeToBackDy;
if (showingAsScrimView || animateToScrimView) {
infoContainer.setAlpha(1f - parentContainer.progressToScrimView);
micIconView.setAlpha(1f - parentContainer.progressToScrimView);
} else if (showingInFullscreen || animateToFullscreen) {
if (!GroupCallActivity.isLandscapeMode && !GroupCallActivity.isTabletMode) {
y -= AndroidUtilities.dp(90) * parentContainer.progressToFullscreenMode * (1f - parentContainer.progressToHideUi);
}
infoContainer.setAlpha(1f);
micIconView.setAlpha(1f);
} else if (secondaryView != null) {
infoContainer.setAlpha(1f - parentContainer.progressToFullscreenMode);
micIconView.setAlpha(1f - parentContainer.progressToFullscreenMode);
} else {
infoContainer.setAlpha(1f);
micIconView.setAlpha(1f);
}
if (showingInFullscreen || animateToFullscreen) {
nameView.setFullAlpha(parentContainer.progressToFullscreenMode);
} else {
nameView.setFullAlpha(0f);
}
micIconView.setTranslationX(infoContainer.getX());
micIconView.setTranslationY(y - AndroidUtilities.dp(2));
if (screencastIcon.getVisibility() == View.VISIBLE) {
screencastIcon.setTranslationX(textureView.getMeasuredWidth() - 2 * textureView.currentClipHorizontal - AndroidUtilities.dp(32));
screencastIcon.setTranslationY(y - AndroidUtilities.dp(2));
screencastIcon.setAlpha(Math.min(1f - parentContainer.progressToFullscreenMode, 1f - parentContainer.progressToScrimView));
}
infoContainer.setTranslationY(y);
infoContainer.setTranslationX(drawFirst ? 0 : AndroidUtilities.dp(6) * parentContainer.progressToFullscreenMode);
}
super.dispatchDraw(canvas);
if (attached) {
if (statusIcon != null) {
if (statusIcon.isSpeaking && progressToSpeaking != 1f) {
progressToSpeaking += 16f / 300f;
if (progressToSpeaking > 1f) {
progressToSpeaking = 1f;
} else {
invalidate();
}
} else if (!statusIcon.isSpeaking && progressToSpeaking != 0) {
progressToSpeaking -= 16f / 300f;
if (progressToSpeaking < 0) {
progressToSpeaking = 0;
} else {
invalidate();
}
}
}
float selectionProgress = progressToSpeaking * (1f - parentContainer.progressToFullscreenMode) * (1f - parentContainer.progressToScrimView);
if (progressToSpeaking > 0) {
speakingPaint.setAlpha((int) (255 * selectionProgress));
float scale = 0.9f + 0.1f * Math.max(0, 1f - Math.abs(swipeToBackDy) / AndroidUtilities.dp(300));
canvas.save();
AndroidUtilities.rectTmp.set(textureView.getX() + textureView.currentClipHorizontal, textureView.getY() + textureView.currentClipVertical, textureView.getX() + textureView.getMeasuredWidth() - textureView.currentClipHorizontal, textureView.getY() + textureView.getMeasuredHeight() - textureView.currentClipVertical);
canvas.scale(scale, scale, AndroidUtilities.rectTmp.centerX(), AndroidUtilities.rectTmp.centerY());
canvas.translate(0, swipeToBackDy);
canvas.drawRoundRect(AndroidUtilities.rectTmp, textureView.roundRadius, textureView.roundRadius, speakingPaint);
canvas.restore();
}
}
}
public void getRenderBufferBitmap(GlGenericDrawer.TextureCallback callback) {
textureView.renderer.getRenderBufferBitmap(callback);
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
if (swipeToBack && (child == textureView || child == noVideoStubLayout)) {
float scale = 0.9f + 0.1f * Math.max(0, 1f - Math.abs(swipeToBackDy) / AndroidUtilities.dp(300));
canvas.save();
canvas.scale(scale, scale, child.getX() + child.getMeasuredWidth() / 2f, child.getY() + child.getMeasuredHeight() / 2f);
canvas.translate(0, swipeToBackDy);
boolean b = super.drawChild(canvas, child, drawingTime);
canvas.restore();
return b;
}
return super.drawChild(canvas, child, drawingTime);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
FrameLayout.LayoutParams layoutParams = (LayoutParams) infoContainer.getLayoutParams();
int lastLeft = layoutParams.leftMargin;
float nameScale = 1f;
if (lastLandscapeMode != GroupCallActivity.isLandscapeMode) {
checkScale = true;
lastLandscapeMode = GroupCallActivity.isLandscapeMode;
}
layoutParams.leftMargin = layoutParams.rightMargin = AndroidUtilities.dp(2);
if (updateNextLayoutAnimated) {
nameView.animate().scaleX(nameScale).scaleY(nameScale).start();
micIconView.animate().scaleX(nameScale).scaleY(nameScale).start();
} else {
nameView.animate().cancel();
nameView.setScaleX(nameScale);
nameView.setScaleY(nameScale);
micIconView.animate().cancel();
micIconView.setScaleX(nameScale);
micIconView.setScaleY(nameScale);
infoContainer.animate().cancel();
}
updateNextLayoutAnimated = false;
if (showingInFullscreen) {
updateSize(0);
overlayIconAlpha = 1f;
if (GroupCallActivity.isTabletMode) {
int w = MeasureSpec.getSize(widthMeasureSpec);
w -= AndroidUtilities.dp(GroupCallActivity.TABLET_LIST_SIZE + 8);
int h = MeasureSpec.getSize(heightMeasureSpec);
h -= AndroidUtilities.dp(4);
super.onMeasure(MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY));
} else if (!GroupCallActivity.isLandscapeMode) {
int h = MeasureSpec.getSize(heightMeasureSpec);
h -= AndroidUtilities.dp(92);
super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY));
} else {
int w = MeasureSpec.getSize(widthMeasureSpec);
w -= AndroidUtilities.dp(92);
super.onMeasure(MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY));
}
} else if (showingAsScrimView) {
overlayIconAlpha = 1f;
int size = Math.min(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)) - AndroidUtilities.dp(14) * 2;
super.onMeasure(MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(size + getPaddingBottom(), MeasureSpec.EXACTLY));
} else if (useSpanSize) {
overlayIconAlpha = 1f;
int spanCountTotal;
if (GroupCallActivity.isTabletMode && tabletGridView != null) {
spanCountTotal = 6;
} else {
spanCountTotal = GroupCallActivity.isLandscapeMode ? 6 : 2;
}
float listSize;
if (tabletGridView != null) {
listSize = MeasureSpec.getSize(widthMeasureSpec) - AndroidUtilities.dp(GroupCallActivity.TABLET_LIST_SIZE + 16 + 8);
} else if (GroupCallActivity.isTabletMode) {
listSize = AndroidUtilities.dp(GroupCallActivity.TABLET_LIST_SIZE);
} else {
listSize = MeasureSpec.getSize(widthMeasureSpec) - AndroidUtilities.dp(14) * 2 + (GroupCallActivity.isLandscapeMode ? -AndroidUtilities.dp(90) : 0);
}
float w = listSize * (spanCount / (float) spanCountTotal);
float h;
if (tabletGridView != null) {
h = tabletGridView.getItemHeight() - AndroidUtilities.dp(4);
w -= AndroidUtilities.dp(4);
} else {
if (GroupCallActivity.isTabletMode) {
h = listSize / 2f;
} else {
h = listSize / (float) (GroupCallActivity.isLandscapeMode ? 3 : 2);
}
w -= AndroidUtilities.dp(2);
}
float layoutContainerW = w;
layoutParams = (LayoutParams) infoContainer.getLayoutParams();
if (screencastIcon.getVisibility() == View.VISIBLE) {
layoutContainerW -= AndroidUtilities.dp(28);
}
updateSize((int) layoutContainerW);
layoutParams.width = (int) (layoutContainerW - layoutParams.leftMargin * 2);
super.onMeasure(MeasureSpec.makeMeasureSpec((int) w, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) h, MeasureSpec.EXACTLY));
} else {
overlayIconAlpha = 0f;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
int size = MeasureSpec.getSize(heightMeasureSpec) + (MeasureSpec.getSize(widthMeasureSpec) << 16);
if (lastSize != size) {
lastSize = size;
gradientShader = new LinearGradient(0, 0, 0, AndroidUtilities.dp(120), Color.TRANSPARENT, ColorUtils.setAlphaComponent(Color.BLACK, 120), Shader.TileMode.CLAMP);
gradientPaint.setShader(gradientShader);
}
nameView.setPivotX(0);
nameView.setPivotY(nameView.getMeasuredHeight() / 2f);
}
public static GroupCallMiniTextureView getOrCreate(ArrayList<GroupCallMiniTextureView> attachedRenderers, GroupCallRenderersContainer renderersContainer, GroupCallGridCell primaryView, GroupCallFullscreenAdapter.GroupCallUserCell secondaryView, GroupCallGridCell tabletGridView, ChatObject.VideoParticipant participant, ChatObject.Call call, GroupCallActivity activity) {
GroupCallMiniTextureView renderer = null;
for (int i = 0; i < attachedRenderers.size(); i++) {
if (participant.equals(attachedRenderers.get(i).participant)) {
renderer = attachedRenderers.get(i);
break;
}
}
if (renderer == null) {
renderer = new GroupCallMiniTextureView(renderersContainer, attachedRenderers, call, activity);
}
if (primaryView != null) {
renderer.setPrimaryView(primaryView);
}
if (secondaryView != null) {
renderer.setSecondaryView(secondaryView);
}
if (tabletGridView != null) {
renderer.setTabletGridView(tabletGridView);
}
return renderer;
}
public void setTabletGridView(GroupCallGridCell tabletGridView) {
if (this.tabletGridView != tabletGridView) {
this.tabletGridView = tabletGridView;
updateAttachState(true);
}
}
public void setPrimaryView(GroupCallGridCell primaryView) {
if (this.primaryView != primaryView) {
this.primaryView = primaryView;
checkScale = true;
updateAttachState(true);
}
}
public void setSecondaryView(GroupCallFullscreenAdapter.GroupCallUserCell secondaryView) {
if (this.secondaryView != secondaryView) {
this.secondaryView = secondaryView;
checkScale = true;
updateAttachState(true);
}
}
public void setShowingAsScrimView(boolean showing, boolean animated) {
this.showingAsScrimView = showing;
updateAttachState(animated);
}
public void setShowingInFullscreen(boolean showing, boolean animated) {
if (this.showingInFullscreen != showing) {
this.showingInFullscreen = showing;
checkScale = true;
updateAttachState(animated);
}
}
public void setFullscreenMode(boolean fullscreenMode, boolean animated) {
if (isFullscreenMode != fullscreenMode) {
isFullscreenMode = fullscreenMode;
updateAttachState((primaryView != null || tabletGridView != null) && animated);
}
}
public void updateAttachState(boolean animated) {
if (forceDetached) {
return;
}
if (participant == null && (primaryView != null || secondaryView != null || tabletGridView != null)) {
if (primaryView != null) {
participant = primaryView.getParticipant();
} else if (tabletGridView != null) {
participant = tabletGridView.getParticipant();
} else {
participant = secondaryView.getVideoParticipant();
}
}
boolean forceRequestLayout = false;
if (attached && !showingInFullscreen) {
boolean needDetach = VoIPService.getSharedInstance() == null;
if (GroupCallActivity.paused || participant == null || (secondaryView == null && (!ChatObject.Call.videoIsActive(participant.participant, participant.presentation, call) || !call.canStreamVideo && participant != call.videoNotAvailableParticipant))) {
needDetach = true;
}
if (needDetach || (primaryView == null && secondaryView == null && tabletGridView == null) && !showingAsScrimView && !animateToScrimView) {
attached = false;
saveThumb();
if (textureView.currentAnimation == null && needDetach) {
GroupCallMiniTextureView viewToRemove = this;
parentContainer.detach(viewToRemove);
animate().scaleX(0.5f).scaleY(0.5f).alpha(0).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
viewToRemove.setScaleX(1f);
viewToRemove.setScaleY(1f);
viewToRemove.setAlpha(1f);
parentContainer.removeView(viewToRemove);
release();
}
}).setDuration(150).start();
} else {
if (parentContainer.inLayout) {
View viewToRemove = this;
AndroidUtilities.runOnUIThread(() -> parentContainer.removeView(viewToRemove));
} else {
parentContainer.removeView(this);
}
parentContainer.detach(this);
release();
}
if (participant.participant.self) {
if (VoIPService.getSharedInstance() != null) {
VoIPService.getSharedInstance().setLocalSink(null, participant.presentation);
}
} else {
if (VoIPService.getSharedInstance() != null) {
VoIPService.getSharedInstance().removeRemoteSink(participant.participant, participant.presentation);
}
}
invalidate();
if (noVideoStubAnimator != null) {
noVideoStubAnimator.removeAllListeners();
noVideoStubAnimator.cancel();
}
}
} else if (!attached) {
if (VoIPService.getSharedInstance() == null) {
return;
}
if (primaryView != null || secondaryView != null || tabletGridView != null || showingInFullscreen) {
if (primaryView != null) {
participant = primaryView.getParticipant();
} else if (secondaryView != null) {
participant = secondaryView.getVideoParticipant();
} else if (tabletGridView != null) {
participant = tabletGridView.getParticipant();
}
boolean videoActive;
if (participant.participant.self) {
videoActive = VoIPService.getSharedInstance() != null && VoIPService.getSharedInstance().getVideoState(participant.presentation) == Instance.VIDEO_STATE_ACTIVE;
} else {
videoActive = (call.canStreamVideo || participant == call.videoNotAvailableParticipant) && ChatObject.Call.videoIsActive(participant.participant, participant.presentation, call);
}
if (showingInFullscreen || (!VoIPService.getSharedInstance().isFullscreen(participant.participant, participant.presentation) && !VoIPService.getSharedInstance().isFullscreen(participant.participant, participant.presentation) && videoActive)) {
if (BuildVars.DEBUG_PRIVATE_VERSION) {
for (int i = 0; i < attachedRenderers.size(); i++) {
if (attachedRenderers.get(i).participant.equals(participant)) {
throw new RuntimeException("try add two same renderers");
}
}
}
forceRequestLayout = true;
attached = true;
if (activity.statusIconPool.size() > 0) {
statusIcon = activity.statusIconPool.remove(activity.statusIconPool.size() - 1);
} else {
statusIcon = new GroupCallStatusIcon();
}
statusIcon.setCallback(this);
statusIcon.setImageView(micIconView);
updateIconColor(false);
if (getParent() == null) {
parentContainer.addView(this, LayoutHelper.createFrame(46, 46, Gravity.LEFT | Gravity.TOP));
parentContainer.attach(this);
}
checkScale = true;
animateEnter = false;
animate().setListener(null).cancel();
if (textureView.currentAnimation == null && ((secondaryView != null && primaryView == null)) && !hasImage()) {
setScaleX(0.5f);
setScaleY(0.5f);
setAlpha(0);
animateEnter = true;
invalidate();
animate().scaleX(1f).scaleY(1f).alpha(1f).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
animateEnter = false;
invalidate();
}
}).setDuration(100).start();
invalidate();
} else {
setScaleY(1f);
setScaleX(1f);
setAlpha(1f);
}
animated = false;
loadThumb();
screencastIcon.setVisibility(participant.presentation ? VISIBLE : GONE);
}
}
}
if (participant == call.videoNotAvailableParticipant) {
if (nameView.getVisibility() != INVISIBLE) {
nameView.setVisibility(INVISIBLE);
micIconView.setVisibility(INVISIBLE);
}
} else {
if (nameView.getVisibility() != VISIBLE) {
nameView.setVisibility(VISIBLE);
micIconView.setVisibility(VISIBLE);
}
}
if (attached) {
int size;
float spanCount = 1f;
boolean useSpanSize = false;
int gridItemsCount = 0;
boolean useTablet = GroupCallActivity.isTabletMode && (!parentContainer.inFullscreenMode || (secondaryView == null && primaryView == null));
if (showingInFullscreen) {
size = LayoutHelper.MATCH_PARENT;
} else if (secondaryView != null && primaryView == null && !parentContainer.inFullscreenMode) {
size = 0;
} else if (showingAsScrimView) {
size = LayoutHelper.MATCH_PARENT;
} else if (secondaryView != null && primaryView == null) {
size = AndroidUtilities.dp(80);
} else if (tabletGridView != null && useTablet) {
if (tabletGridView != null) {
useSpanSize = true;
size = LayoutHelper.MATCH_PARENT;
spanCount = tabletGridView.spanCount;
gridItemsCount = tabletGridView.gridAdapter.getItemCount();
} else {
size = AndroidUtilities.dp(46);
}
} else if (primaryView != null && secondaryView == null || !isFullscreenMode) {
if (primaryView != null) {
useSpanSize = true;
size = LayoutHelper.MATCH_PARENT;
spanCount = primaryView.spanCount;
} else {
size = AndroidUtilities.dp(46);
}
} else if (primaryView != null) {
size = AndroidUtilities.dp(80);
} else {
size = 0;
}
MarginLayoutParams layoutParams = (MarginLayoutParams) getLayoutParams();
if (size != 0 && (layoutParams.height != size || forceRequestLayout || this.useSpanSize != useSpanSize || (useSpanSize && this.spanCount != spanCount || this.gridItemsCount != gridItemsCount))) {
layoutParams.height = size;
layoutParams.width = useSpanSize ? LayoutHelper.MATCH_PARENT : size;
this.useSpanSize = useSpanSize;
this.spanCount = spanCount;
checkScale = true;
if (animated) {
textureView.animateToLayout();
updateNextLayoutAnimated = true;
} else {
textureView.requestLayout();
}
AndroidUtilities.runOnUIThread(this::requestLayout);
parentContainer.requestLayout();
invalidate();
}
if (participant.participant.self && !participant.presentation && VoIPService.getSharedInstance() != null) {
textureView.renderer.setMirror(VoIPService.getSharedInstance().isFrontFaceCamera());
textureView.renderer.setRotateTextureWitchScreen(true);
textureView.renderer.setUseCameraRotation(true);
} else {
textureView.renderer.setMirror(false);
textureView.renderer.setRotateTextureWitchScreen(true);
textureView.renderer.setUseCameraRotation(false);
}
textureView.updateRotation();
if (participant.participant.self) {
textureView.renderer.setMaxTextureSize(720);
} else {
textureView.renderer.setMaxTextureSize(0);
}
boolean hasVideoLocal = true;
if (!ChatObject.Call.videoIsActive(participant.participant, participant.presentation, call) || !call.canStreamVideo && participant != call.videoNotAvailableParticipant) {
noVideoStubLayout.avatarImageReceiver.setCurrentAccount(currentAccount);
int peerId = MessageObject.getPeerId(participant.participant.peer);
ImageLocation imageLocation;
ImageLocation thumbLocation;
Object parentObject;
if (peerId > 0) {
TLRPC.User currentUser = AccountInstance.getInstance(currentAccount).getMessagesController().getUser(peerId);
noVideoStubLayout.avatarDrawable.setInfo(currentUser);
imageLocation = ImageLocation.getForUser(currentUser, ImageLocation.TYPE_BIG);
thumbLocation = ImageLocation.getForUser(currentUser, ImageLocation.TYPE_SMALL);
parentObject = currentUser;
} else {
TLRPC.Chat currentChat = AccountInstance.getInstance(UserConfig.selectedAccount).getMessagesController().getChat(-peerId);
noVideoStubLayout.avatarDrawable.setInfo(currentChat);
imageLocation = ImageLocation.getForChat(currentChat, ImageLocation.TYPE_BIG);
thumbLocation = ImageLocation.getForChat(currentChat, ImageLocation.TYPE_SMALL);
parentObject = currentChat;
}
Drawable thumb = noVideoStubLayout.avatarDrawable;
if (thumbLocation != null) {
BitmapDrawable drawable = ImageLoader.getInstance().getImageFromMemory(thumbLocation.location, null, "50_50");
if (drawable != null) {
thumb = drawable;
}
}
noVideoStubLayout.avatarImageReceiver.setImage(imageLocation, null, thumb, null, parentObject, 0);
noVideoStubLayout.backgroundImageReceiver.setImage(imageLocation, "50_50_b", new ColorDrawable(Theme.getColor(Theme.key_voipgroup_listViewBackground)), null, parentObject, 0);
hasVideoLocal = false;
}
boolean skipNoStubTransition = animated && secondaryView != null && !showingInFullscreen && !hasVideoLocal;
if (hasVideoLocal != hasVideo && !skipNoStubTransition) {
hasVideo = hasVideoLocal;
if (noVideoStubAnimator != null) {
noVideoStubAnimator.removeAllListeners();
noVideoStubAnimator.cancel();
}
if (animated) {
if (!hasVideo && noVideoStubLayout.getVisibility() != View.VISIBLE) {
noVideoStubLayout.setVisibility(View.VISIBLE);
noVideoStubLayout.setAlpha(0);
}
noVideoStubAnimator = ValueAnimator.ofFloat(progressToNoVideoStub, hasVideo ? 0 : 1f);
noVideoStubAnimator.addUpdateListener(valueAnimator1 -> {
progressToNoVideoStub = (float) valueAnimator1.getAnimatedValue();
noVideoStubLayout.setAlpha(progressToNoVideoStub);
textureView.invalidate();
});
noVideoStubAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
progressToNoVideoStub = hasVideo ? 0f : 1f;
noVideoStubLayout.setAlpha(progressToNoVideoStub);
noVideoStubLayout.setVisibility(hasVideo ? View.GONE : View.VISIBLE);
textureView.invalidate();
}
});
noVideoStubAnimator.start();
} else {
progressToNoVideoStub = hasVideo ? 0f : 1f;
noVideoStubLayout.setVisibility(hasVideo ? View.GONE : View.VISIBLE);
noVideoStubLayout.setAlpha(progressToNoVideoStub);
textureView.invalidate();
}
if (hasVideo) {
noVideoStubLayout.updateMuteButtonState(false);
}
}
if (participant.participant.self && VoIPService.getSharedInstance() != null) {
VoIPService.getSharedInstance().setLocalSink(textureView.renderer, participant.presentation);
}
statusIcon.setParticipant(participant.participant, animated);
if (noVideoStubLayout.getVisibility() == View.VISIBLE) {
noVideoStubLayout.updateMuteButtonState(true);
}
boolean pausedInternal = false;
if (participant.participant.video != null && participant.participant.video.paused) {
pausedInternal = true;
}
if (videoIsPaused != pausedInternal) {
videoIsPaused = pausedInternal;
textureView.renderer.animate().alpha(videoIsPaused ? 0 : 1f).setDuration(250).start();
textureView.invalidate();
}
if (GroupCallActivity.paused || !hasVideo) {
if (participant.participant.self) {
if (VoIPService.getSharedInstance() != null) {
VoIPService.getSharedInstance().setLocalSink(null, participant.presentation);
}
} else if (VoIPService.getSharedInstance() != null) {
VoIPService.getSharedInstance().removeRemoteSink(participant.participant, participant.presentation);
VoIPService.getSharedInstance().removeRemoteSink(participant.participant, participant.presentation);
}
if (GroupCallActivity.paused && textureView.renderer.isFirstFrameRendered()) {
saveThumb();
textureView.renderer.clearFirstFrame();
textureView.renderer.setAlpha(0f);
textureView.blurRenderer.setAlpha(0f);
}
} else {
if (!textureView.renderer.isFirstFrameRendered()) {
loadThumb();
}
if (participant.participant.self) {
if (VoIPService.getSharedInstance() != null) {
VoIPService.getSharedInstance().setLocalSink(textureView.renderer, participant.presentation);
}
} else if (VoIPService.getSharedInstance() != null) {
VoIPService.getSharedInstance().addRemoteSink(participant.participant, participant.presentation, textureView.renderer, null);
VoIPService.getSharedInstance().addRemoteSink(participant.participant, participant.presentation, textureView.renderer, null);
}
}
}
updateInfo();
}
private void loadThumb() {
if (thumb != null) {
return;
}
thumb = call.thumbs.get(participant.presentation ? participant.participant.presentationEndpoint : participant.participant.videoEndpoint);
textureView.setThumb(thumb);
if (thumb == null) {
int peerId = MessageObject.getPeerId(participant.participant.peer);
if (participant.participant.self && participant.presentation) {
imageReceiver.setImageBitmap(new MotionBackgroundDrawable(0xff212E3A, 0xff2B5B4D, 0xff245863, 0xff274558, true));
} else {
if (peerId > 0) {
TLRPC.User user = MessagesController.getInstance(currentAccount).getUser(peerId);
ImageLocation imageLocation = ImageLocation.getForUser(user, ImageLocation.TYPE_SMALL);
int color = user != null ? AvatarDrawable.getColorForId(user.id) : ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.2f);
GradientDrawable gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, new int[]{ColorUtils.blendARGB(color, Color.BLACK, 0.2f), ColorUtils.blendARGB(color, Color.BLACK, 0.4f)});
imageReceiver.setImage(imageLocation, "50_50_b", gradientDrawable, null, user, 0);
} else {
TLRPC.Chat chat = MessagesController.getInstance(currentAccount).getChat(-peerId);
ImageLocation imageLocation = ImageLocation.getForChat(chat, ImageLocation.TYPE_SMALL);
int color = chat != null ? AvatarDrawable.getColorForId(chat.id) : ColorUtils.blendARGB(Color.BLACK, Color.WHITE, 0.2f);
GradientDrawable gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, new int[]{ColorUtils.blendARGB(color, Color.BLACK, 0.2f), ColorUtils.blendARGB(color, Color.BLACK, 0.4f)});
imageReceiver.setImage(imageLocation, "50_50_b", gradientDrawable, null, chat, 0);
}
}
}
}
public void updateInfo() {
if (!attached) {
return;
}
String name = null;
int peerId = MessageObject.getPeerId(participant.participant.peer);
if (peerId > 0) {
TLRPC.User currentUser = AccountInstance.getInstance(currentAccount).getMessagesController().getUser(peerId);
name = UserObject.getUserName(currentUser);
} else {
TLRPC.Chat currentChat = AccountInstance.getInstance(currentAccount).getMessagesController().getChat(-peerId);
if (currentChat != null) {
name = currentChat.title;
}
}
nameView.setText(name);
}
public boolean hasImage() {
return textureView.stubVisibleProgress == 1f;
}
public void updatePosition(ViewGroup listView, ViewGroup tabletGridListView, RecyclerListView fullscreenListView, GroupCallRenderersContainer renderersContainer) {
if (showingAsScrimView || animateToScrimView || forceDetached) {
return;
}
drawFirst = false;
float progressToFullscreen = renderersContainer.progressToFullscreenMode;
if (animateToFullscreen || showingInFullscreen) {
if (primaryView != null || tabletGridView != null) {
GroupCallGridCell callUserCell = tabletGridView != null ? tabletGridView : primaryView;
ViewGroup fromListView = tabletGridView != null ? tabletGridListView : listView;
float fromX = callUserCell.getX() + fromListView.getX() - getLeft() - renderersContainer.getLeft();
float fromY = callUserCell.getY() + AndroidUtilities.dp(2) + fromListView.getY() - getTop() - renderersContainer.getTop();
float toX = 0;
float toY = 0;
setTranslationX(fromX * (1f - progressToFullscreen) + toX * progressToFullscreen);
setTranslationY(fromY * (1f - progressToFullscreen) + toY * progressToFullscreen);
} else {
setTranslationX(0);
setTranslationY(0);
}
textureView.setRoundCorners(AndroidUtilities.dp(8));
if (secondaryView != null) {
secondaryView.setAlpha(progressToFullscreen);
}
if (!showingInFullscreen && primaryView == null && tabletGridView == null) {
setAlpha(progressToFullscreen);
} else if (!animateEnter) {
setAlpha(1f);
}
} else if (secondaryView != null) {
if (secondaryView.isRemoving(fullscreenListView)) {
setAlpha(secondaryView.getAlpha());
} else if (primaryView == null) {
if (attached && !animateEnter) {
setAlpha(progressToFullscreen);
}
secondaryView.setAlpha(progressToFullscreen);
progressToFullscreen = 1f;
} else {
secondaryView.setAlpha(1f);
if (attached && !animateEnter) {
setAlpha(1f);
}
}
setTranslationX(secondaryView.getX() + fullscreenListView.getX() - getLeft());
setTranslationY(AndroidUtilities.dp(2) * (1f - progressToFullscreen) + secondaryView.getY() + fullscreenListView.getY() - getTop());
textureView.setRoundCorners(AndroidUtilities.dp(13) * progressToFullscreen + AndroidUtilities.dp(8) * (1f - progressToFullscreen));
} else if (primaryView != null || tabletGridView != null) {
GroupCallGridCell callUserCell;
ViewGroup fromListView;
if (tabletGridView != null && primaryView != null) {
boolean useTablet = GroupCallActivity.isTabletMode && !parentContainer.inFullscreenMode;
callUserCell = useTablet ? tabletGridView : primaryView;
fromListView = useTablet ? tabletGridListView : listView;
} else {
callUserCell = tabletGridView != null ? tabletGridView : primaryView;
fromListView = tabletGridView != null ? tabletGridListView : listView;
}
setTranslationX(callUserCell.getX() + fromListView.getX() - getLeft() - renderersContainer.getLeft());
setTranslationY(callUserCell.getY() + AndroidUtilities.dp(2) + fromListView.getY() - getTop() - renderersContainer.getTop());
textureView.setRoundCorners(AndroidUtilities.dp(8));
if (attached && !animateEnter) {
if (!GroupCallActivity.isTabletMode) {
drawFirst = true;
setAlpha((1f - progressToFullscreen) * callUserCell.getAlpha());
} else if (primaryView != null && tabletGridView == null) {
setAlpha(progressToFullscreen * callUserCell.getAlpha());
}
}
}
}
public boolean isAttached() {
return attached;
}
public void release() {
textureView.renderer.release();
if (statusIcon != null) {
activity.statusIconPool.add(statusIcon);
statusIcon.setCallback(null);
statusIcon.setImageView(null);
}
statusIcon = null;
}
public boolean isFullyVisible() {
if (showingInFullscreen || animateToFullscreen) {
return false;
}
return attached && textureView.renderer.isFirstFrameRendered() && getAlpha() == 1;
}
public boolean isVisible() {
if (showingInFullscreen || animateToFullscreen) {
return false;
}
return attached && textureView.renderer.isFirstFrameRendered();
}
@Override
public void invalidate() {
super.invalidate();
if (!invalidateFromChild) {
textureView.invalidate();
}
if (primaryView != null) {
primaryView.invalidate();
if (activity.getScrimView() == primaryView) {
activity.getContainerView().invalidate();
}
}
if (secondaryView != null) {
secondaryView.invalidate();
if (secondaryView.getParent() != null) {
((View) secondaryView.getParent()).invalidate();
}
}
if (getParent() != null) {
((View) getParent()).invalidate();
}
}
public void forceDetach(boolean removeSink) {
GroupCallMiniTextureView viewToRemove = this;
forceDetached = true;
attached = false;
parentContainer.detach(viewToRemove);
if (removeSink) {
if (participant.participant.self) {
if (VoIPService.getSharedInstance() != null) {
VoIPService.getSharedInstance().setLocalSink(null, participant.presentation);
}
} else {
if (VoIPService.getSharedInstance() != null) {
VoIPService.getSharedInstance().removeRemoteSink(participant.participant, participant.presentation);
}
}
}
saveThumb();
if (noVideoStubAnimator != null) {
noVideoStubAnimator.removeAllListeners();
noVideoStubAnimator.cancel();
}
textureView.renderer.release();
}
public void saveThumb() {
if (participant != null && textureView.renderer.getMeasuredHeight() != 0 && textureView.renderer.getMeasuredWidth() != 0) {
getRenderBufferBitmap((bitmap, rotation1) -> {
if (bitmap != null && bitmap.getPixel(0, 0) != Color.TRANSPARENT) {
Utilities.stackBlurBitmap(bitmap, Math.max(7, Math.max(bitmap.getWidth(), bitmap.getHeight()) / 180));
AndroidUtilities.runOnUIThread(() -> call.thumbs.put(participant.presentation ? participant.participant.presentationEndpoint : participant.participant.videoEndpoint, bitmap));
}
});
}
}
public void setViews(GroupCallGridCell primaryView, GroupCallFullscreenAdapter.GroupCallUserCell secondaryView, GroupCallGridCell tabletGrid) {
this.primaryView = primaryView;
this.secondaryView = secondaryView;
this.tabletGridView = tabletGrid;
}
public void setAmplitude(double value) {
statusIcon.setAmplitude(value);
noVideoStubLayout.setAmplitude(value);
}
public void setZoom(boolean inPinchToZoom, float pinchScale, float pinchCenterX, float pinchCenterY, float pinchTranslationX, float pinchTranslationY) {
if (this.pinchScale != pinchScale || this.pinchCenterX != pinchCenterX || this.pinchCenterY != pinchCenterY || this.pinchTranslationX != pinchTranslationX || this.pinchTranslationY != pinchTranslationY) {
this.inPinchToZoom = inPinchToZoom;
this.pinchScale = pinchScale;
this.pinchCenterX = pinchCenterX;
this.pinchCenterY = pinchCenterY;
this.pinchTranslationX = pinchTranslationX;
this.pinchTranslationY = pinchTranslationY;
textureView.invalidate();
}
}
public void setSwipeToBack(boolean swipeToBack, float swipeToBackDy) {
if (this.swipeToBack != swipeToBack || this.swipeToBackDy != swipeToBackDy) {
this.swipeToBack = swipeToBack;
this.swipeToBackDy = swipeToBackDy;
textureView.invalidate();
invalidate();
}
}
public void runOnFrameRendered(Runnable runnable) {
if (textureView.renderer.isFirstFrameRendered()) {
runnable.run();
} else {
AndroidUtilities.runOnUIThread(runnable, 250);
onFirstFrameRunnables.add(runnable);
}
}
int lastIconColor;
int animateToColor;
int lastSpeakingFrameColor;
ValueAnimator colorAnimator;
@Override
public void onStatusChanged() {
invalidate();
updateIconColor(true);
if (noVideoStubLayout.getVisibility() == View.VISIBLE) {
noVideoStubLayout.updateMuteButtonState(true);
}
}
private void updateIconColor(boolean animated) {
if (statusIcon == null) {
return;
}
int newColor;
int newSpeakingFrameColor;
if (statusIcon.isMutedByMe()) {
newSpeakingFrameColor = newColor = Theme.getColor(Theme.key_voipgroup_mutedByAdminIcon);
} else if (statusIcon.isSpeaking()) {
newSpeakingFrameColor = newColor = Theme.getColor(Theme.key_voipgroup_speakingText);
} else {
newSpeakingFrameColor = Theme.getColor(Theme.key_voipgroup_speakingText);
newColor = Color.WHITE;
}
if (animateToColor == newColor) {
return;
}
if (colorAnimator != null) {
colorAnimator.removeAllListeners();
colorAnimator.cancel();
}
if (!animated) {
// micIconView.setColorFilter(new PorterDuffColorFilter(animateToColor = lastIconColor = newColor, PorterDuff.Mode.MULTIPLY));
speakingPaint.setColor(lastSpeakingFrameColor = newSpeakingFrameColor);
} else {
int colorFrom = lastIconColor;
int colorFromSpeaking = lastSpeakingFrameColor;
animateToColor = newColor;
colorAnimator = ValueAnimator.ofFloat(0, 1f);
colorAnimator.addUpdateListener(valueAnimator -> {
float v = (float) valueAnimator.getAnimatedValue();
lastIconColor = ColorUtils.blendARGB(colorFrom, newColor, v);
lastSpeakingFrameColor = ColorUtils.blendARGB(colorFromSpeaking, newSpeakingFrameColor, v);
// micIconView.setColorFilter(new PorterDuffColorFilter(lastIconColor, PorterDuff.Mode.MULTIPLY));
speakingPaint.setColor(lastSpeakingFrameColor);
});
colorAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
animateToColor = lastIconColor = newColor;
lastSpeakingFrameColor = newSpeakingFrameColor;
// micIconView.setColorFilter(new PorterDuffColorFilter(lastIconColor, PorterDuff.Mode.MULTIPLY));
speakingPaint.setColor(lastSpeakingFrameColor);
}
});
colorAnimator.start();
}
}
public void runDelayedAnimations() {
for (int i = 0; i < onFirstFrameRunnables.size(); i++) {
onFirstFrameRunnables.get(i).run();
}
onFirstFrameRunnables.clear();
}
int collapseSize;
int fullSize;
public void updateSize(int collapseSize) {
int fullSize = parentContainer.getMeasuredWidth() - AndroidUtilities.dp(6);
if ((this.collapseSize != collapseSize && collapseSize > 0) || (this.fullSize != fullSize && fullSize > 0)) {
if (collapseSize != 0) {
this.collapseSize = collapseSize;
}
if (fullSize != 0) {
this.fullSize = fullSize;
}
nameView.setFullLayoutAdditionalWidth(fullSize - collapseSize, 0);
}
}
private class NoVideoStubLayout extends View {
public ImageReceiver avatarImageReceiver = new ImageReceiver();
public ImageReceiver backgroundImageReceiver = new ImageReceiver();
AvatarDrawable avatarDrawable = new AvatarDrawable();
BlobDrawable tinyWaveDrawable;
BlobDrawable bigWaveDrawable;
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
Paint backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
float amplitude;
float animateToAmplitude;
float animateAmplitudeDiff;
float wavesEnter = 0f;
float cx, cy;
float speakingProgress;
public NoVideoStubLayout(@NonNull Context context) {
super(context);
tinyWaveDrawable = new BlobDrawable(9);
bigWaveDrawable = new BlobDrawable(12);
tinyWaveDrawable.minRadius = AndroidUtilities.dp(76);
tinyWaveDrawable.maxRadius = AndroidUtilities.dp(92);
tinyWaveDrawable.generateBlob();
bigWaveDrawable.minRadius = AndroidUtilities.dp(80);
bigWaveDrawable.maxRadius = AndroidUtilities.dp(95);
bigWaveDrawable.generateBlob();
paint.setColor(ColorUtils.blendARGB(Theme.getColor(Theme.key_voipgroup_listeningText), Theme.getColor(Theme.key_voipgroup_speakingText), speakingProgress));
paint.setAlpha((int) (255 * 0.4f));
backgroundPaint.setColor(ColorUtils.setAlphaComponent(Color.BLACK, (int) (255 * 0.5f)));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
float size = AndroidUtilities.dp(157);
cx = getMeasuredWidth() >> 1;
cy = (getMeasuredHeight() >> 1) + (GroupCallActivity.isLandscapeMode ? 0 : -getMeasuredHeight() * 0.12f);
avatarImageReceiver.setRoundRadius((int) (size / 2f));
avatarImageReceiver.setImageCoords(cx - size / 2, cy - size / 2, size, size);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
AndroidUtilities.rectTmp.set(textureView.getX() + textureView.currentClipHorizontal, textureView.getY() + textureView.currentClipVertical, textureView.getX() + textureView.getMeasuredWidth() - textureView.currentClipHorizontal, textureView.getY() + textureView.getMeasuredHeight() + textureView.currentClipVertical);
backgroundImageReceiver.setImageCoords(AndroidUtilities.rectTmp.left, AndroidUtilities.rectTmp.top, AndroidUtilities.rectTmp.width(), AndroidUtilities.rectTmp.height());
backgroundImageReceiver.setRoundRadius((int) textureView.roundRadius);
backgroundImageReceiver.draw(canvas);
canvas.drawRoundRect(AndroidUtilities.rectTmp, textureView.roundRadius, textureView.roundRadius, backgroundPaint);
if (animateToAmplitude != amplitude) {
amplitude += animateAmplitudeDiff * 16;
if (animateAmplitudeDiff > 0) {
if (amplitude > animateToAmplitude) {
amplitude = animateToAmplitude;
}
} else {
if (amplitude < animateToAmplitude) {
amplitude = animateToAmplitude;
}
}
}
if (switchProgress != 1f) {
if (prevState != null) {
switchProgress += 16 / 220f;
}
if (switchProgress >= 1.0f) {
switchProgress = 1f;
prevState = null;
}
}
float scale = 1f + 0.8f * amplitude;
canvas.save();
canvas.scale(scale, scale, cx, cy);
if (currentState != null) {
currentState.update((int) (cy - AndroidUtilities.dp(100)), (int) (cx - AndroidUtilities.dp(100)), AndroidUtilities.dp(200), 16, amplitude);
}
bigWaveDrawable.update(amplitude, 1f);
tinyWaveDrawable.update(amplitude, 1f);
for (int i = 0; i < 2; i++) {
float alpha;
if (i == 0 && prevState != null) {
paint.setShader(prevState.shader);
alpha = 1f - switchProgress;
} else if (i == 1 && currentState != null) {
paint.setShader(currentState.shader);
alpha = switchProgress;
} else {
continue;
}
paint.setAlpha((int) (76 * alpha));
bigWaveDrawable.draw(cx, cy, canvas, paint);
tinyWaveDrawable.draw(cx, cy, canvas, paint);
}
canvas.restore();
scale = 1f + 0.2f * amplitude;
canvas.save();
canvas.scale(scale, scale, cx, cy);
avatarImageReceiver.draw(canvas);
canvas.restore();
invalidate();
}
private GroupCallActivity.WeavingState[] states = new GroupCallActivity.WeavingState[3];
private GroupCallActivity.WeavingState currentState;
private GroupCallActivity.WeavingState prevState;
int muteButtonState = -1;
private final static int MUTE_BUTTON_STATE_MUTE = 1;
private final static int MUTE_BUTTON_STATE_UNMUTE = 0;
private final static int MUTED_BY_ADMIN = 2;
float switchProgress = 1f;
private void updateMuteButtonState(boolean animated) {
int newButtonState;
if (statusIcon.isMutedByMe() || statusIcon.isMutedByAdmin()) {
newButtonState = MUTED_BY_ADMIN;
} else if (statusIcon.isSpeaking()) {
newButtonState = MUTE_BUTTON_STATE_MUTE;
} else {
newButtonState = MUTE_BUTTON_STATE_UNMUTE;
}
if (newButtonState == muteButtonState) {
return;
}
muteButtonState = newButtonState;
if (states[muteButtonState] == null) {
states[muteButtonState] = new GroupCallActivity.WeavingState(muteButtonState);
if (muteButtonState == MUTED_BY_ADMIN) {
states[muteButtonState].shader = new LinearGradient(0, 400, 400, 0, new int[]{Theme.getColor(Theme.key_voipgroup_mutedByAdminGradient), Theme.getColor(Theme.key_voipgroup_mutedByAdminGradient3), Theme.getColor(Theme.key_voipgroup_mutedByAdminGradient2)}, null, Shader.TileMode.CLAMP);
} else if (muteButtonState == MUTE_BUTTON_STATE_MUTE) {
states[muteButtonState].shader = new RadialGradient(200, 200, 200, new int[]{Theme.getColor(Theme.key_voipgroup_muteButton), Theme.getColor(Theme.key_voipgroup_muteButton3)}, null, Shader.TileMode.CLAMP);
} else {
states[muteButtonState].shader = new RadialGradient(200, 200, 200, new int[]{Theme.getColor(Theme.key_voipgroup_unmuteButton2), Theme.getColor(Theme.key_voipgroup_unmuteButton)}, null, Shader.TileMode.CLAMP);
}
}
if (states[muteButtonState] != currentState) {
prevState = currentState;
currentState = states[muteButtonState];
if (prevState == null || !animated) {
switchProgress = 1;
prevState = null;
} else {
switchProgress = 0;
}
}
invalidate();
}
public void setAmplitude(double value) {
float amplitude = (float) value / 80f;
if (amplitude > 1f) {
amplitude = 1f;
} else if (amplitude < 0) {
amplitude = 0;
}
animateToAmplitude = amplitude;
animateAmplitudeDiff = (animateToAmplitude - this.amplitude) / 200;
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
avatarImageReceiver.onAttachedToWindow();
backgroundImageReceiver.onAttachedToWindow();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
avatarImageReceiver.onDetachedFromWindow();
backgroundImageReceiver.onDetachedFromWindow();
}
}
public String getName() {
int peerId = MessageObject.getPeerId(participant.participant.peer);
if (peerId > 0) {
TLRPC.User currentUser = AccountInstance.getInstance(UserConfig.selectedAccount).getMessagesController().getUser(peerId);
return UserObject.getUserName(currentUser);
} else {
TLRPC.Chat currentChat = AccountInstance.getInstance(UserConfig.selectedAccount).getMessagesController().getChat(-peerId);
return currentChat.title;
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
imageReceiver.onDetachedFromWindow();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
imageReceiver.onAttachedToWindow();
}
ValueAnimator flipAnimator;
boolean flipHalfReached;
public void startFlipAnimation() {
if (flipAnimator != null) {
return;
}
flipHalfReached = false;
if (blurredFlippingStub == null) {
blurredFlippingStub = new ImageView(getContext());
} else {
blurredFlippingStub.animate().cancel();
}
if (textureView.renderer.isFirstFrameRendered()) {
Bitmap bitmap = textureView.blurRenderer.getBitmap(100, 100);
if (bitmap != null) {
Utilities.blurBitmap(bitmap, 3, 1, bitmap.getWidth(), bitmap.getHeight(), bitmap.getRowBytes());
Drawable drawable = new BitmapDrawable(bitmap);
blurredFlippingStub.setBackground(drawable);
}
blurredFlippingStub.setAlpha(0f);
} else {
blurredFlippingStub.setAlpha(1f);
}
if (blurredFlippingStub.getParent() == null) {
textureView.addView(blurredFlippingStub);
}
((LayoutParams) blurredFlippingStub.getLayoutParams()).gravity = Gravity.CENTER;
flipAnimator = ValueAnimator.ofFloat(0, 1f);
flipAnimator.addUpdateListener(valueAnimator -> {
float v = (float) valueAnimator.getAnimatedValue();
float rotation;
boolean halfReached = false;
if (v < 0.5f) {
rotation = v;
} else {
halfReached = true;
rotation = v - 1f;
}
if (halfReached && !flipHalfReached) {
blurredFlippingStub.setAlpha(1f);
flipHalfReached = true;
textureView.renderer.clearImage();
}
rotation *= 180;
blurredFlippingStub.setRotationY(rotation);
textureView.renderer.setRotationY(rotation);
});
flipAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
flipAnimator = null;
textureView.setRotationY(0);
if (!flipHalfReached) {
textureView.renderer.clearImage();
//
}
}
});
flipAnimator.setDuration(400);
flipAnimator.setInterpolator(CubicBezierInterpolator.DEFAULT);
flipAnimator.start();
}
}