/*
 * 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.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.NonNull;
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.EditText;
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.UserConfig;
import org.telegram.messenger.Utilities;
import org.telegram.messenger.voip.EncryptionKeyEmojifier;
import org.telegram.messenger.voip.VoIPBaseService;
import org.telegram.messenger.voip.VoIPController;
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.BackupImageView;
import org.telegram.ui.Components.CorrectlyMeasuringTextView;
import org.telegram.ui.Components.CubicBezierInterpolator;
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) {
                    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);
            contentView.setBackgroundDrawable(new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, new int[]{0xFF1b354e, 0xFF255b7d}));
        }

        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(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
				VoIPService svc=VoIPService.getSharedInstance();
                if (svc == null)
                    return;
				svc.toggleSpeakerphoneOrShowRouteSheet(VoIPActivity.this);
            }
        });
        micToggle.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (VoIPService.getSharedInstance() == null) {
                    finish();
                    return;
                }
                boolean checked = !micToggle.isChecked();
                micToggle.setChecked(checked);
                VoIPService.getSharedInstance().setMicMute(checked);
            }
        });
        chatBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(isIncomingWaiting){
                    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, "alpha", .2f),
                        ObjectAnimator.ofFloat(declineBtn, "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, "alpha", 1),
                        ObjectAnimator.ofFloat(declineBtn, "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, "alpha", .2f),
                        ObjectAnimator.ofFloat(acceptBtn, "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, "alpha", 1),
                        ObjectAnimator.ofFloat(acceptBtn, "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));

        ImageView chat=new ImageView(this);
        Drawable chatIcon=getResources().getDrawable(R.drawable.ic_chat_bubble_white_24dp).mutate();
        chatIcon.setAlpha(204);
        chat.setImageDrawable(chatIcon);
        chat.setScaleType(ImageView.ScaleType.CENTER);
        chat.setContentDescription(LocaleController.getString("AccDescrOpenChat", R.string.AccDescrOpenChat));
        wrap=new FrameLayout(this);
        wrap.addView(chatBtn=chat, 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("libtgvoip v"+VoIPController.getVersion());
        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;
                }
                debugText.setText(getFormattedDebugString());
                debugOverlay.postDelayed(this, 500);
            }
        };
        debugOverlay.postDelayed(r, 500);
    }

    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){
                    long duration=VoIPService.getSharedInstance().getCallDuration()/1000;
                    durationText.setText(duration>3600 ? String.format("%d:%02d:%02d", duration/3600, duration%3600/60, duration%60) : String.format("%d:%02d", duration/60, duration%60));
                    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, "rotation", -135, 0),
                    colorAnim
            );
            decSet.setInterpolator(CubicBezierInterpolator.EASE_OUT);
            decSet.setDuration(500);
            AnimatorSet accSet = new AnimatorSet();
            accSet.playTogether(
                    ObjectAnimator.ofFloat(swipeViewsWrap, "alpha", 1, 0),
                    ObjectAnimator.ofFloat(declineBtn, "alpha", 0),
                    ObjectAnimator.ofFloat(accountNameText, "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, "alpha", 0, 1)
            );
            decSet.setInterpolator(CubicBezierInterpolator.EASE_OUT);
            decSet.setDuration(500);
            AnimatorSet accSet = new AnimatorSet();
            accSet.playTogether(
                    ObjectAnimator.ofFloat(swipeViewsWrap, "alpha", 1, 0),
                    ObjectAnimator.ofFloat(declineBtn, "alpha", 0),
                    ObjectAnimator.ofFloat(acceptBtn, "alpha", 0),
                    ObjectAnimator.ofFloat(accountNameText, "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, "alpha", 0, 1),
                ObjectAnimator.ofFloat(endBtn, "translationX", 0, content.getWidth()/2-AndroidUtilities.dp(52)-endBtn.getWidth()/2),
                colorAnim,
                ObjectAnimator.ofFloat(endBtnIcon, "rotation", 0, -135)//,
                //ObjectAnimator.ofFloat(spkToggle, "alpha", 0),
                //ObjectAnimator.ofFloat(micToggle, "alpha", 0),
                //ObjectAnimator.ofFloat(chatBtn, "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, "translationX", 0),
                ObjectAnimator.ofFloat(cancelBtn, "alpha", 0)//,
                //ObjectAnimator.ofFloat(bottomButtons, "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.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);
                    int lastError=VoIPService.getSharedInstance()!=null ? VoIPService.getSharedInstance().getLastError() : VoIPController.ERROR_UNKNOWN;
                    if (lastError== VoIPController.ERROR_INCOMPATIBLE) {
                        showErrorDialog(AndroidUtilities.replaceTags(LocaleController.formatString("VoipPeerIncompatible", R.string.VoipPeerIncompatible,
                                        ContactsController.formatName(user.first_name, user.last_name))));
                    }else if (lastError== VoIPController.ERROR_PEER_OUTDATED) {
                        showErrorDialog(AndroidUtilities.replaceTags(LocaleController.formatString("VoipPeerOutdated", R.string.VoipPeerOutdated,
                                        ContactsController.formatName(user.first_name, user.last_name))));
                    }else if(lastError==VoIPController.ERROR_PRIVACY){
                        showErrorDialog(AndroidUtilities.replaceTags(LocaleController.formatString("CallNotAvailable", R.string.CallNotAvailable,
                                ContactsController.formatName(user.first_name, user.last_name))));
                    }else if(lastError==VoIPController.ERROR_AUDIO_IO){
                        showErrorDialog("Error initializing audio hardware");
                    }else if(lastError==VoIPController.ERROR_LOCALIZED){
                        finish();
                    }else if(lastError==VoIPController.ERROR_CONNECTION_SERVICE){
                        showErrorDialog(LocaleController.getString("VoipErrorUnknown", R.string.VoipErrorUnknown));
                    } else {
                        stateText.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                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, "alpha", 0, 1),
                ObjectAnimator.ofFloat(stateText2, "translationY", stateText.getHeight()/2, 0),
                ObjectAnimator.ofFloat(stateText2, "scaleX", 0.7f, 1),
                ObjectAnimator.ofFloat(stateText2, "scaleY", 0.7f, 1),
                ObjectAnimator.ofFloat(stateText, "alpha", 1, 0),
                ObjectAnimator.ofFloat(stateText, "translationY", 0, -stateText.getHeight()/2),
                ObjectAnimator.ofFloat(stateText, "scaleX", 1, 0.7f),
                ObjectAnimator.ofFloat(stateText, "scaleY", 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, "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, "translationY", offsetY),
                    ObjectAnimator.ofFloat(emojiWrap, "translationX", firstOffsetX),
                    ObjectAnimator.ofFloat(emojiWrap, "scaleX", 2.5f),
                    ObjectAnimator.ofFloat(emojiWrap, "scaleY", 2.5f),
                    ObjectAnimator.ofFloat(blurOverlayView1, "alpha", blurOverlayView1.getAlpha(), 1, 1),
                    ObjectAnimator.ofFloat(blurOverlayView2, "alpha", blurOverlayView2.getAlpha(), blurOverlayView2.getAlpha(), 1),
                    ObjectAnimator.ofFloat(emojiExpandedText, "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, "translationX", 0),
                    ObjectAnimator.ofFloat(emojiWrap, "translationY", 0),
					ObjectAnimator.ofFloat(emojiWrap, "scaleX", 1),
                    ObjectAnimator.ofFloat(emojiWrap, "scaleY", 1),
                    ObjectAnimator.ofFloat(blurOverlayView1, "alpha", blurOverlayView1.getAlpha(), blurOverlayView1.getAlpha(), 0),
                    ObjectAnimator.ofFloat(blurOverlayView2, "alpha", blurOverlayView2.getAlpha(), 0, 0),
                    ObjectAnimator.ofFloat(emojiExpandedText, "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(new Runnable() {
                        @Override
                        public void run() {
                            blurOverlayView1.setImageBitmap(blurredPhoto1);
                            blurOverlayView2.setImageBitmap(blurredPhoto2);
                            src.release();
                        }
                    });
                } catch (Throwable ignore) {

                }
            }
        }).start();
    }

    private void sendTextMessage(final String text){
        AndroidUtilities.runOnUIThread(new Runnable(){
            @Override
            public void run(){
                SendMessagesHelper.getInstance(currentAccount).sendMessage(text, user.id, null, null, false, null, null, null);
            }
        });
    }

    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, 0);
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP){
        	getWindow().setNavigationBarColor(0xff2b2b2b);
            sheet.setOnDismissListener(new DialogInterface.OnDismissListener(){
                @Override
                public void onDismiss(DialogInterface dialog){
                    getWindow().setNavigationBarColor(0);
                }
            });
        }
        View.OnClickListener listener=new View.OnClickListener(){
            @Override
            public void onClick(final View v){
                sheet.dismiss();
                if(VoIPService.getSharedInstance()!=null)
                    VoIPService.getSharedInstance().declineIncomingCall(VoIPService.DISCARD_REASON_LINE_BUSY, new Runnable(){
                        @Override
                        public void run(){
                            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 EditText field=new EditText(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(new View.OnClickListener(){
			@Override
			public void onClick(View 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(new View.OnClickListener(){
			@Override
			public void onClick(View 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(new View.OnClickListener(){
			@Override
			public void onClick(View 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;
        }

        public int getAlpha(){
            return alpha;
        }

        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(@NonNull 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;
        }
    }
}
