/*
 * This is the source code of Telegram for Android v. 5.x.x.
 * It is licensed under GNU GPL v. 2 or later.
 * You should have received a copy of the license in this archive (see LICENSE).
 *
 * Copyright Grishka, 2013-2016.
 */

package org.telegram.ui;

import android.Manifest;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.IntRange;
import androidx.annotation.Keep;
import androidx.annotation.Nullable;
import androidx.palette.graphics.Palette;
import android.text.Editable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.style.CharacterStyle;
import android.text.style.ForegroundColorSpan;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.DecelerateInterpolator;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;

import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.ApplicationLoader;
import org.telegram.messenger.BuildVars;
import org.telegram.messenger.ContactsController;
import org.telegram.messenger.Emoji;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.ImageLocation;
import org.telegram.messenger.ImageReceiver;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.NotificationCenter;
import org.telegram.messenger.R;
import org.telegram.messenger.SendMessagesHelper;
import org.telegram.messenger.SharedConfig;
import org.telegram.messenger.UserConfig;
import org.telegram.messenger.Utilities;
import org.telegram.messenger.voip.EncryptionKeyEmojifier;
import org.telegram.messenger.voip.TgVoip;
import org.telegram.messenger.voip.VoIPBaseService;
import org.telegram.messenger.voip.VoIPService;
import org.telegram.tgnet.TLRPC;
import org.telegram.ui.ActionBar.AlertDialog;
import org.telegram.ui.ActionBar.BottomSheet;
import org.telegram.ui.ActionBar.DarkAlertDialog;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.Components.BackgroundGradientDrawable;
import org.telegram.ui.Components.BackupImageView;
import org.telegram.ui.Components.CorrectlyMeasuringTextView;
import org.telegram.ui.Components.CubicBezierInterpolator;
import org.telegram.ui.Components.EditTextBoldCursor;
import org.telegram.ui.Components.IdenticonDrawable;
import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.Components.voip.CallSwipeView;
import org.telegram.ui.Components.voip.CheckableImageView;
import org.telegram.ui.Components.voip.DarkTheme;
import org.telegram.ui.Components.voip.FabBackgroundDrawable;
import org.telegram.ui.Components.voip.VoIPHelper;

import java.io.ByteArrayOutputStream;

public class VoIPActivity extends Activity implements VoIPService.StateListener, NotificationCenter.NotificationCenterDelegate {

    private int currentAccount = -1;
    private static final String TAG = "tg-voip-ui";
    private TextView stateText, nameText, stateText2;
    private TextView durationText;
    private TextView brandingText;
    private View endBtn, acceptBtn, declineBtn, endBtnIcon, cancelBtn;
    private CheckableImageView spkToggle, micToggle;
    private ImageView chatBtn, addMemberBtn;
    private FabBackgroundDrawable endBtnBg;
    private CallSwipeView acceptSwipe, declineSwipe;
    private LinearLayout swipeViewsWrap;
    private BackupImageView photoView;
    private boolean isIncomingWaiting;
    private boolean firstStateChange = true;
    private Animator currentDeclineAnim, currentAcceptAnim, textChangingAnim;
    private TLRPC.User user;
    private boolean didAcceptFromHere = false;
    private int callState;
    private TextAlphaSpan[] ellSpans;
    private AnimatorSet ellAnimator;
    private String lastStateText;
    private ImageView[] keyEmojiViews = new ImageView[4];
    private boolean keyEmojiVisible;
    private AnimatorSet emojiAnimator;
    private TextView hintTextView;
    private Animator tooltipAnim;
    private Runnable tooltipHider;
    private LinearLayout emojiWrap;
    boolean emojiTooltipVisible;
    boolean emojiExpanded;
    private Bitmap blurredPhoto1, blurredPhoto2;
    private ImageView blurOverlayView1, blurOverlayView2;
    private TextView emojiExpandedText;
    private FrameLayout content;
    private boolean retrying;
    private AnimatorSet retryAnim;
    private int signalBarsCount;
    private SignalBarsDrawable signalBarsDrawable;
    private LinearLayout bottomButtons;
    private TextView accountNameText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
        super.onCreate(savedInstanceState);

        if (VoIPService.getSharedInstance() == null) {
            finish();
            return;
        }

        currentAccount = VoIPService.getSharedInstance().getAccount();
        if (currentAccount == -1) {
            finish();
            return;
        }

        if ((getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) < Configuration.SCREENLAYOUT_SIZE_LARGE) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }

        View contentView;
        setContentView(contentView = createContentView());

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
            getWindow().setStatusBarColor(0);
            getWindow().setNavigationBarColor(0);
            getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
        }

        user = VoIPService.getSharedInstance().getUser();
        if (user.photo != null) {
            photoView.getImageReceiver().setDelegate(new ImageReceiver.ImageReceiverDelegate() {
                @Override
                public void didSetImage(ImageReceiver imageReceiver, boolean set, boolean thumb, boolean memCache) {
                    ImageReceiver.BitmapHolder bmp = imageReceiver.getBitmapSafe();
                    if (bmp != null) {
                        updateBlurredPhotos(bmp);
                    }
                }
            });
            photoView.setImage(ImageLocation.getForUser(user, true), null, new ColorDrawable(0xFF000000), user);
            photoView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
        } else {
            photoView.setVisibility(View.GONE);
            final BackgroundGradientDrawable gradientDrawable = new BackgroundGradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[]{0xFF1b354e, 0xFF255b7d});
            final BackgroundGradientDrawable.Sizes sizes = BackgroundGradientDrawable.Sizes.ofDeviceScreen(BackgroundGradientDrawable.Sizes.Orientation.PORTRAIT);
            gradientDrawable.startDithering(sizes, new BackgroundGradientDrawable.ListenerAdapter() {
                @Override
                public void onAllSizesReady() {
                    contentView.invalidate();
                }
            });
            contentView.setBackground(gradientDrawable);
        }

        getWindow().setBackgroundDrawable(new ColorDrawable(0));
        setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);

        nameText.setOnClickListener(new View.OnClickListener() {
            private int tapCount = 0;

            @Override
            public void onClick(View v) {
                if (BuildVars.DEBUG_VERSION || tapCount == 9) {
                    showDebugAlert();
                    tapCount = 0;
                } else {
                    tapCount++;
                }
            }
        });
        /*nameText.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                showDebugCtlAlert();
                return true;
            }
        });*/

        endBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                endBtn.setEnabled(false);
                if (retrying) {
                    Intent intent = new Intent(VoIPActivity.this, VoIPService.class);
                    intent.putExtra("user_id", user.id);
                    intent.putExtra("is_outgoing", true);
                    intent.putExtra("start_incall_activity", false);
                    intent.putExtra("account", currentAccount);
                    try {
                        startService(intent);
                    } catch (Throwable e) {
                        FileLog.e(e);
                    }
                    hideRetry();
                    endBtn.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            if (VoIPService.getSharedInstance() == null && !isFinishing()) {
                                endBtn.postDelayed(this, 100);
                                return;
                            }
                            if (VoIPService.getSharedInstance() != null)
                                VoIPService.getSharedInstance().registerStateListener(VoIPActivity.this);
                        }
                    }, 100);
                    return;
                }
                if (VoIPService.getSharedInstance() != null)
                    VoIPService.getSharedInstance().hangUp();
            }
        });

        spkToggle.setOnClickListener(v -> {
            VoIPService svc = VoIPService.getSharedInstance();
            if (svc == null)
                return;
            svc.toggleSpeakerphoneOrShowRouteSheet(VoIPActivity.this);
        });
        micToggle.setOnClickListener(v -> {
            if (VoIPService.getSharedInstance() == null) {
                finish();
                return;
            }
            boolean checked = !micToggle.isChecked();
            micToggle.setChecked(checked);
            VoIPService.getSharedInstance().setMicMute(checked);
        });
        chatBtn.setOnClickListener(v -> {
            if (isIncomingWaiting) {
                if (SharedConfig.passcodeHash.length() > 0) {
                    return;
                }
                try {
                    KeyguardManager myKM = (KeyguardManager) ApplicationLoader.applicationContext.getSystemService(Context.KEYGUARD_SERVICE);
                    if (myKM.inKeyguardRestrictedInputMode()) {
                        return;
                    }
                } catch (Exception ignore) {
                    return;
                }
                showMessagesSheet();
                return;
            }
            Intent intent = new Intent(ApplicationLoader.applicationContext, LaunchActivity.class);
            intent.setAction("com.tmessages.openchat" + Math.random() + Integer.MAX_VALUE);
            intent.putExtra("currentAccount", currentAccount);
            intent.setFlags(32768);
            intent.putExtra("userId", user.id);
            startActivity(intent);
            finish();
        });
        /*addMemberBtn.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                showInviteFragment();
            }
        });*/

        spkToggle.setChecked(((AudioManager) getSystemService(AUDIO_SERVICE)).isSpeakerphoneOn());
        micToggle.setChecked(VoIPService.getSharedInstance().isMicMute());

        onAudioSettingsChanged();

        nameText.setText(ContactsController.formatName(user.first_name, user.last_name));

        VoIPService.getSharedInstance().registerStateListener(this);

        acceptSwipe.setListener(new CallSwipeView.Listener() {
            @Override
            public void onDragComplete() {
                acceptSwipe.setEnabled(false);
                declineSwipe.setEnabled(false);
                if (VoIPService.getSharedInstance() == null) {
                    finish();
                    return;
                }
                didAcceptFromHere = true;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
                    requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 101);
                } else {
                    VoIPService.getSharedInstance().acceptIncomingCall();
                    callAccepted();
                }
            }

            @Override
            public void onDragStart() {
                if (currentDeclineAnim != null) {
                    currentDeclineAnim.cancel();
                }
                AnimatorSet set = new AnimatorSet();
                set.playTogether(
                        ObjectAnimator.ofFloat(declineSwipe, View.ALPHA, .2f),
                        ObjectAnimator.ofFloat(declineBtn, View.ALPHA, .2f)
                );
                set.setDuration(200);
                set.setInterpolator(CubicBezierInterpolator.DEFAULT);
                set.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        currentDeclineAnim = null;
                    }
                });
                currentDeclineAnim = set;
                set.start();
                declineSwipe.stopAnimatingArrows();
            }

            @Override
            public void onDragCancel() {
                if (currentDeclineAnim != null) {
                    currentDeclineAnim.cancel();
                }
                AnimatorSet set = new AnimatorSet();
                set.playTogether(
                        ObjectAnimator.ofFloat(declineSwipe, View.ALPHA, 1),
                        ObjectAnimator.ofFloat(declineBtn, View.ALPHA, 1)
                );
                set.setDuration(200);
                set.setInterpolator(CubicBezierInterpolator.DEFAULT);
                set.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        currentDeclineAnim = null;
                    }
                });
                currentDeclineAnim = set;
                set.start();
                declineSwipe.startAnimatingArrows();
            }
        });
        declineSwipe.setListener(new CallSwipeView.Listener() {
            @Override
            public void onDragComplete() {
                acceptSwipe.setEnabled(false);
                declineSwipe.setEnabled(false);
                if (VoIPService.getSharedInstance() != null)
                    VoIPService.getSharedInstance().declineIncomingCall(VoIPService.DISCARD_REASON_LINE_BUSY, null);
                else
                    finish();
            }

            @Override
            public void onDragStart() {
                if (currentAcceptAnim != null) {
                    currentAcceptAnim.cancel();
                }
                AnimatorSet set = new AnimatorSet();
                set.playTogether(
                        ObjectAnimator.ofFloat(acceptSwipe, View.ALPHA, .2f),
                        ObjectAnimator.ofFloat(acceptBtn, View.ALPHA, .2f)
                );
                set.setDuration(200);
                set.setInterpolator(new DecelerateInterpolator());
                set.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        currentAcceptAnim = null;
                    }
                });
                currentAcceptAnim = set;
                set.start();
                acceptSwipe.stopAnimatingArrows();
            }

            @Override
            public void onDragCancel() {
                if (currentAcceptAnim != null) {
                    currentAcceptAnim.cancel();
                }
                AnimatorSet set = new AnimatorSet();
                set.playTogether(
                        ObjectAnimator.ofFloat(acceptSwipe, View.ALPHA, 1),
                        ObjectAnimator.ofFloat(acceptBtn, View.ALPHA, 1)
                );
                set.setDuration(200);
                set.setInterpolator(CubicBezierInterpolator.DEFAULT);
                set.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        currentAcceptAnim = null;
                    }
                });
                currentAcceptAnim = set;
                set.start();
                acceptSwipe.startAnimatingArrows();
            }
        });
        cancelBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        });
        getWindow().getDecorView().setKeepScreenOn(true);

        NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.emojiDidLoad);
        NotificationCenter.getGlobalInstance().addObserver(this, NotificationCenter.closeInCallActivity);
        hintTextView.setText(LocaleController.formatString("CallEmojiKeyTooltip", R.string.CallEmojiKeyTooltip, user.first_name));
        emojiExpandedText.setText(LocaleController.formatString("CallEmojiKeyTooltip", R.string.CallEmojiKeyTooltip, user.first_name));

        AccessibilityManager am = (AccessibilityManager) getSystemService(ACCESSIBILITY_SERVICE);
        if (am.isTouchExplorationEnabled()) {
            nameText.postDelayed(new Runnable() {
                @Override
                public void run() {
                    nameText.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
                }
            }, 500);
        }
    }

    private View createContentView() {
        FrameLayout content = new FrameLayout(this) {
            private void setNegativeMargins(Rect insets, LayoutParams lp) {
                lp.topMargin = -insets.top;
                lp.bottomMargin = -insets.bottom;
                lp.leftMargin = -insets.left;
                lp.rightMargin = -insets.right;
            }

            @Override
            protected boolean fitSystemWindows(Rect insets) {
                setNegativeMargins(insets, (LayoutParams) photoView.getLayoutParams());
                setNegativeMargins(insets, (LayoutParams) blurOverlayView1.getLayoutParams());
                setNegativeMargins(insets, (LayoutParams) blurOverlayView2.getLayoutParams());
                return super.fitSystemWindows(insets);
            }
        };
        content.setBackgroundColor(0);
        content.setFitsSystemWindows(true);
        content.setClipToPadding(false);

        BackupImageView photo = new BackupImageView(this) {
            private Drawable topGradient = getResources().getDrawable(R.drawable.gradient_top);
            private Drawable bottomGradient = getResources().getDrawable(R.drawable.gradient_bottom);
            private Paint paint = new Paint();

            @Override
            protected void onDraw(Canvas canvas) {
                super.onDraw(canvas);
                paint.setColor(0x4C000000);
                canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
                topGradient.setBounds(0, 0, getWidth(), AndroidUtilities.dp(170));
                topGradient.setAlpha(128);
                topGradient.draw(canvas);
                bottomGradient.setBounds(0, getHeight() - AndroidUtilities.dp(220), getWidth(), getHeight());
                bottomGradient.setAlpha(178);
                bottomGradient.draw(canvas);
            }
        };
        content.addView(photoView = photo);
        blurOverlayView1 = new ImageView(this);
        blurOverlayView1.setScaleType(ImageView.ScaleType.CENTER_CROP);
        blurOverlayView1.setAlpha(0f);
        content.addView(blurOverlayView1);
        blurOverlayView2 = new ImageView(this);
        blurOverlayView2.setScaleType(ImageView.ScaleType.CENTER_CROP);
        blurOverlayView2.setAlpha(0f);
        content.addView(blurOverlayView2);

        TextView branding = new TextView(this);
        branding.setTextColor(0xCCFFFFFF);
        branding.setText(LocaleController.getString("VoipInCallBranding", R.string.VoipInCallBranding));
        Drawable logo = getResources().getDrawable(R.drawable.notification).mutate();
        logo.setAlpha(0xCC);
        logo.setBounds(0, 0, AndroidUtilities.dp(15), AndroidUtilities.dp(15));
        signalBarsDrawable = new SignalBarsDrawable();
        signalBarsDrawable.setBounds(0, 0, signalBarsDrawable.getIntrinsicWidth(), signalBarsDrawable.getIntrinsicHeight());
        branding.setCompoundDrawables(LocaleController.isRTL ? signalBarsDrawable : logo, null, LocaleController.isRTL ? logo : signalBarsDrawable, null);
        branding.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
        branding.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
        branding.setCompoundDrawablePadding(AndroidUtilities.dp(5));
        branding.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
        content.addView(branding, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 18, 18, 18, 0));
        brandingText = branding;

        TextView name = new TextView(this);
        name.setSingleLine();
        name.setTextColor(0xFFFFFFFF);
        name.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 40);
        name.setEllipsize(TextUtils.TruncateAt.END);
        name.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
        name.setShadowLayer(AndroidUtilities.dp(3), 0, AndroidUtilities.dp(.666666667f), 0x4C000000);
        name.setTypeface(Typeface.create("sans-serif-light", Typeface.NORMAL));
        content.addView(nameText = name, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 16, 43, 18, 0));

        TextView state = new TextView(this);
        state.setTextColor(0xCCFFFFFF);
        state.setSingleLine();
        state.setEllipsize(TextUtils.TruncateAt.END);
        state.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
        state.setShadowLayer(AndroidUtilities.dp(3), 0, AndroidUtilities.dp(.666666667f), 0x4C000000);
        state.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
        state.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
        //state.setAllCaps(true);
        content.addView(stateText = state, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 18, 98, 18, 0));
        durationText = state;

        state = new TextView(this);
        state.setTextColor(0xCCFFFFFF);
        state.setSingleLine();
        state.setEllipsize(TextUtils.TruncateAt.END);
        state.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
        state.setShadowLayer(AndroidUtilities.dp(3), 0, AndroidUtilities.dp(.666666667f), 0x4C000000);
        state.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
        state.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
        //state.setAllCaps(true);
        state.setVisibility(View.GONE);
        content.addView(stateText2 = state, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 18, 98, 18, 0));

        ellSpans = new TextAlphaSpan[]{new TextAlphaSpan(), new TextAlphaSpan(), new TextAlphaSpan()};

        LinearLayout buttons = new LinearLayout(this);
        buttons.setOrientation(LinearLayout.HORIZONTAL);
        content.addView(buttons, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM));

        FrameLayout wrap;

        TextView accountName = new TextView(this);
        accountName.setTextColor(0xCCFFFFFF);
        accountName.setSingleLine();
        accountName.setEllipsize(TextUtils.TruncateAt.END);
        accountName.setShadowLayer(AndroidUtilities.dp(3), 0, AndroidUtilities.dp(.6666667f), 0x4c000000);
        accountName.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
        accountName.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT);
        content.addView(accountNameText = accountName, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 18, 120, 18, 0));

        CheckableImageView mic = new CheckableImageView(this);
        mic.setBackgroundResource(R.drawable.bg_voip_icon_btn);
        Drawable micIcon = getResources().getDrawable(R.drawable.ic_mic_off_white_24dp).mutate();
        mic.setAlpha(204);
        mic.setImageDrawable(micIcon);
        mic.setScaleType(ImageView.ScaleType.CENTER);
        mic.setContentDescription(LocaleController.getString("AccDescrMuteMic", R.string.AccDescrMuteMic));
        wrap = new FrameLayout(this);
        wrap.addView(micToggle = mic, LayoutHelper.createFrame(38, 38, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 10));
        buttons.addView(wrap, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f));

        chatBtn = new ImageView(this);
        Drawable chatIcon = getResources().getDrawable(R.drawable.ic_chat_bubble_white_24dp).mutate();
        chatIcon.setAlpha(204);
        chatBtn.setImageDrawable(chatIcon);
        chatBtn.setScaleType(ImageView.ScaleType.CENTER);
        chatBtn.setContentDescription(LocaleController.getString("AccDescrOpenChat", R.string.AccDescrOpenChat));
        wrap = new FrameLayout(this);
        wrap.addView(chatBtn, LayoutHelper.createFrame(38, 38, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 10));
        buttons.addView(wrap, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f));

        /*ImageView addMember=new ImageView(this);
        Drawable addIcon=getResources().getDrawable(R.drawable.menu_invite).mutate();
        addIcon.setColorFilter(null);
        addMember.setAlpha(204);
        addMember.setImageDrawable(addIcon);
        addMember.setScaleType(ImageView.ScaleType.CENTER);
        addMember.setEnabled(false);
        addMember.setAlpha(.6f);
        wrap=new FrameLayout(this);
        wrap.addView(addMemberBtn=addMember, LayoutHelper.createFrame(38, 38, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 10));
        buttons.addView(wrap, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f));*/

        CheckableImageView speaker = new CheckableImageView(this);
        speaker.setBackgroundResource(R.drawable.bg_voip_icon_btn);
        Drawable speakerIcon = getResources().getDrawable(R.drawable.ic_volume_up_white_24dp).mutate();
        speaker.setAlpha(204);
        speaker.setImageDrawable(speakerIcon);
        speaker.setScaleType(ImageView.ScaleType.CENTER);
        speaker.setContentDescription(LocaleController.getString("VoipAudioRoutingSpeaker", R.string.VoipAudioRoutingSpeaker));
        wrap = new FrameLayout(this);
        wrap.addView(spkToggle = speaker, LayoutHelper.createFrame(38, 38, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 10));
        buttons.addView(wrap, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1f));
        bottomButtons = buttons;

        LinearLayout swipesWrap = new LinearLayout(this);
        swipesWrap.setOrientation(LinearLayout.HORIZONTAL);

        CallSwipeView acceptSwipe = new CallSwipeView(this);
        acceptSwipe.setColor(0xFF45bc4d);
        acceptSwipe.setContentDescription(LocaleController.getString("Accept", R.string.Accept));
        swipesWrap.addView(this.acceptSwipe = acceptSwipe, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 70, 1f, 4, 4, -35, 4));

        CallSwipeView declineSwipe = new CallSwipeView(this);
        declineSwipe.setColor(0xFFe61e44);
        declineSwipe.setContentDescription(LocaleController.getString("Decline", R.string.Decline));
        swipesWrap.addView(this.declineSwipe = declineSwipe, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 70, 1f, -35, 4, 4, 4));

        content.addView(swipeViewsWrap = swipesWrap, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM, 20, 0, 20, 68));

        ImageView acceptBtn = new ImageView(this);
        FabBackgroundDrawable acceptBtnBg = new FabBackgroundDrawable();
        acceptBtnBg.setColor(0xFF45bc4d);
        acceptBtn.setBackgroundDrawable(acceptBtnBg);
        acceptBtn.setImageResource(R.drawable.ic_call_end_white_36dp);
        acceptBtn.setScaleType(ImageView.ScaleType.MATRIX);
        Matrix matrix = new Matrix();
        matrix.setTranslate(AndroidUtilities.dp(17), AndroidUtilities.dp(17));
        matrix.postRotate(-135, AndroidUtilities.dp(35), AndroidUtilities.dp(35));
        acceptBtn.setImageMatrix(matrix);
        content.addView(this.acceptBtn = acceptBtn, LayoutHelper.createFrame(78, 78, Gravity.BOTTOM | Gravity.LEFT, 20, 0, 0, 68));

        ImageView declineBtn = new ImageView(this);
        FabBackgroundDrawable rejectBtnBg = new FabBackgroundDrawable();
        rejectBtnBg.setColor(0xFFe61e44);
        declineBtn.setBackgroundDrawable(rejectBtnBg);
        declineBtn.setImageResource(R.drawable.ic_call_end_white_36dp);
        declineBtn.setScaleType(ImageView.ScaleType.CENTER);
        content.addView(this.declineBtn = declineBtn, LayoutHelper.createFrame(78, 78, Gravity.BOTTOM | Gravity.RIGHT, 0, 0, 20, 68));

        acceptSwipe.setViewToDrag(acceptBtn, false);
        declineSwipe.setViewToDrag(declineBtn, true);

        FrameLayout end = new FrameLayout(this);
        FabBackgroundDrawable endBtnBg = new FabBackgroundDrawable();
        endBtnBg.setColor(0xFFe61e44);
        end.setBackgroundDrawable(this.endBtnBg = endBtnBg);
        ImageView endInner = new ImageView(this);
        endInner.setImageResource(R.drawable.ic_call_end_white_36dp);
        endInner.setScaleType(ImageView.ScaleType.CENTER);
        end.addView(endBtnIcon = endInner, LayoutHelper.createFrame(70, 70));
        end.setForeground(getResources().getDrawable(R.drawable.fab_highlight_dark));
        end.setContentDescription(LocaleController.getString("VoipEndCall", R.string.VoipEndCall));
        content.addView(endBtn = end, LayoutHelper.createFrame(78, 78, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0, 0, 68));

        ImageView cancelBtn = new ImageView(this);
        FabBackgroundDrawable cancelBtnBg = new FabBackgroundDrawable();
        cancelBtnBg.setColor(0xFFFFFFFF);
        cancelBtn.setBackgroundDrawable(cancelBtnBg);
        cancelBtn.setImageResource(R.drawable.edit_cancel);
        cancelBtn.setColorFilter(0x89000000);
        cancelBtn.setScaleType(ImageView.ScaleType.CENTER);
        cancelBtn.setVisibility(View.GONE);
        cancelBtn.setContentDescription(LocaleController.getString("Cancel", R.string.Cancel));
        content.addView(this.cancelBtn = cancelBtn, LayoutHelper.createFrame(78, 78, Gravity.BOTTOM | Gravity.LEFT, 52, 0, 0, 68));


        emojiWrap = new LinearLayout(this);
        emojiWrap.setOrientation(LinearLayout.HORIZONTAL);
        emojiWrap.setClipToPadding(false);
        emojiWrap.setPivotX(0);
        emojiWrap.setPivotY(0);
        emojiWrap.setPadding(AndroidUtilities.dp(14), AndroidUtilities.dp(10), AndroidUtilities.dp(14), AndroidUtilities.dp(10));
        for (int i = 0; i < 4; i++) {
            ImageView emoji = new ImageView(this);
            emoji.setScaleType(ImageView.ScaleType.FIT_XY);
            emojiWrap.addView(emoji, LayoutHelper.createLinear(22, 22, i == 0 ? 0 : 4, 0, 0, 0));
            keyEmojiViews[i] = emoji;
        }
        emojiWrap.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (emojiTooltipVisible) {
                    setEmojiTooltipVisible(false);
                    if (tooltipHider != null) {
                        hintTextView.removeCallbacks(tooltipHider);
                        tooltipHider = null;
                    }
                }
                setEmojiExpanded(!emojiExpanded);
            }
        });
        //keyEmojiText=new TextView(this);
        //keyEmojiText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20);
        content.addView(emojiWrap, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT)));
        emojiWrap.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                if (emojiExpanded)
                    return false;
                if (tooltipHider != null) {
                    hintTextView.removeCallbacks(tooltipHider);
                    tooltipHider = null;
                }
                setEmojiTooltipVisible(!emojiTooltipVisible);
                if (emojiTooltipVisible) {
                    hintTextView.postDelayed(tooltipHider = new Runnable() {
                        @Override
                        public void run() {
                            tooltipHider = null;
                            setEmojiTooltipVisible(false);
                        }
                    }, 5000);
                }
                return true;
            }
        });
        emojiExpandedText = new TextView(this);
        emojiExpandedText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
        emojiExpandedText.setTextColor(0xFFFFFFFF);
        emojiExpandedText.setGravity(Gravity.CENTER);
        emojiExpandedText.setAlpha(0);
        content.addView(emojiExpandedText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 10, 32, 10, 0));

        hintTextView = new CorrectlyMeasuringTextView(this);
        hintTextView.setBackgroundDrawable(Theme.createRoundRectDrawable(AndroidUtilities.dp(3), 0xf2333333));
        hintTextView.setTextColor(Theme.getColor(Theme.key_chat_gifSaveHintText));
        hintTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
        hintTextView.setPadding(AndroidUtilities.dp(10), AndroidUtilities.dp(10), AndroidUtilities.dp(10), AndroidUtilities.dp(10));
        hintTextView.setGravity(Gravity.CENTER);
        hintTextView.setMaxWidth(AndroidUtilities.dp(300));
        hintTextView.setAlpha(0.0f);
        content.addView(hintTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.RIGHT, 0, 42, 10, 0));

        int ellMaxAlpha = stateText.getPaint().getAlpha();
        ellAnimator = new AnimatorSet();
        ellAnimator.playTogether(
                createAlphaAnimator(ellSpans[0], 0, ellMaxAlpha, 0, 300),
                createAlphaAnimator(ellSpans[1], 0, ellMaxAlpha, 150, 300),
                createAlphaAnimator(ellSpans[2], 0, ellMaxAlpha, 300, 300),
                createAlphaAnimator(ellSpans[0], ellMaxAlpha, 0, 1000, 400),
                createAlphaAnimator(ellSpans[1], ellMaxAlpha, 0, 1000, 400),
                createAlphaAnimator(ellSpans[2], ellMaxAlpha, 0, 1000, 400)
        );
        ellAnimator.addListener(new AnimatorListenerAdapter() {
            private Runnable restarter = new Runnable() {
                @Override
                public void run() {
                    if (!isFinishing())
                        ellAnimator.start();
                }
            };

            @Override
            public void onAnimationEnd(Animator animation) {
                if (!isFinishing()) {
                    VoIPActivity.this.content.postDelayed(restarter, 300);
                }
            }
        });
        content.setClipChildren(false);
        this.content = content;

        return content;
    }

    @SuppressLint("ObjectAnimatorBinding")
    private ObjectAnimator createAlphaAnimator(Object target, int startVal, int endVal, int startDelay, int duration) {
        ObjectAnimator a = ObjectAnimator.ofInt(target, "alpha", startVal, endVal);
        a.setDuration(duration);
        a.setStartDelay(startDelay);
        a.setInterpolator(CubicBezierInterpolator.DEFAULT);
        return a;
    }

    @Override
    protected void onDestroy() {
        NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.emojiDidLoad);
        NotificationCenter.getGlobalInstance().removeObserver(this, NotificationCenter.closeInCallActivity);
        if (VoIPService.getSharedInstance() != null) {
            VoIPService.getSharedInstance().unregisterStateListener(this);
        }
        super.onDestroy();
    }

    @Override
    public void onBackPressed() {
        if (emojiExpanded) {
            setEmojiExpanded(false);
            return;
        }
        if (!isIncomingWaiting) {
            super.onBackPressed();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (VoIPService.getSharedInstance() != null)
            VoIPService.getSharedInstance().onUIForegroundStateChanged(true);
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (retrying)
            finish();
        if (VoIPService.getSharedInstance() != null)
            VoIPService.getSharedInstance().onUIForegroundStateChanged(false);
    }

    @TargetApi(Build.VERSION_CODES.M)
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == 101) {
            if (VoIPService.getSharedInstance() == null) {
                finish();
                return;
            }
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                VoIPService.getSharedInstance().acceptIncomingCall();
                callAccepted();
            } else {
                if (!shouldShowRequestPermissionRationale(Manifest.permission.RECORD_AUDIO)) {
                    VoIPService.getSharedInstance().declineIncomingCall();
                    VoIPHelper.permissionDenied(this, new Runnable() {
                        @Override
                        public void run() {
                            finish();
                        }
                    });
                    return;
                }
                acceptSwipe.reset();
            }
        }

    }

    private void updateKeyView() {
        if (VoIPService.getSharedInstance() == null)
            return;
        IdenticonDrawable img = new IdenticonDrawable();
        img.setColors(new int[]{0x00FFFFFF, 0xFFFFFFFF, 0x99FFFFFF, 0x33FFFFFF});
        TLRPC.EncryptedChat encryptedChat = new TLRPC.TL_encryptedChat();
        try {
            ByteArrayOutputStream buf = new ByteArrayOutputStream();
            buf.write(VoIPService.getSharedInstance().getEncryptionKey());
            buf.write(VoIPService.getSharedInstance().getGA());
            encryptedChat.auth_key = buf.toByteArray();
        } catch (Exception checkedExceptionsAreBad) {
        }
        byte[] sha256 = Utilities.computeSHA256(encryptedChat.auth_key, 0, encryptedChat.auth_key.length);
        String[] emoji = EncryptionKeyEmojifier.emojifyForCall(sha256);
        //keyEmojiText.setText(Emoji.replaceEmoji(TextUtils.join(" ", emoji), keyEmojiText.getPaint().getFontMetricsInt(), AndroidUtilities.dp(32), false));
        emojiWrap.setContentDescription(LocaleController.getString("EncryptionKey", R.string.EncryptionKey) + ", " + TextUtils.join(", ", emoji));
        for (int i = 0; i < 4; i++) {
            Drawable drawable = Emoji.getEmojiDrawable(emoji[i]);
            if (drawable != null) {
                drawable.setBounds(0, 0, AndroidUtilities.dp(22), AndroidUtilities.dp(22));
                keyEmojiViews[i].setImageDrawable(drawable);
            }
        }
    }

    private CharSequence getFormattedDebugString() {
        String in = VoIPService.getSharedInstance().getDebugString();
        SpannableString ss = new SpannableString(in);

        int offset = 0;
        do {
            int lineEnd = in.indexOf('\n', offset + 1);
            if (lineEnd == -1)
                lineEnd = in.length();
            String line = in.substring(offset, lineEnd);
            if (line.contains("IN_USE")) {
                ss.setSpan(new ForegroundColorSpan(0xFF00FF00), offset, lineEnd, 0);
            } else {
                if (line.contains(": ")) {
                    ss.setSpan(new ForegroundColorSpan(0xAAFFFFFF), offset, offset + line.indexOf(':') + 1, 0);
                }
            }
        } while ((offset = in.indexOf('\n', offset + 1)) != -1);

        return ss;
    }

    private void showDebugAlert() {
        if (VoIPService.getSharedInstance() == null)
            return;
        VoIPService.getSharedInstance().forceRating();
        final LinearLayout debugOverlay = new LinearLayout(this);
        debugOverlay.setOrientation(LinearLayout.VERTICAL);
        debugOverlay.setBackgroundColor(0xCC000000);
        int pad = AndroidUtilities.dp(16);
        debugOverlay.setPadding(pad, pad * 2, pad, pad * 2);

        TextView title = new TextView(this);
        title.setTextColor(0xFFFFFFFF);
        title.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
        title.setTypeface(Typeface.DEFAULT_BOLD);
        title.setGravity(Gravity.CENTER);
        title.setText(getDebugTitle());
        debugOverlay.addView(title, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 0, 0, 0, 16));

        ScrollView scroll = new ScrollView(this);
        final TextView debugText = new TextView(this);
        debugText.setTypeface(Typeface.MONOSPACE);
        debugText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 11);
        debugText.setMaxWidth(AndroidUtilities.dp(350));
        debugText.setTextColor(0xFFFFFFFF);
        debugText.setText(getFormattedDebugString());
        scroll.addView(debugText);
        debugOverlay.addView(scroll, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 1f));

        TextView closeBtn = new TextView(this);
        closeBtn.setBackgroundColor(0xFFFFFFFF);
        closeBtn.setTextColor(0xFF000000);
        closeBtn.setPadding(pad, pad, pad, pad);
        closeBtn.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15);
        closeBtn.setText(LocaleController.getString("Close", R.string.Close));
        debugOverlay.addView(closeBtn, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 16, 0, 0));

        final WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.addView(debugOverlay, new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_APPLICATION_PANEL, 0, PixelFormat.TRANSLUCENT));

        closeBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                wm.removeView(debugOverlay);
            }
        });

        final Runnable r = new Runnable() {
            @Override
            public void run() {
                if (isFinishing() || VoIPService.getSharedInstance() == null) {
                    return;
                }
                title.setText(getDebugTitle());
                debugText.setText(getFormattedDebugString());
                debugOverlay.postDelayed(this, 500);
            }
        };
        debugOverlay.postDelayed(r, 500);
    }

    private String getDebugTitle() {
        String title = "libtgvoip";
        final String version = TgVoip.getVersion();
        if (version != null) {
            title += " v" + version;
        }
        return title;
    }

    private void showInviteFragment() {
        /*KeyguardManager km=(KeyguardManager) getSystemService(KEYGUARD_SERVICE);
        if(km.inKeyguardRestrictedInputMode()){
        	VoIPHelper.dismissKeyguard(this, new VoIPHelper.OnKeyguardDismissListener(){
                @Override
                public void onDismissed(){
                    showInviteFragment();
                }

                @Override
                public void onCanceled(){

                }
            });
            return;
        }
        FragmentStackDialog d=new FragmentStackDialog(VoIPActivity.this);
        d.show();
        CallUpgradeToGroupActivity fragment=new CallUpgradeToGroupActivity(currentAccount);
        fragment.setDelegate(new CallUpgradeToGroupActivity.ResultReceiver(){
            @Override
            public void didSelectUsers(ArrayList<Integer> ids){
                if(VoIPService.getSharedInstance()==null)
                    return;
                VoIPService.getSharedInstance().upgradeToGroupCall(ids);
            }
        });
        d.presentFragment(fragment);*/
    }

    private void startUpdatingCallDuration() {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                if (isFinishing() || VoIPService.getSharedInstance() == null) {
                    return;
                }
                if (callState == VoIPService.STATE_ESTABLISHED || callState == VoIPService.STATE_RECONNECTING) {
                    durationText.setText(AndroidUtilities.formatShortDuration((int) (VoIPService.getSharedInstance().getCallDuration() / 1000)));
                    durationText.postDelayed(this, 500);
                }
            }
        };
        r.run();
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (isIncomingWaiting && (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
            if (VoIPService.getSharedInstance() != null)
                VoIPService.getSharedInstance().stopRinging();
            else
                finish();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

    private void callAccepted() {
        endBtn.setVisibility(View.VISIBLE);
        if (VoIPService.getSharedInstance().hasEarpiece())
            spkToggle.setVisibility(View.VISIBLE);
        else
            spkToggle.setVisibility(View.GONE);
        bottomButtons.setVisibility(View.VISIBLE);
        if (didAcceptFromHere) {
            acceptBtn.setVisibility(View.GONE);
            ObjectAnimator colorAnim;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                colorAnim = ObjectAnimator.ofArgb(endBtnBg, "color", 0xFF45bc4d, 0xFFe61e44);
            } else {
                colorAnim = ObjectAnimator.ofInt(endBtnBg, "color", 0xFF45bc4d, 0xFFe61e44);
                colorAnim.setEvaluator(new ArgbEvaluator());
            }
            AnimatorSet set = new AnimatorSet();
            AnimatorSet decSet = new AnimatorSet();
            decSet.playTogether(
                    ObjectAnimator.ofFloat(endBtnIcon, View.ROTATION, -135, 0),
                    colorAnim
            );
            decSet.setInterpolator(CubicBezierInterpolator.EASE_OUT);
            decSet.setDuration(500);
            AnimatorSet accSet = new AnimatorSet();
            accSet.playTogether(
                    ObjectAnimator.ofFloat(swipeViewsWrap, View.ALPHA, 1, 0),
                    ObjectAnimator.ofFloat(declineBtn, View.ALPHA, 0),
                    ObjectAnimator.ofFloat(accountNameText, View.ALPHA, 0)
            );
            accSet.setInterpolator(CubicBezierInterpolator.EASE_IN);
            accSet.setDuration(125);
            set.playTogether(
                    decSet,
                    accSet
            );
            set.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    swipeViewsWrap.setVisibility(View.GONE);
                    declineBtn.setVisibility(View.GONE);
                    accountNameText.setVisibility(View.GONE);
                }
            });
            set.start();
        } else {
            AnimatorSet set = new AnimatorSet();
            AnimatorSet decSet = new AnimatorSet();
            decSet.playTogether(
                    ObjectAnimator.ofFloat(bottomButtons, View.ALPHA, 0, 1)
            );
            decSet.setInterpolator(CubicBezierInterpolator.EASE_OUT);
            decSet.setDuration(500);
            AnimatorSet accSet = new AnimatorSet();
            accSet.playTogether(
                    ObjectAnimator.ofFloat(swipeViewsWrap, View.ALPHA, 1, 0),
                    ObjectAnimator.ofFloat(declineBtn, View.ALPHA, 0),
                    ObjectAnimator.ofFloat(acceptBtn, View.ALPHA, 0),
                    ObjectAnimator.ofFloat(accountNameText, View.ALPHA, 0)
            );
            accSet.setInterpolator(CubicBezierInterpolator.EASE_IN);
            accSet.setDuration(125);
            set.playTogether(
                    decSet,
                    accSet
            );
            set.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    swipeViewsWrap.setVisibility(View.GONE);
                    declineBtn.setVisibility(View.GONE);
                    acceptBtn.setVisibility(View.GONE);
                    accountNameText.setVisibility(View.GONE);
                }
            });
            set.start();
        }
    }

    private void showRetry() {
        if (retryAnim != null)
            retryAnim.cancel();
        endBtn.setEnabled(false);
        retrying = true;
        cancelBtn.setVisibility(View.VISIBLE);
        cancelBtn.setAlpha(0);
        AnimatorSet set = new AnimatorSet();
        ObjectAnimator colorAnim;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            colorAnim = ObjectAnimator.ofArgb(endBtnBg, "color", 0xFFe61e44, 0xFF45bc4d);
        } else {
            colorAnim = ObjectAnimator.ofInt(endBtnBg, "color", 0xFFe61e44, 0xFF45bc4d);
            colorAnim.setEvaluator(new ArgbEvaluator());
        }
        set.playTogether(
                ObjectAnimator.ofFloat(cancelBtn, View.ALPHA, 0, 1),
                ObjectAnimator.ofFloat(endBtn, View.TRANSLATION_X, 0, content.getWidth() / 2 - AndroidUtilities.dp(52) - endBtn.getWidth() / 2),
                colorAnim,
                ObjectAnimator.ofFloat(endBtnIcon, View.ROTATION, 0, -135)//,
                //ObjectAnimator.ofFloat(spkToggle, View.ALPHA, 0),
                //ObjectAnimator.ofFloat(micToggle, View.ALPHA, 0),
                //ObjectAnimator.ofFloat(chatBtn, View.ALPHA, 0)
        );
        set.setStartDelay(200);
        set.setDuration(300);
        set.setInterpolator(CubicBezierInterpolator.DEFAULT);
        set.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                //bottomButtons.setVisibility(View.GONE);
                retryAnim = null;
                endBtn.setEnabled(true);
            }
        });
        retryAnim = set;
        set.start();
    }

    private void hideRetry() {
        if (retryAnim != null)
            retryAnim.cancel();
        retrying = false;
        //bottomButtons.setVisibility(View.VISIBLE);
        ObjectAnimator colorAnim;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            colorAnim = ObjectAnimator.ofArgb(endBtnBg, "color", 0xFF45bc4d, 0xFFe61e44);
        } else {
            colorAnim = ObjectAnimator.ofInt(endBtnBg, "color", 0xFF45bc4d, 0xFFe61e44);
            colorAnim.setEvaluator(new ArgbEvaluator());
        }
        AnimatorSet set = new AnimatorSet();
        set.playTogether(
                colorAnim,
                ObjectAnimator.ofFloat(endBtnIcon, "rotation", -135, 0),
                ObjectAnimator.ofFloat(endBtn, View.TRANSLATION_X, 0),
                ObjectAnimator.ofFloat(cancelBtn, View.ALPHA, 0)//,
                //ObjectAnimator.ofFloat(bottomButtons, View.ALPHA, 1)
        );
        set.setStartDelay(200);
        set.setDuration(300);
        set.setInterpolator(CubicBezierInterpolator.DEFAULT);
        set.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                cancelBtn.setVisibility(View.GONE);
                endBtn.setEnabled(true);
                retryAnim = null;
            }
        });
        retryAnim = set;
        set.start();
    }

    @Override
    public void onStateChanged(final int state) {
        final int prevState = callState;
        callState = state;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                boolean wasFirstStateChange = firstStateChange;
                if (firstStateChange) {
                    spkToggle.setChecked(((AudioManager) getSystemService(AUDIO_SERVICE)).isSpeakerphoneOn());
                    if (isIncomingWaiting = state == VoIPService.STATE_WAITING_INCOMING) {
                        swipeViewsWrap.setVisibility(View.VISIBLE);
                        endBtn.setVisibility(View.GONE);
                        //bottomButtons.setVisibility(View.GONE);
                        acceptSwipe.startAnimatingArrows();
                        declineSwipe.startAnimatingArrows();
                        if (UserConfig.getActivatedAccountsCount() > 1) {
                            TLRPC.User self = UserConfig.getInstance(currentAccount).getCurrentUser();
                            accountNameText.setText(LocaleController.formatString("VoipAnsweringAsAccount", R.string.VoipAnsweringAsAccount, ContactsController.formatName(self.first_name, self.last_name)));
                        } else {
                            accountNameText.setVisibility(View.GONE);
                        }
                        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
                        VoIPService svc = VoIPService.getSharedInstance();
                        if (svc != null)
                            svc.startRingtoneAndVibration();
                        setTitle(LocaleController.getString("VoipIncoming", R.string.VoipIncoming));
                    } else {
                        swipeViewsWrap.setVisibility(View.GONE);
                        acceptBtn.setVisibility(View.GONE);
                        declineBtn.setVisibility(View.GONE);
                        accountNameText.setVisibility(View.GONE);
                        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
                    }
                    if (state != VoIPService.STATE_ESTABLISHED)
                        emojiWrap.setVisibility(View.GONE);
                    firstStateChange = false;
                }

                if (isIncomingWaiting && state != VoIPService.STATE_WAITING_INCOMING && state != VoIPBaseService.STATE_ENDED && state != VoIPService.STATE_HANGING_UP) {
                    isIncomingWaiting = false;
                    if (!didAcceptFromHere)
                        callAccepted();
                }

                if (state == VoIPService.STATE_WAITING_INCOMING) {
                    setStateTextAnimated(LocaleController.getString("VoipIncoming", R.string.VoipIncoming), false);
                    getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
                } else if (state == VoIPService.STATE_WAIT_INIT || state == VoIPService.STATE_WAIT_INIT_ACK) {
                    setStateTextAnimated(LocaleController.getString("VoipConnecting", R.string.VoipConnecting), true);
                } else if (state == VoIPService.STATE_EXCHANGING_KEYS) {
                    setStateTextAnimated(LocaleController.getString("VoipExchangingKeys", R.string.VoipExchangingKeys), true);
                } else if (state == VoIPService.STATE_WAITING) {
                    setStateTextAnimated(LocaleController.getString("VoipWaiting", R.string.VoipWaiting), true);
                } else if (state == VoIPService.STATE_RINGING) {
                    setStateTextAnimated(LocaleController.getString("VoipRinging", R.string.VoipRinging), true);
                } else if (state == VoIPService.STATE_REQUESTING) {
                    setStateTextAnimated(LocaleController.getString("VoipRequesting", R.string.VoipRequesting), true);
                } else if (state == VoIPService.STATE_HANGING_UP) {
                    setStateTextAnimated(LocaleController.getString("VoipHangingUp", R.string.VoipHangingUp), true);
                    endBtnIcon.setAlpha(.5f);
                    endBtn.setEnabled(false);
                } else if (state == VoIPBaseService.STATE_ENDED) {
                    setStateTextAnimated(LocaleController.getString("VoipCallEnded", R.string.VoipCallEnded), false);
                    stateText.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            finish();
                        }
                    }, 200);
                } else if (state == VoIPService.STATE_BUSY) {
                    endBtn.setContentDescription(LocaleController.getString("CallAgain", R.string.CallAgain));
                    //endBtn.setEnabled(false);
                    setStateTextAnimated(LocaleController.getString("VoipBusy", R.string.VoipBusy), false);
                    /*stateText.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            finish();
                        }
                    }, 2000);*/
                    showRetry();
                } else if (state == VoIPService.STATE_ESTABLISHED || state == VoIPService.STATE_RECONNECTING) {
                    /*if(VoIPService.getSharedInstance().canUpgrate()){
                        addMemberBtn.setEnabled(true);
                        addMemberBtn.setAlpha(1f);
                    }*/
                    setTitle(null);
                    if (!wasFirstStateChange && state == VoIPService.STATE_ESTABLISHED) {
                        int count = MessagesController.getGlobalMainSettings().getInt("call_emoji_tooltip_count", 0);
                        if (count < 3) {
                            setEmojiTooltipVisible(true);
                            hintTextView.postDelayed(tooltipHider = new Runnable() {
                                @Override
                                public void run() {
                                    tooltipHider = null;
                                    setEmojiTooltipVisible(false);
                                }
                            }, 5000);
                            MessagesController.getGlobalMainSettings().edit().putInt("call_emoji_tooltip_count", count + 1).commit();
                        }
                    }
                    if (prevState != VoIPService.STATE_ESTABLISHED && prevState != VoIPService.STATE_RECONNECTING) {
                        setStateTextAnimated("0:00", false);
                        startUpdatingCallDuration();
                        updateKeyView();
                        if (emojiWrap.getVisibility() != View.VISIBLE) {
                            emojiWrap.setVisibility(View.VISIBLE);
                            emojiWrap.setAlpha(0f);
                            emojiWrap.animate().alpha(1).setDuration(200).setInterpolator(new DecelerateInterpolator()).start();
                        }
                    }
                } else if (state == VoIPService.STATE_FAILED) {
                    setStateTextAnimated(LocaleController.getString("VoipFailed", R.string.VoipFailed), false);
                    final VoIPService voipService = VoIPService.getSharedInstance();
                    final String lastError = voipService != null ? voipService.getLastError() : TgVoip.ERROR_UNKNOWN;
                    if (!TextUtils.equals(lastError, TgVoip.ERROR_UNKNOWN)) {
                        if (TextUtils.equals(lastError, TgVoip.ERROR_INCOMPATIBLE)) {
                            final String name = ContactsController.formatName(user.first_name, user.last_name);
                            final String message = LocaleController.formatString("VoipPeerIncompatible", R.string.VoipPeerIncompatible, name);
                            showErrorDialog(AndroidUtilities.replaceTags(message));
                        } else if (TextUtils.equals(lastError, TgVoip.ERROR_PEER_OUTDATED)) {
                            final String name = ContactsController.formatName(user.first_name, user.last_name);
                            final String message = LocaleController.formatString("VoipPeerOutdated", R.string.VoipPeerOutdated, name);
                            showErrorDialog(AndroidUtilities.replaceTags(message));
                        } else if (TextUtils.equals(lastError, TgVoip.ERROR_PRIVACY)) {
                            final String name = ContactsController.formatName(user.first_name, user.last_name);
                            final String message = LocaleController.formatString("CallNotAvailable", R.string.CallNotAvailable, name);
                            showErrorDialog(AndroidUtilities.replaceTags(message));
                        } else if (TextUtils.equals(lastError, TgVoip.ERROR_AUDIO_IO)) {
                            showErrorDialog("Error initializing audio hardware");
                        } else if (TextUtils.equals(lastError, TgVoip.ERROR_LOCALIZED)) {
                            finish();
                        } else if (TextUtils.equals(lastError, TgVoip.ERROR_CONNECTION_SERVICE)) {
                            showErrorDialog(LocaleController.getString("VoipErrorUnknown", R.string.VoipErrorUnknown));
                        } else {
                            stateText.postDelayed(() -> finish(), 1000);
                        }
                    } else {
                        stateText.postDelayed(() -> finish(), 1000);
                    }
                }
                brandingText.invalidate();
            }
        });
    }

    @Override
    public void onSignalBarsCountChanged(final int count) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                signalBarsCount = count;
                brandingText.invalidate();
            }
        });
    }

    private void showErrorDialog(CharSequence message) {
        AlertDialog dlg = new DarkAlertDialog.Builder(VoIPActivity.this)
                .setTitle(LocaleController.getString("VoipFailed", R.string.VoipFailed))
                .setMessage(message)
                .setPositiveButton(LocaleController.getString("OK", R.string.OK), null)
                .show();
        dlg.setCanceledOnTouchOutside(true);
        dlg.setOnDismissListener(new DialogInterface.OnDismissListener() {
            @Override
            public void onDismiss(DialogInterface dialog) {
                finish();
            }
        });
    }

    @Override
    public void onAudioSettingsChanged() {
        VoIPBaseService svc = VoIPBaseService.getSharedInstance();
        if (svc == null)
            return;
        micToggle.setChecked(svc.isMicMute());
        if (!svc.hasEarpiece() && !svc.isBluetoothHeadsetConnected()) {
            spkToggle.setVisibility(View.INVISIBLE);
        } else {
            spkToggle.setVisibility(View.VISIBLE);
            if (!svc.hasEarpiece()) {
                spkToggle.setImageResource(R.drawable.ic_bluetooth_white_24dp);
                spkToggle.setChecked(svc.isSpeakerphoneOn());
            } else if (svc.isBluetoothHeadsetConnected()) {
                switch (svc.getCurrentAudioRoute()) {
                    case VoIPBaseService.AUDIO_ROUTE_BLUETOOTH:
                        spkToggle.setImageResource(R.drawable.ic_bluetooth_white_24dp);
                        break;
                    case VoIPBaseService.AUDIO_ROUTE_SPEAKER:
                        spkToggle.setImageResource(R.drawable.ic_volume_up_white_24dp);
                        break;
                    case VoIPBaseService.AUDIO_ROUTE_EARPIECE:
                        spkToggle.setImageResource(R.drawable.ic_phone_in_talk_white_24dp);
                        break;
                }
                spkToggle.setChecked(false);
            } else {
                spkToggle.setImageResource(R.drawable.ic_volume_up_white_24dp);
                spkToggle.setChecked(svc.isSpeakerphoneOn());
            }
        }
    }

    private void setStateTextAnimated(String _newText, boolean ellipsis) {
        if (_newText.equals(lastStateText))
            return;
        lastStateText = _newText;
        if (textChangingAnim != null)
            textChangingAnim.cancel();
        CharSequence newText;
        if (ellipsis) {
            if (!ellAnimator.isRunning())
                ellAnimator.start();
            SpannableStringBuilder ssb = new SpannableStringBuilder(_newText.toUpperCase());
            for (TextAlphaSpan s : ellSpans)
                s.setAlpha(0);
            SpannableString ell = new SpannableString("...");
            ell.setSpan(ellSpans[0], 0, 1, 0);
            ell.setSpan(ellSpans[1], 1, 2, 0);
            ell.setSpan(ellSpans[2], 2, 3, 0);
            ssb.append(ell);
            newText = ssb;
        } else {
            if (ellAnimator.isRunning())
                ellAnimator.cancel();
            newText = _newText.toUpperCase();
        }
        stateText2.setText(newText);
        stateText2.setVisibility(View.VISIBLE);
        stateText.setPivotX(LocaleController.isRTL ? stateText.getWidth() : 0);
        stateText.setPivotY(stateText.getHeight() / 2);
        stateText2.setPivotX(LocaleController.isRTL ? stateText.getWidth() : 0);
        stateText2.setPivotY(stateText.getHeight() / 2);
        durationText = stateText2;
        AnimatorSet set = new AnimatorSet();
        set.playTogether(
                ObjectAnimator.ofFloat(stateText2, View.ALPHA, 0, 1),
                ObjectAnimator.ofFloat(stateText2, View.TRANSLATION_Y, stateText.getHeight() / 2, 0),
                ObjectAnimator.ofFloat(stateText2, View.SCALE_X, 0.7f, 1),
                ObjectAnimator.ofFloat(stateText2, View.SCALE_Y, 0.7f, 1),
                ObjectAnimator.ofFloat(stateText, View.ALPHA, 1, 0),
                ObjectAnimator.ofFloat(stateText, View.TRANSLATION_Y, 0, -stateText.getHeight() / 2),
                ObjectAnimator.ofFloat(stateText, View.SCALE_X, 1, 0.7f),
                ObjectAnimator.ofFloat(stateText, View.SCALE_Y, 1, 0.7f)
        );
        set.setDuration(200);
        set.setInterpolator(CubicBezierInterpolator.DEFAULT);
        set.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                textChangingAnim = null;
                stateText2.setVisibility(View.GONE);
                durationText = stateText;
                stateText.setTranslationY(0);
                stateText.setScaleX(1);
                stateText.setScaleY(1);
                stateText.setAlpha(1);
                stateText.setText(stateText2.getText());
            }
        });
        textChangingAnim = set;
        set.start();
    }

    @Override
    public void didReceivedNotification(int id, int account, Object... args) {
        if (id == NotificationCenter.emojiDidLoad) {
            for (ImageView iv : keyEmojiViews) {
                iv.invalidate();
            }
        }
        if (id == NotificationCenter.closeInCallActivity) {
            finish();
        }
    }

    private void setEmojiTooltipVisible(boolean visible) {
        emojiTooltipVisible = visible;
        if (tooltipAnim != null)
            tooltipAnim.cancel();
        hintTextView.setVisibility(View.VISIBLE);
        ObjectAnimator oa = ObjectAnimator.ofFloat(hintTextView, View.ALPHA, visible ? 1 : 0);
        oa.setDuration(300);
        oa.setInterpolator(CubicBezierInterpolator.DEFAULT);
        oa.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                tooltipAnim = null;
            }
        });
        tooltipAnim = oa;
        oa.start();
    }

    private void setEmojiExpanded(boolean expanded) {
        if (emojiExpanded == expanded)
            return;
        emojiExpanded = expanded;
        if (emojiAnimator != null)
            emojiAnimator.cancel();
        if (expanded) {
            int[] loc = {0, 0}, loc2 = {0, 0};
            emojiWrap.getLocationInWindow(loc);
            emojiExpandedText.getLocationInWindow(loc2);
            Rect rect = new Rect();
            getWindow().getDecorView().getGlobalVisibleRect(rect);
            int offsetY = loc2[1] - (loc[1] + emojiWrap.getHeight()) - AndroidUtilities.dp(32) - emojiWrap.getHeight();
            int firstOffsetX = (rect.width() / 2 - Math.round(emojiWrap.getWidth() * 2.5f) / 2) - loc[0];
            AnimatorSet set = new AnimatorSet();
            set.playTogether(
                    ObjectAnimator.ofFloat(emojiWrap, View.TRANSLATION_Y, offsetY),
                    ObjectAnimator.ofFloat(emojiWrap, View.TRANSLATION_X, firstOffsetX),
                    ObjectAnimator.ofFloat(emojiWrap, View.SCALE_X, 2.5f),
                    ObjectAnimator.ofFloat(emojiWrap, View.SCALE_Y, 2.5f),
                    ObjectAnimator.ofFloat(blurOverlayView1, View.ALPHA, blurOverlayView1.getAlpha(), 1, 1),
                    ObjectAnimator.ofFloat(blurOverlayView2, View.ALPHA, blurOverlayView2.getAlpha(), blurOverlayView2.getAlpha(), 1),
                    ObjectAnimator.ofFloat(emojiExpandedText, View.ALPHA, 1)
            );
            set.setDuration(300);
            set.setInterpolator(CubicBezierInterpolator.DEFAULT);
            emojiAnimator = set;
            set.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    emojiAnimator = null;
                }
            });
            set.start();
        } else {
            AnimatorSet set = new AnimatorSet();
            set.playTogether(
                    ObjectAnimator.ofFloat(emojiWrap, View.TRANSLATION_X, 0),
                    ObjectAnimator.ofFloat(emojiWrap, View.TRANSLATION_Y, 0),
                    ObjectAnimator.ofFloat(emojiWrap, View.SCALE_X, 1),
                    ObjectAnimator.ofFloat(emojiWrap, View.SCALE_Y, 1),
                    ObjectAnimator.ofFloat(blurOverlayView1, View.ALPHA, blurOverlayView1.getAlpha(), blurOverlayView1.getAlpha(), 0),
                    ObjectAnimator.ofFloat(blurOverlayView2, View.ALPHA, blurOverlayView2.getAlpha(), 0, 0),
                    ObjectAnimator.ofFloat(emojiExpandedText, View.ALPHA, 0)
            );
            set.setDuration(300);
            set.setInterpolator(CubicBezierInterpolator.DEFAULT);
            emojiAnimator = set;
            set.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    emojiAnimator = null;
                }
            });
            set.start();
        }
    }

    private void updateBlurredPhotos(final ImageReceiver.BitmapHolder src) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Bitmap blur1 = Bitmap.createBitmap(150, 150, Bitmap.Config.ARGB_8888);
                    Canvas canvas = new Canvas(blur1);
                    canvas.drawBitmap(src.bitmap, null, new Rect(0, 0, 150, 150), new Paint(Paint.FILTER_BITMAP_FLAG));
                    Utilities.blurBitmap(blur1, 3, 0, blur1.getWidth(), blur1.getHeight(), blur1.getRowBytes());
                    final Palette palette = Palette.from(src.bitmap).generate();
                    Paint paint = new Paint();
                    paint.setColor((palette.getDarkMutedColor(0xFF547499) & 0x00FFFFFF) | 0x44000000);
                    canvas.drawColor(0x26000000);
                    canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), paint);
                    Bitmap blur2 = Bitmap.createBitmap(50, 50, Bitmap.Config.ARGB_8888);
                    canvas = new Canvas(blur2);
                    canvas.drawBitmap(src.bitmap, null, new Rect(0, 0, 50, 50), new Paint(Paint.FILTER_BITMAP_FLAG));
                    Utilities.blurBitmap(blur2, 3, 0, blur2.getWidth(), blur2.getHeight(), blur2.getRowBytes());
                    paint.setAlpha(0x66);
                    canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), paint);
                    blurredPhoto1 = blur1;
                    blurredPhoto2 = blur2;
                    runOnUiThread(() -> {
                        blurOverlayView1.setImageBitmap(blurredPhoto1);
                        blurOverlayView2.setImageBitmap(blurredPhoto2);
                        src.release();
                    });
                } catch (Throwable ignore) {

                }
            }
        }).start();
    }

    private void sendTextMessage(final String text) {
        AndroidUtilities.runOnUIThread(() -> SendMessagesHelper.getInstance(currentAccount).sendMessage(text, user.id, null, null, false, null, null, null, true, 0));
    }

    private void showMessagesSheet() {
        if (VoIPService.getSharedInstance() != null)
            VoIPService.getSharedInstance().stopRinging();
        SharedPreferences prefs = getSharedPreferences("mainconfig", MODE_PRIVATE);
        final String[] msgs = {prefs.getString("quick_reply_msg1", LocaleController.getString("QuickReplyDefault1", R.string.QuickReplyDefault1)),
                prefs.getString("quick_reply_msg2", LocaleController.getString("QuickReplyDefault2", R.string.QuickReplyDefault2)),
                prefs.getString("quick_reply_msg3", LocaleController.getString("QuickReplyDefault3", R.string.QuickReplyDefault3)),
                prefs.getString("quick_reply_msg4", LocaleController.getString("QuickReplyDefault4", R.string.QuickReplyDefault4))};
        LinearLayout sheetView = new LinearLayout(this);
        sheetView.setOrientation(LinearLayout.VERTICAL);
        final BottomSheet sheet = new BottomSheet(this, true);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            getWindow().setNavigationBarColor(0xff2b2b2b);
            sheet.setOnDismissListener(dialog -> getWindow().setNavigationBarColor(0));
        }
        View.OnClickListener listener = v -> {
            sheet.dismiss();
            if (VoIPService.getSharedInstance() != null)
                VoIPService.getSharedInstance().declineIncomingCall(VoIPService.DISCARD_REASON_LINE_BUSY, () -> sendTextMessage((String) v.getTag()));
        };
        for (String msg : msgs) {
            BottomSheet.BottomSheetCell cell = new BottomSheet.BottomSheetCell(this, 0);
            cell.setTextAndIcon(msg, 0);
            cell.setTextColor(0xFFFFFFFF);
            cell.setTag(msg);
            cell.setOnClickListener(listener);
            sheetView.addView(cell);
        }
        FrameLayout customWrap = new FrameLayout(this);
        final BottomSheet.BottomSheetCell cell = new BottomSheet.BottomSheetCell(this, 0);
        cell.setTextAndIcon(LocaleController.getString("QuickReplyCustom", R.string.QuickReplyCustom), 0);
        cell.setTextColor(0xFFFFFFFF);
        customWrap.addView(cell);

        final FrameLayout editor = new FrameLayout(this);
        final EditTextBoldCursor field = new EditTextBoldCursor(this);
        field.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16);
        field.setTextColor(0xFFFFFFFF);
        field.setHintTextColor(DarkTheme.getColor(Theme.key_chat_messagePanelHint));
        field.setBackgroundDrawable(null);
        field.setPadding(AndroidUtilities.dp(16), AndroidUtilities.dp(11), AndroidUtilities.dp(16), AndroidUtilities.dp(12));
        field.setHint(LocaleController.getString("QuickReplyCustom", R.string.QuickReplyCustom));
        field.setMinHeight(AndroidUtilities.dp(48));
        field.setGravity(Gravity.BOTTOM);
        field.setMaxLines(4);
        field.setSingleLine(false);
        field.setInputType(field.getInputType() | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE);
        editor.addView(field, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 48 : 0, 0, LocaleController.isRTL ? 0 : 48, 0));

        final ImageView sendBtn = new ImageView(this);
        sendBtn.setScaleType(ImageView.ScaleType.CENTER);
        sendBtn.setImageDrawable(DarkTheme.getThemedDrawable(this, R.drawable.ic_send, Theme.key_chat_messagePanelSend));
        if (LocaleController.isRTL)
            sendBtn.setScaleX(-0.1f);
        else
            sendBtn.setScaleX(0.1f);
        sendBtn.setScaleY(0.1f);
        sendBtn.setAlpha(0f);
        editor.addView(sendBtn, LayoutHelper.createFrame(48, 48, Gravity.BOTTOM | (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT)));
        sendBtn.setOnClickListener(v -> {
            if (field.length() == 0)
                return;
            sheet.dismiss();
            if (VoIPService.getSharedInstance() != null)
                VoIPService.getSharedInstance().declineIncomingCall(VoIPService.DISCARD_REASON_LINE_BUSY, new Runnable() {
                    @Override
                    public void run() {
                        sendTextMessage(field.getText().toString());
                    }
                });
        });
        sendBtn.setVisibility(View.INVISIBLE);

        final ImageView cancelBtn = new ImageView(this);
        cancelBtn.setScaleType(ImageView.ScaleType.CENTER);
        cancelBtn.setImageDrawable(DarkTheme.getThemedDrawable(this, R.drawable.edit_cancel, Theme.key_chat_messagePanelIcons));
        editor.addView(cancelBtn, LayoutHelper.createFrame(48, 48, Gravity.BOTTOM | (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT)));
        cancelBtn.setOnClickListener(v -> {
            editor.setVisibility(View.GONE);
            cell.setVisibility(View.VISIBLE);
            field.setText("");
            InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(field.getWindowToken(), 0);
        });

        field.addTextChangedListener(new TextWatcher() {
            boolean prevState = false;

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                boolean hasText = s.length() > 0;
                if (prevState != hasText) {
                    prevState = hasText;
                    if (hasText) {
                        sendBtn.setVisibility(View.VISIBLE);
                        sendBtn.animate().alpha(1).scaleX(LocaleController.isRTL ? -1 : 1).scaleY(1).setDuration(200).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
                        cancelBtn.animate().alpha(0).scaleX(0.1f).scaleY(0.1f).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(200).withEndAction(new Runnable() {
                            @Override
                            public void run() {
                                cancelBtn.setVisibility(View.INVISIBLE);
                            }
                        }).start();
                    } else {
                        cancelBtn.setVisibility(View.VISIBLE);
                        cancelBtn.animate().alpha(1).scaleX(1).scaleY(1).setDuration(200).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
                        sendBtn.animate().alpha(0).scaleX(LocaleController.isRTL ? -0.1f : 0.1f).scaleY(0.1f).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(200).withEndAction(new Runnable() {
                            @Override
                            public void run() {
                                sendBtn.setVisibility(View.INVISIBLE);
                            }
                        }).start();
                    }
                }
            }
        });

        editor.setVisibility(View.GONE);
        customWrap.addView(editor);

        cell.setOnClickListener(v -> {
            editor.setVisibility(View.VISIBLE);
            cell.setVisibility(View.INVISIBLE);
            field.requestFocus();
            InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
            imm.showSoftInput(field, 0);
        });

        sheetView.addView(customWrap);
        sheet.setCustomView(sheetView);
        sheet.setBackgroundColor(0xff2b2b2b);
        sheet.show();
    }

    private class TextAlphaSpan extends CharacterStyle {
        private int alpha;

        public TextAlphaSpan() {
            this.alpha = 0;
        }

        @Keep
        public int getAlpha() {
            return alpha;
        }

        @Keep
        public void setAlpha(int alpha) {
            this.alpha = alpha;
            stateText.invalidate();
            stateText2.invalidate();
        }

        @Override
        public void updateDrawState(TextPaint tp) {
            tp.setAlpha(alpha);
        }
    }

    private class SignalBarsDrawable extends Drawable {

        private int[] barHeights = {AndroidUtilities.dp(3), AndroidUtilities.dp(6), AndroidUtilities.dp(9), AndroidUtilities.dp(12)};
        private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        private RectF rect = new RectF();
        private int offsetStart = 6;

        @Override
        public void draw(Canvas canvas) {
            if (callState != VoIPService.STATE_ESTABLISHED && callState != VoIPService.STATE_RECONNECTING)
                return;
            paint.setColor(0xFFFFFFFF);
            int x = getBounds().left + AndroidUtilities.dp(LocaleController.isRTL ? 0 : offsetStart);
            int y = getBounds().top;
            for (int i = 0; i < 4; i++) {
                paint.setAlpha(i + 1 <= signalBarsCount ? 242 : 102);
                rect.set(x + AndroidUtilities.dp(4 * i), y + getIntrinsicHeight() - barHeights[i], x + AndroidUtilities.dp(4) * i + AndroidUtilities.dp(3), y + getIntrinsicHeight());
                canvas.drawRoundRect(rect, AndroidUtilities.dp(.3f), AndroidUtilities.dp(.3f), paint);
            }
        }

        @Override
        public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {

        }

        @Override
        public void setColorFilter(@Nullable ColorFilter colorFilter) {

        }

        @Override
        public int getIntrinsicWidth() {
            return AndroidUtilities.dp(15 + offsetStart);
        }

        @Override
        public int getIntrinsicHeight() {
            return AndroidUtilities.dp(12);
        }

        @Override
        public int getOpacity() {
            return PixelFormat.TRANSLUCENT;
        }
    }
}