org.linphone.CallActivity.java Source code

Java tutorial

Introduction

Here is the source code for org.linphone.CallActivity.java

Source

package org.linphone;

/*
CallActivity.java
Copyright (C) 2015  Belledonne Communications, Grenoble, France
    
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
    
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
import android.Manifest;
import android.app.Activity;
import android.app.Dialog;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.DrawerLayout;
import android.text.Html;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.Chronometer;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCall.State;
import org.linphone.core.LinphoneCallParams;
import org.linphone.core.LinphoneCallStats;
import org.linphone.core.LinphoneCallStats.LinphoneAddressFamily;
import org.linphone.core.LinphoneChatMessage;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreListenerBase;
import org.linphone.core.LinphonePlayer;
import org.linphone.core.PayloadType;
import org.linphone.mediastream.Log;
import org.linphone.mediastream.video.capture.hwconf.AndroidCameraConfiguration;
import org.linphone.ui.Numpad;

import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @author Sylvain Berfini
 */
public class CallActivity extends LinphoneGenericActivity
        implements OnClickListener, ActivityCompat.OnRequestPermissionsResultCallback {
    private final static int SECONDS_BEFORE_HIDING_CONTROLS = 4000;
    private final static int SECONDS_BEFORE_DENYING_CALL_UPDATE = 30000;
    private static final int PERMISSIONS_REQUEST_CAMERA = 202;
    private static final int PERMISSIONS_ENABLED_CAMERA = 203;
    private static final int PERMISSIONS_ENABLED_MIC = 204;

    private static CallActivity instance;

    private Handler mControlsHandler = new Handler();
    private Runnable mControls;
    private ImageView switchCamera;
    private TextView missedChats;
    private RelativeLayout mActiveCallHeader, sideMenuContent, avatar_layout;
    private ImageView pause, hangUp, dialer, video, micro, speaker, options, addCall, transfer, conference,
            conferenceStatus, contactPicture;
    private ImageView audioRoute, routeSpeaker, routeEarpiece, routeBluetooth, menu, chat;
    private LinearLayout mNoCurrentCall, callInfo, mCallPaused;
    private ProgressBar videoProgress;
    private StatusFragment status;
    private CallAudioFragment audioCallFragment;
    private CallVideoFragment videoCallFragment;
    private boolean isSpeakerEnabled = false, isMicMuted = false, isTransferAllowed;
    private LinearLayout mControlsLayout;
    private Numpad numpad;
    private int cameraNumber;
    private CountDownTimer timer;
    private boolean isVideoCallPaused = false;
    private Dialog dialog = null;
    private static long TimeRemind = 0;

    private LinearLayout callsList, conferenceList;
    private LayoutInflater inflater;
    private ViewGroup container;
    private boolean isConferenceRunning = false;
    private LinphoneCoreListenerBase mListener;
    private DrawerLayout sideMenu;

    private Handler mHandler = new Handler();
    private Timer mTimer;
    private TimerTask mTask;
    private HashMap<String, String> mEncoderTexts;
    private HashMap<String, String> mDecoderTexts;

    public static CallActivity instance() {
        return instance;
    }

    public static boolean isInstanciated() {
        return instance != null;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        instance = this;

        if (getResources().getBoolean(R.bool.orientation_portrait_only)) {
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        }

        getWindow().addFlags(
                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
        setContentView(R.layout.call);

        isTransferAllowed = getApplicationContext().getResources().getBoolean(R.bool.allow_transfers);

        cameraNumber = AndroidCameraConfiguration.retrieveCameras().length;

        mEncoderTexts = new HashMap<String, String>();
        mDecoderTexts = new HashMap<String, String>();

        mListener = new LinphoneCoreListenerBase() {
            @Override
            public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message) {
                displayMissedChats();
            }

            @Override
            public void callState(LinphoneCore lc, final LinphoneCall call, LinphoneCall.State state,
                    String message) {
                if (LinphoneManager.getLc().getCallsNb() == 0) {
                    finish();
                    return;
                }

                if (state == State.IncomingReceived) {
                    startIncomingCallActivity();
                    return;
                } else if (state == State.Paused || state == State.PausedByRemote || state == State.Pausing) {
                    if (LinphoneManager.getLc().getCurrentCall() != null) {
                        enabledVideoButton(false);
                    }
                    if (isVideoEnabled(call)) {
                        showAudioView();
                    }
                } else if (state == State.Resuming) {
                    if (LinphonePreferences.instance().isVideoEnabled()) {
                        status.refreshStatusItems(call, isVideoEnabled(call));
                        if (call.getCurrentParams().getVideoEnabled()) {
                            showVideoView();
                        }
                    }
                    if (LinphoneManager.getLc().getCurrentCall() != null) {
                        enabledVideoButton(true);
                    }
                } else if (state == State.StreamsRunning) {
                    switchVideo(isVideoEnabled(call));
                    enableAndRefreshInCallActions();

                    if (status != null) {
                        videoProgress.setVisibility(View.GONE);
                        status.refreshStatusItems(call, isVideoEnabled(call));
                    }
                } else if (state == State.CallUpdatedByRemote) {
                    // If the correspondent proposes video while audio call
                    boolean videoEnabled = LinphonePreferences.instance().isVideoEnabled();
                    if (!videoEnabled) {
                        acceptCallUpdate(false);
                    }

                    boolean remoteVideo = call.getRemoteParams().getVideoEnabled();
                    boolean localVideo = call.getCurrentParams().getVideoEnabled();
                    boolean autoAcceptCameraPolicy = LinphonePreferences.instance()
                            .shouldAutomaticallyAcceptVideoRequests();
                    if (remoteVideo && !localVideo && !autoAcceptCameraPolicy
                            && !LinphoneManager.getLc().isInConference()) {
                        showAcceptCallUpdateDialog();
                        createTimerForDialog(SECONDS_BEFORE_DENYING_CALL_UPDATE);
                    }
                    //                 else if (remoteVideo && !LinphoneManager.getLc().isInConference() && autoAcceptCameraPolicy) {
                    //                    mHandler.post(new Runnable() {
                    //                       @Override
                    //                       public void run() {
                    //                          acceptCallUpdate(true);
                    //                       }
                    //                    });
                    //                 }
                }

                refreshIncallUi();
                transfer.setEnabled(LinphoneManager.getLc().getCurrentCall() != null);
            }

            @Override
            public void callEncryptionChanged(LinphoneCore lc, final LinphoneCall call, boolean encrypted,
                    String authenticationToken) {
                if (status != null) {
                    if (call.getCurrentParams().getMediaEncryption().equals(LinphoneCore.MediaEncryption.ZRTP)
                            && !call.isAuthenticationTokenVerified()) {
                        status.showZRTPDialog(call);
                    }
                    status.refreshStatusItems(call, call.getCurrentParams().getVideoEnabled());
                }
            }

        };

        if (findViewById(R.id.fragmentContainer) != null) {
            initUI();

            if (LinphoneManager.getLc().getCallsNb() > 0) {
                LinphoneCall call = LinphoneManager.getLc().getCalls()[0];

                if (LinphoneUtils.isCallEstablished(call)) {
                    enableAndRefreshInCallActions();
                }
            }
            if (savedInstanceState != null) {
                // Fragment already created, no need to create it again (else it will generate a memory leak with duplicated fragments)
                isSpeakerEnabled = savedInstanceState.getBoolean("Speaker");
                isMicMuted = savedInstanceState.getBoolean("Mic");
                isVideoCallPaused = savedInstanceState.getBoolean("VideoCallPaused");
                if (savedInstanceState.getBoolean("AskingVideo")) {
                    showAcceptCallUpdateDialog();
                    TimeRemind = savedInstanceState.getLong("TimeRemind");
                    createTimerForDialog(TimeRemind);
                }
                refreshInCallActions();
                return;
            } else {
                isSpeakerEnabled = LinphoneManager.getLc().isSpeakerEnabled();
                isMicMuted = LinphoneManager.getLc().isMicMuted();
            }

            Fragment callFragment;
            if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) {
                callFragment = new CallVideoFragment();
                videoCallFragment = (CallVideoFragment) callFragment;
                displayVideoCall(false);
                LinphoneManager.getInstance().routeAudioToSpeaker();
                isSpeakerEnabled = true;
            } else {
                callFragment = new CallAudioFragment();
                audioCallFragment = (CallAudioFragment) callFragment;
            }

            if (BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) {
                BluetoothManager.getInstance().routeAudioToBluetooth();
            }

            callFragment.setArguments(getIntent().getExtras());
            getFragmentManager().beginTransaction().add(R.id.fragmentContainer, callFragment)
                    .commitAllowingStateLoss();
        }
    }

    public void createTimerForDialog(long time) {
        timer = new CountDownTimer(time, 1000) {
            public void onTick(long millisUntilFinished) {
                TimeRemind = millisUntilFinished;
            }

            public void onFinish() {
                if (dialog != null) {
                    dialog.dismiss();
                    dialog = null;
                }
                acceptCallUpdate(false);
            }
        }.start();
    }

    private boolean isVideoEnabled(LinphoneCall call) {
        if (call != null) {
            return call.getCurrentParams().getVideoEnabled();
        }
        return false;
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putBoolean("Speaker", LinphoneManager.getLc().isSpeakerEnabled());
        outState.putBoolean("Mic", LinphoneManager.getLc().isMicMuted());
        outState.putBoolean("VideoCallPaused", isVideoCallPaused);
        outState.putBoolean("AskingVideo", (dialog != null));
        outState.putLong("TimeRemind", TimeRemind);
        if (dialog != null)
            dialog.dismiss();
        super.onSaveInstanceState(outState);
    }

    private boolean isTablet() {
        return getResources().getBoolean(R.bool.isTablet);
    }

    private void initUI() {
        inflater = LayoutInflater.from(this);
        container = (ViewGroup) findViewById(R.id.topLayout);
        callsList = (LinearLayout) findViewById(R.id.calls_list);
        conferenceList = (LinearLayout) findViewById(R.id.conference_list);

        //TopBar
        video = (ImageView) findViewById(R.id.video);
        video.setOnClickListener(this);
        enabledVideoButton(false);

        videoProgress = (ProgressBar) findViewById(R.id.video_in_progress);
        videoProgress.setVisibility(View.GONE);

        micro = (ImageView) findViewById(R.id.micro);
        micro.setOnClickListener(this);

        speaker = (ImageView) findViewById(R.id.speaker);
        speaker.setOnClickListener(this);

        options = (ImageView) findViewById(R.id.options);
        options.setOnClickListener(this);
        options.setEnabled(false);

        //BottonBar
        hangUp = (ImageView) findViewById(R.id.hang_up);
        hangUp.setOnClickListener(this);

        dialer = (ImageView) findViewById(R.id.dialer);
        dialer.setOnClickListener(this);

        numpad = (Numpad) findViewById(R.id.numpad);
        numpad.getBackground().setAlpha(240);

        chat = (ImageView) findViewById(R.id.chat);
        chat.setOnClickListener(this);
        missedChats = (TextView) findViewById(R.id.missed_chats);

        //Others

        //Active Call
        callInfo = (LinearLayout) findViewById(R.id.active_call_info);

        pause = (ImageView) findViewById(R.id.pause);
        pause.setOnClickListener(this);
        enabledPauseButton(false);

        mActiveCallHeader = (RelativeLayout) findViewById(R.id.active_call);
        mNoCurrentCall = (LinearLayout) findViewById(R.id.no_current_call);
        mCallPaused = (LinearLayout) findViewById(R.id.remote_pause);

        contactPicture = (ImageView) findViewById(R.id.contact_picture);
        avatar_layout = (RelativeLayout) findViewById(R.id.avatar_layout);

        //Options
        addCall = (ImageView) findViewById(R.id.add_call);
        addCall.setOnClickListener(this);
        addCall.setEnabled(false);

        transfer = (ImageView) findViewById(R.id.transfer);
        transfer.setOnClickListener(this);
        transfer.setEnabled(false);

        conference = (ImageView) findViewById(R.id.conference);
        conference.setEnabled(false);
        conference.setOnClickListener(this);

        try {
            audioRoute = (ImageView) findViewById(R.id.audio_route);
            audioRoute.setOnClickListener(this);
            routeSpeaker = (ImageView) findViewById(R.id.route_speaker);
            routeSpeaker.setOnClickListener(this);
            routeEarpiece = (ImageView) findViewById(R.id.route_earpiece);
            routeEarpiece.setOnClickListener(this);
            routeBluetooth = (ImageView) findViewById(R.id.route_bluetooth);
            routeBluetooth.setOnClickListener(this);
        } catch (NullPointerException npe) {
            Log.e("Bluetooth: Audio routes menu disabled on tablets for now (1)");
        }

        switchCamera = (ImageView) findViewById(R.id.switchCamera);
        switchCamera.setOnClickListener(this);

        mControlsLayout = (LinearLayout) findViewById(R.id.menu);

        if (!isTransferAllowed) {
            addCall.setBackgroundResource(R.drawable.options_add_call);
        }

        if (BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) {
            try {
                audioRoute.setVisibility(View.VISIBLE);
                speaker.setVisibility(View.GONE);
            } catch (NullPointerException npe) {
                Log.e("Bluetooth: Audio routes menu disabled on tablets for now (2)");
            }
        } else {
            try {
                audioRoute.setVisibility(View.GONE);
                speaker.setVisibility(View.VISIBLE);
            } catch (NullPointerException npe) {
                Log.e("Bluetooth: Audio routes menu disabled on tablets for now (3)");
            }
        }

        createInCallStats();
        LinphoneManager.getInstance().changeStatusToOnThePhone();
    }

    public void checkAndRequestPermission(String permission, int result) {
        int permissionGranted = getPackageManager().checkPermission(permission, getPackageName());
        Log.i("[Permission] " + permission + " is "
                + (permissionGranted == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));

        if (permissionGranted != PackageManager.PERMISSION_GRANTED) {
            if (LinphonePreferences.instance().firstTimeAskingForPermission(permission)
                    || ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
                Log.i("[Permission] Asking for " + permission);
                ActivityCompat.requestPermissions(this, new String[] { permission }, result);
            }
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, final int[] grantResults) {
        for (int i = 0; i < permissions.length; i++) {
            Log.i("[Permission] " + permissions[i] + " is "
                    + (grantResults[i] == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
        }

        switch (requestCode) {
        case PERMISSIONS_REQUEST_CAMERA:
            UIThreadDispatcher.dispatch(new Runnable() {
                @Override
                public void run() {
                    acceptCallUpdate(grantResults[0] == PackageManager.PERMISSION_GRANTED);
                }
            });
            break;
        case PERMISSIONS_ENABLED_CAMERA:
            UIThreadDispatcher.dispatch(new Runnable() {
                @Override
                public void run() {
                    disableVideo(grantResults[0] != PackageManager.PERMISSION_GRANTED);
                }
            });
            break;
        case PERMISSIONS_ENABLED_MIC:
            UIThreadDispatcher.dispatch(new Runnable() {
                @Override
                public void run() {
                    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                        toggleMicro();
                    }
                }
            });
            break;
        }
    }

    public void createInCallStats() {
        sideMenu = (DrawerLayout) findViewById(R.id.side_menu);
        menu = (ImageView) findViewById(R.id.call_quality);

        sideMenuContent = (RelativeLayout) findViewById(R.id.side_menu_content);

        menu.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                if (sideMenu.isDrawerVisible(Gravity.LEFT)) {
                    sideMenu.closeDrawer(sideMenuContent);
                } else {
                    sideMenu.openDrawer(sideMenuContent);
                }
            }
        });

        initCallStatsRefresher(LinphoneManager.getLc().getCurrentCall(), findViewById(R.id.incall_stats));
    }

    private void refreshIncallUi() {
        refreshInCallActions();
        refreshCallList(getResources());
        enableAndRefreshInCallActions();
        displayMissedChats();
    }

    protected void setSpeakerEnabled(boolean enabled) {
        isSpeakerEnabled = enabled;
    }

    protected void refreshInCallActions() {
        if (!LinphonePreferences.instance().isVideoEnabled() || isConferenceRunning) {
            enabledVideoButton(false);
        } else {
            if (video.isEnabled()) {
                if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) {
                    video.setImageResource(R.drawable.camera_selected);
                    videoProgress.setVisibility(View.INVISIBLE);
                } else {
                    video.setImageResource(R.drawable.camera_button);
                }
            } else {
                video.setImageResource(R.drawable.camera_button);
            }
        }
        if (getPackageManager().checkPermission(Manifest.permission.CAMERA,
                getPackageName()) != PackageManager.PERMISSION_GRANTED) {
            video.setImageResource(R.drawable.camera_button);
        }

        if (isSpeakerEnabled) {
            speaker.setImageResource(R.drawable.speaker_selected);
        } else {
            speaker.setImageResource(R.drawable.speaker_default);
        }

        if (getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO,
                getPackageName()) != PackageManager.PERMISSION_GRANTED) {
            isMicMuted = true;
        }
        if (isMicMuted) {
            micro.setImageResource(R.drawable.micro_selected);
        } else {
            micro.setImageResource(R.drawable.micro_default);
        }

        try {
            if (isSpeakerEnabled) {
                routeSpeaker.setImageResource(R.drawable.route_speaker_selected);
                routeEarpiece.setImageResource(R.drawable.route_earpiece);
                routeBluetooth.setImageResource(R.drawable.route_bluetooth);
            }

            routeSpeaker.setImageResource(R.drawable.route_speaker);
            if (BluetoothManager.getInstance().isUsingBluetoothAudioRoute()) {
                routeEarpiece.setImageResource(R.drawable.route_earpiece);
                routeBluetooth.setImageResource(R.drawable.route_bluetooth_selected);
            } else {
                routeEarpiece.setImageResource(R.drawable.route_earpiece_selected);
                routeBluetooth.setImageResource(R.drawable.route_bluetooth);
            }
        } catch (NullPointerException npe) {
            Log.e("Bluetooth: Audio routes menu disabled on tablets for now (4)");
        }
    }

    private void enableAndRefreshInCallActions() {
        int confsize = 0;

        if (LinphoneManager.getLc().isInConference()) {
            confsize = LinphoneManager.getLc().getConferenceSize()
                    - (LinphoneManager.getLc().isInConference() ? 1 : 0);
        }

        //Enabled transfer button
        if (isTransferAllowed && !LinphoneManager.getLc().soundResourcesLocked())
            enabledTransferButton(true);

        //Enable conference button
        if (LinphoneManager.getLc().getCallsNb() > 1 && LinphoneManager.getLc().getCallsNb() > confsize
                && !LinphoneManager.getLc().soundResourcesLocked()) {
            enabledConferenceButton(true);
        } else {
            enabledConferenceButton(false);
        }

        addCall.setEnabled(LinphoneManager.getLc().getCallsNb() < LinphoneManager.getLc().getMaxCalls()
                && !LinphoneManager.getLc().soundResourcesLocked());
        options.setEnabled(!getResources().getBoolean(R.bool.disable_options_in_call)
                && (addCall.isEnabled() || transfer.isEnabled()));

        if (LinphoneManager.getLc().getCurrentCall() != null && LinphonePreferences.instance().isVideoEnabled()
                && !LinphoneManager.getLc().getCurrentCall().mediaInProgress()) {
            enabledVideoButton(true);
        } else {
            enabledVideoButton(false);
        }
        if (LinphoneManager.getLc().getCurrentCall() != null
                && !LinphoneManager.getLc().getCurrentCall().mediaInProgress()) {
            enabledPauseButton(true);
        } else {
            enabledPauseButton(false);
        }
        micro.setEnabled(true);
        if (!isTablet()) {
            speaker.setEnabled(true);
        }
        transfer.setEnabled(true);
        pause.setEnabled(true);
        dialer.setEnabled(true);
    }

    public void updateStatusFragment(StatusFragment statusFragment) {
        status = statusFragment;
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();

        if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) {
            //displayVideoCallControlsIfHidden();
        }

        if (id == R.id.video) {
            int camera = getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName());
            Log.i("[Permission] Camera permission is "
                    + (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));

            if (camera == PackageManager.PERMISSION_GRANTED) {
                disableVideo(isVideoEnabled(LinphoneManager.getLc().getCurrentCall()));
            } else {
                checkAndRequestPermission(Manifest.permission.CAMERA, PERMISSIONS_ENABLED_CAMERA);

            }
        } else if (id == R.id.micro) {
            int recordAudio = getPackageManager().checkPermission(Manifest.permission.RECORD_AUDIO,
                    getPackageName());
            Log.i("[Permission] Record audio permission is "
                    + (recordAudio == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));

            if (recordAudio == PackageManager.PERMISSION_GRANTED) {
                toggleMicro();
            } else {
                checkAndRequestPermission(Manifest.permission.RECORD_AUDIO, PERMISSIONS_ENABLED_MIC);
            }
        } else if (id == R.id.speaker) {
            toggleSpeaker();
        } else if (id == R.id.add_call) {
            goBackToDialer();
        } else if (id == R.id.pause) {
            pauseOrResumeCall(LinphoneManager.getLc().getCurrentCall());
        } else if (id == R.id.hang_up) {
            hangUp();
        } else if (id == R.id.dialer) {
            hideOrDisplayNumpad();
        } else if (id == R.id.chat) {
            goToChatList();
        } else if (id == R.id.conference) {
            enterConference();
            hideOrDisplayCallOptions();
        } else if (id == R.id.switchCamera) {
            if (videoCallFragment != null) {
                videoCallFragment.switchCamera();
            }
        } else if (id == R.id.transfer) {
            goBackToDialerAndDisplayTransferButton();
        } else if (id == R.id.options) {
            hideOrDisplayCallOptions();
        } else if (id == R.id.audio_route) {
            hideOrDisplayAudioRoutes();
        } else if (id == R.id.route_bluetooth) {
            if (BluetoothManager.getInstance().routeAudioToBluetooth()) {
                isSpeakerEnabled = false;
                routeBluetooth.setImageResource(R.drawable.route_bluetooth_selected);
                routeSpeaker.setImageResource(R.drawable.route_speaker);
                routeEarpiece.setImageResource(R.drawable.route_earpiece);
            }
            hideOrDisplayAudioRoutes();
        } else if (id == R.id.route_earpiece) {
            LinphoneManager.getInstance().routeAudioToReceiver();
            isSpeakerEnabled = false;
            routeBluetooth.setImageResource(R.drawable.route_bluetooth);
            routeSpeaker.setImageResource(R.drawable.route_speaker);
            routeEarpiece.setImageResource(R.drawable.route_earpiece_selected);
            hideOrDisplayAudioRoutes();
        } else if (id == R.id.route_speaker) {
            LinphoneManager.getInstance().routeAudioToSpeaker();
            isSpeakerEnabled = true;
            routeBluetooth.setImageResource(R.drawable.route_bluetooth);
            routeSpeaker.setImageResource(R.drawable.route_speaker_selected);
            routeEarpiece.setImageResource(R.drawable.route_earpiece);
            hideOrDisplayAudioRoutes();
        }

        else if (id == R.id.call_pause) {
            LinphoneCall call = (LinphoneCall) v.getTag();
            pauseOrResumeCall(call);
        } else if (id == R.id.conference_pause) {
            pauseOrResumeConference();
        }
    }

    private void enabledVideoButton(boolean enabled) {
        if (enabled) {
            video.setEnabled(true);
        } else {
            video.setEnabled(false);
        }
    }

    private void enabledPauseButton(boolean enabled) {
        if (enabled) {
            pause.setEnabled(true);
            pause.setImageResource(R.drawable.pause_big_default);
        } else {
            pause.setEnabled(false);
            pause.setImageResource(R.drawable.pause_big_disabled);
        }
    }

    private void enabledTransferButton(boolean enabled) {
        if (enabled) {
            transfer.setEnabled(true);
        } else {
            transfer.setEnabled(false);
        }
    }

    private void enabledConferenceButton(boolean enabled) {
        if (enabled) {
            conference.setEnabled(true);
        } else {
            conference.setEnabled(false);
        }
    }

    private void disableVideo(final boolean videoDisabled) {
        final LinphoneCall call = LinphoneManager.getLc().getCurrentCall();
        if (call == null) {
            return;
        }

        if (videoDisabled) {
            LinphoneCallParams params = LinphoneManager.getLc().createCallParams(call);
            params.setVideoEnabled(false);
            LinphoneManager.getLc().updateCall(call, params);
        } else {
            videoProgress.setVisibility(View.VISIBLE);
            if (call.getRemoteParams() != null && !call.getRemoteParams().isLowBandwidthEnabled()) {
                LinphoneManager.getInstance().addVideo();
            } else {
                displayCustomToast(getString(R.string.error_low_bandwidth), Toast.LENGTH_LONG);
            }
        }
    }

    public void displayCustomToast(final String message, final int duration) {
        LayoutInflater inflater = getLayoutInflater();
        View layout = inflater.inflate(R.layout.toast, (ViewGroup) findViewById(R.id.toastRoot));

        TextView toastText = (TextView) layout.findViewById(R.id.toastMessage);
        toastText.setText(message);

        final Toast toast = new Toast(getApplicationContext());
        toast.setGravity(Gravity.CENTER, 0, 0);
        toast.setDuration(duration);
        toast.setView(layout);
        toast.show();
    }

    private void switchVideo(final boolean displayVideo) {
        final LinphoneCall call = LinphoneManager.getLc().getCurrentCall();
        if (call == null) {
            return;
        }

        //Check if the call is not terminated
        if (call.getState() == State.CallEnd || call.getState() == State.CallReleased)
            return;

        if (!displayVideo) {
            showAudioView();
        } else {
            if (!call.getRemoteParams().isLowBandwidthEnabled()) {
                LinphoneManager.getInstance().addVideo();
                if (videoCallFragment == null || !videoCallFragment.isVisible())
                    showVideoView();
            } else {
                displayCustomToast(getString(R.string.error_low_bandwidth), Toast.LENGTH_LONG);
            }
        }
    }

    private void showAudioView() {
        if (LinphoneManager.getLc().getCurrentCall() != null) {
            LinphoneManager.getInstance().enableProximitySensing(true);
        }
        replaceFragmentVideoByAudio();
        displayAudioCall();
        showStatusBar();
        removeCallbacks();
    }

    private void showVideoView() {
        if (!BluetoothManager.getInstance().isBluetoothHeadsetAvailable()) {
            Log.w("Bluetooth not available, using speaker");
            LinphoneManager.getInstance().routeAudioToSpeaker();
            isSpeakerEnabled = true;
        }
        refreshInCallActions();

        LinphoneManager.getInstance().enableProximitySensing(false);

        replaceFragmentAudioByVideo();
        hideStatusBar();
    }

    private void displayNoCurrentCall(boolean display) {
        if (!display) {
            mActiveCallHeader.setVisibility(View.VISIBLE);
            mNoCurrentCall.setVisibility(View.GONE);
        } else {
            mActiveCallHeader.setVisibility(View.GONE);
            mNoCurrentCall.setVisibility(View.VISIBLE);
        }
    }

    private void displayCallPaused(boolean display) {
        if (display) {
            mCallPaused.setVisibility(View.VISIBLE);
        } else {
            mCallPaused.setVisibility(View.GONE);
        }
    }

    private void displayAudioCall() {
        mControlsLayout.setVisibility(View.VISIBLE);
        mActiveCallHeader.setVisibility(View.VISIBLE);
        callInfo.setVisibility(View.VISIBLE);
        avatar_layout.setVisibility(View.VISIBLE);
        switchCamera.setVisibility(View.GONE);
    }

    private void replaceFragmentVideoByAudio() {
        audioCallFragment = new CallAudioFragment();
        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        transaction.replace(R.id.fragmentContainer, audioCallFragment);
        try {
            transaction.commitAllowingStateLoss();
        } catch (Exception e) {
        }
    }

    private void replaceFragmentAudioByVideo() {
        //      Hiding controls to let displayVideoCallControlsIfHidden add them plus the callback
        videoCallFragment = new CallVideoFragment();

        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        transaction.replace(R.id.fragmentContainer, videoCallFragment);
        try {
            transaction.commitAllowingStateLoss();
        } catch (Exception e) {
        }
    }

    private void toggleMicro() {
        LinphoneCore lc = LinphoneManager.getLc();
        isMicMuted = !isMicMuted;
        lc.muteMic(isMicMuted);
        if (isMicMuted) {
            micro.setImageResource(R.drawable.micro_selected);
        } else {
            micro.setImageResource(R.drawable.micro_default);
        }
    }

    protected void toggleSpeaker() {
        isSpeakerEnabled = !isSpeakerEnabled;
        if (isSpeakerEnabled) {
            LinphoneManager.getInstance().routeAudioToSpeaker();
            speaker.setImageResource(R.drawable.speaker_selected);
            LinphoneManager.getLc().enableSpeaker(isSpeakerEnabled);
        } else {
            Log.d("Toggle speaker off, routing back to earpiece");
            LinphoneManager.getInstance().routeAudioToReceiver();
            speaker.setImageResource(R.drawable.speaker_default);
        }
    }

    public void pauseOrResumeCall(LinphoneCall call) {
        LinphoneCore lc = LinphoneManager.getLc();
        if (call != null && LinphoneManager.getLc().getCurrentCall() == call) {
            lc.pauseCall(call);
            if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) {
                isVideoCallPaused = true;
            }
            pause.setImageResource(R.drawable.pause_big_over_selected);
        } else if (call != null) {
            if (call.getState() == State.Paused) {
                lc.resumeCall(call);
                if (isVideoCallPaused) {
                    isVideoCallPaused = false;
                }
                pause.setImageResource(R.drawable.pause_big_default);
            }
        }
    }

    private void hangUp() {
        LinphoneCore lc = LinphoneManager.getLc();
        LinphoneCall currentCall = lc.getCurrentCall();

        if (currentCall != null) {
            lc.terminateCall(currentCall);
        } else if (lc.isInConference()) {
            lc.terminateConference();
        } else {
            lc.terminateAllCalls();
        }
    }

    public void displayVideoCall(boolean display) {
        if (display) {
            showStatusBar();
            mControlsLayout.setVisibility(View.VISIBLE);
            mActiveCallHeader.setVisibility(View.VISIBLE);
            callInfo.setVisibility(View.VISIBLE);
            avatar_layout.setVisibility(View.GONE);
            callsList.setVisibility(View.VISIBLE);
            if (cameraNumber > 1) {
                switchCamera.setVisibility(View.VISIBLE);
            }
        } else {
            hideStatusBar();
            mControlsLayout.setVisibility(View.GONE);
            mActiveCallHeader.setVisibility(View.GONE);
            switchCamera.setVisibility(View.GONE);
            callsList.setVisibility(View.GONE);
        }
    }

    public void displayVideoCallControlsIfHidden() {
        if (mControlsLayout != null) {
            if (mControlsLayout.getVisibility() != View.VISIBLE) {
                displayVideoCall(true);
            }
            resetControlsHidingCallBack();
        }
    }

    public void resetControlsHidingCallBack() {
        if (mControlsHandler != null && mControls != null) {
            mControlsHandler.removeCallbacks(mControls);
        }
        mControls = null;

        if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall()) && mControlsHandler != null) {
            mControlsHandler.postDelayed(mControls = new Runnable() {
                public void run() {
                    hideNumpad();
                    video.setEnabled(true);
                    transfer.setVisibility(View.INVISIBLE);
                    addCall.setVisibility(View.INVISIBLE);
                    conference.setVisibility(View.INVISIBLE);
                    displayVideoCall(false);
                    numpad.setVisibility(View.GONE);
                    options.setImageResource(R.drawable.options_default);
                }
            }, SECONDS_BEFORE_HIDING_CONTROLS);
        }
    }

    public void removeCallbacks() {
        if (mControlsHandler != null && mControls != null) {
            mControlsHandler.removeCallbacks(mControls);
        }
        mControls = null;
    }

    private void hideNumpad() {
        if (numpad == null || numpad.getVisibility() != View.VISIBLE) {
            return;
        }

        dialer.setImageResource(R.drawable.footer_dialer);
        numpad.setVisibility(View.GONE);
    }

    private void hideOrDisplayNumpad() {
        if (numpad == null) {
            return;
        }

        if (numpad.getVisibility() == View.VISIBLE) {
            hideNumpad();
        } else {
            dialer.setImageResource(R.drawable.dialer_alt_back);
            numpad.setVisibility(View.VISIBLE);
        }
    }

    private void hideOrDisplayAudioRoutes() {
        if (routeSpeaker.getVisibility() == View.VISIBLE) {
            routeSpeaker.setVisibility(View.INVISIBLE);
            routeBluetooth.setVisibility(View.INVISIBLE);
            routeEarpiece.setVisibility(View.INVISIBLE);
        } else {
            routeSpeaker.setVisibility(View.VISIBLE);
            routeBluetooth.setVisibility(View.VISIBLE);
            routeEarpiece.setVisibility(View.VISIBLE);
        }
    }

    private void hideOrDisplayCallOptions() {
        //Hide options
        if (addCall.getVisibility() == View.VISIBLE) {
            options.setImageResource(R.drawable.options_default);
            if (isTransferAllowed) {
                transfer.setVisibility(View.INVISIBLE);
            }
            addCall.setVisibility(View.INVISIBLE);
            conference.setVisibility(View.INVISIBLE);
        } else { //Display options
            if (isTransferAllowed) {
                transfer.setVisibility(View.VISIBLE);
            }
            addCall.setVisibility(View.VISIBLE);
            conference.setVisibility(View.VISIBLE);
            options.setImageResource(R.drawable.options_selected);
            transfer.setEnabled(LinphoneManager.getLc().getCurrentCall() != null);
        }
    }

    public void goBackToDialer() {
        Intent intent = new Intent();
        intent.putExtra("Transfer", false);
        setResult(Activity.RESULT_FIRST_USER, intent);
        finish();
    }

    private void goBackToDialerAndDisplayTransferButton() {
        Intent intent = new Intent();
        intent.putExtra("Transfer", true);
        setResult(Activity.RESULT_FIRST_USER, intent);
        finish();
    }

    private void goToChatList() {
        Intent intent = new Intent();
        intent.putExtra("chat", true);
        setResult(Activity.RESULT_FIRST_USER, intent);
        finish();
    }

    public void acceptCallUpdate(boolean accept) {
        if (timer != null) {
            timer.cancel();
        }

        LinphoneCall call = LinphoneManager.getLc().getCurrentCall();
        if (call == null) {
            return;
        }

        LinphoneCallParams params = LinphoneManager.getLc().createCallParams(call);
        if (accept) {
            params.setVideoEnabled(true);
            LinphoneManager.getLc().enableVideo(true, true);
        }

        try {
            LinphoneManager.getLc().acceptCallUpdate(call, params);
        } catch (LinphoneCoreException e) {
            Log.e(e);
        }
    }

    public void startIncomingCallActivity() {
        startActivity(new Intent(this, CallIncomingActivity.class));
    }

    public void hideStatusBar() {
        if (isTablet()) {
            return;
        }

        findViewById(R.id.status).setVisibility(View.GONE);
        findViewById(R.id.fragmentContainer).setPadding(0, 0, 0, 0);
    }

    public void showStatusBar() {
        if (isTablet()) {
            return;
        }

        if (status != null && !status.isVisible()) {
            // Hack to ensure statusFragment is visible after coming back to
            // dialer from chat
            status.getView().setVisibility(View.VISIBLE);
        }
        findViewById(R.id.status).setVisibility(View.VISIBLE);
        //findViewById(R.id.fragmentContainer).setPadding(0, LinphoneUtils.pixelsToDpi(getResources(), 40), 0, 0);
    }

    private void showAcceptCallUpdateDialog() {
        dialog = new Dialog(this);
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
        Drawable d = new ColorDrawable(ContextCompat.getColor(this, R.color.colorC));
        d.setAlpha(200);
        dialog.setContentView(R.layout.dialog);
        dialog.getWindow().setLayout(WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.MATCH_PARENT);
        dialog.getWindow().setBackgroundDrawable(d);

        TextView customText = (TextView) dialog.findViewById(R.id.customText);
        customText.setText(getResources().getString(R.string.add_video_dialog));
        Button delete = (Button) dialog.findViewById(R.id.delete_button);
        delete.setText(R.string.accept);
        Button cancel = (Button) dialog.findViewById(R.id.cancel);
        cancel.setText(R.string.decline);

        delete.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                int camera = getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName());
                Log.i("[Permission] Camera permission is "
                        + (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));

                if (camera == PackageManager.PERMISSION_GRANTED) {
                    CallActivity.instance().acceptCallUpdate(true);
                } else {
                    checkAndRequestPermission(Manifest.permission.CAMERA, PERMISSIONS_REQUEST_CAMERA);
                }

                dialog.dismiss();
                dialog = null;
            }
        });

        cancel.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                if (CallActivity.isInstanciated()) {
                    CallActivity.instance().acceptCallUpdate(false);
                }
                dialog.dismiss();
                dialog = null;
            }
        });
        dialog.show();
    }

    @Override
    protected void onResume() {

        instance = this;
        super.onResume();

        LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
        if (lc != null) {
            lc.addListener(mListener);
        }
        isSpeakerEnabled = LinphoneManager.getLc().isSpeakerEnabled();

        refreshIncallUi();
        handleViewIntent();

        if (!isVideoEnabled(LinphoneManager.getLc().getCurrentCall())) {
            LinphoneManager.getInstance().enableProximitySensing(true);
            removeCallbacks();
        }
    }

    private void handleViewIntent() {
        Intent intent = getIntent();
        if (intent != null && intent.getAction() == "android.intent.action.VIEW") {
            LinphoneCall call = LinphoneManager.getLc().getCurrentCall();
            if (call != null && isVideoEnabled(call)) {
                LinphonePlayer player = call.getPlayer();
                String path = intent.getData().getPath();
                Log.i("Openning " + path);
                int openRes = player.open(path, new LinphonePlayer.Listener() {

                    @Override
                    public void endOfFile(LinphonePlayer player) {
                        player.close();
                    }
                });
                if (openRes == -1) {
                    String message = "Could not open " + path;
                    Log.e(message);
                    Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
                    return;
                }
                Log.i("Start playing");
                if (player.start() == -1) {
                    player.close();
                    String message = "Could not start playing " + path;
                    Log.e(message);
                    Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
                }
            }
        }
    }

    @Override
    protected void onPause() {
        LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
        if (lc != null) {
            lc.removeListener(mListener);
        }

        super.onPause();

        if (mControlsHandler != null && mControls != null) {
            mControlsHandler.removeCallbacks(mControls);
        }
        mControls = null;
    }

    @Override
    protected void onDestroy() {
        LinphoneManager.getInstance().changeStatusToOnline();

        if (mControlsHandler != null && mControls != null) {
            mControlsHandler.removeCallbacks(mControls);
        }
        mControls = null;
        mControlsHandler = null;

        unbindDrawables(findViewById(R.id.topLayout));
        if (mTimer != null) {
            mTimer.cancel();
        }
        instance = null;
        super.onDestroy();
        System.gc();
    }

    private void unbindDrawables(View view) {
        if (view.getBackground() != null) {
            view.getBackground().setCallback(null);
        }
        if (view instanceof ImageView) {
            view.setOnClickListener(null);
        }
        if (view instanceof ViewGroup && !(view instanceof AdapterView)) {
            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
                unbindDrawables(((ViewGroup) view).getChildAt(i));
            }
            ((ViewGroup) view).removeAllViews();
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (LinphoneUtils.onKeyVolumeAdjust(keyCode))
            return true;
        if (LinphoneUtils.onKeyBackGoHome(this, keyCode, event))
            return true;
        return super.onKeyDown(keyCode, event);
    }

    @Override // Never invoke actually
    public void onBackPressed() {
        if (dialog != null) {
            acceptCallUpdate(false);
            dialog.dismiss();
            dialog = null;
        }
        return;
    }

    public void bindAudioFragment(CallAudioFragment fragment) {
        audioCallFragment = fragment;
    }

    public void bindVideoFragment(CallVideoFragment fragment) {
        videoCallFragment = fragment;
    }

    //CALL INFORMATION
    private void displayCurrentCall(LinphoneCall call) {
        LinphoneAddress lAddress = call.getRemoteAddress();
        TextView contactName = (TextView) findViewById(R.id.current_contact_name);
        setContactInformation(contactName, contactPicture, lAddress);
        registerCallDurationTimer(null, call);
    }

    private void displayPausedCalls(Resources resources, final LinphoneCall call, int index) {
        // Control Row
        LinearLayout callView;

        if (call == null) {
            callView = (LinearLayout) inflater.inflate(R.layout.conference_paused_row, container, false);
            callView.setId(index + 1);
            callView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View view) {
                    pauseOrResumeConference();
                }
            });
        } else {
            callView = (LinearLayout) inflater.inflate(R.layout.call_inactive_row, container, false);
            callView.setId(index + 1);

            TextView contactName = (TextView) callView.findViewById(R.id.contact_name);
            ImageView contactImage = (ImageView) callView.findViewById(R.id.contact_picture);

            LinphoneAddress lAddress = call.getRemoteAddress();
            setContactInformation(contactName, contactImage, lAddress);
            displayCallStatusIconAndReturnCallPaused(callView, call);
            registerCallDurationTimer(callView, call);
        }
        callsList.addView(callView);
    }

    private void setContactInformation(TextView contactName, ImageView contactPicture, LinphoneAddress lAddress) {
        LinphoneContact lContact = ContactsManager.getInstance().findContactFromAddress(lAddress);
        if (lContact == null) {
            contactName.setText(LinphoneUtils.getAddressDisplayName(lAddress));
            contactPicture.setImageBitmap(ContactsManager.getInstance().getDefaultAvatarBitmap());
        } else {
            contactName.setText(lContact.getFullName());
            LinphoneUtils.setImagePictureFromUri(contactPicture.getContext(), contactPicture,
                    lContact.getPhotoUri(), lContact.getThumbnailUri());
        }
    }

    private boolean displayCallStatusIconAndReturnCallPaused(LinearLayout callView, LinphoneCall call) {
        boolean isCallPaused, isInConference;
        ImageView callState = (ImageView) callView.findViewById(R.id.call_pause);
        callState.setTag(call);
        callState.setOnClickListener(this);

        if (call.getState() == State.Paused || call.getState() == State.PausedByRemote
                || call.getState() == State.Pausing) {
            callState.setImageResource(R.drawable.pause);
            isCallPaused = true;
            isInConference = false;
        } else if (call.getState() == State.OutgoingInit || call.getState() == State.OutgoingProgress
                || call.getState() == State.OutgoingRinging) {
            isCallPaused = false;
            isInConference = false;
        } else {
            isInConference = isConferenceRunning && call.isInConference();
            isCallPaused = false;
        }

        return isCallPaused || isInConference;
    }

    private void registerCallDurationTimer(View v, LinphoneCall call) {
        int callDuration = call.getDuration();
        if (callDuration == 0 && call.getState() != State.StreamsRunning) {
            return;
        }

        Chronometer timer;
        if (v == null) {
            timer = (Chronometer) findViewById(R.id.current_call_timer);
        } else {
            timer = (Chronometer) v.findViewById(R.id.call_timer);
        }

        if (timer == null) {
            throw new IllegalArgumentException("no callee_duration view found");
        }

        timer.setBase(SystemClock.elapsedRealtime() - 1000 * callDuration);
        timer.start();
    }

    public void refreshCallList(Resources resources) {
        isConferenceRunning = LinphoneManager.getLc().isInConference();
        List<LinphoneCall> pausedCalls = LinphoneUtils.getCallsInState(LinphoneManager.getLc(),
                Arrays.asList(State.PausedByRemote));

        //MultiCalls
        if (LinphoneManager.getLc().getCallsNb() > 1) {
            callsList.setVisibility(View.VISIBLE);
        }

        //Active call
        if (LinphoneManager.getLc().getCurrentCall() != null) {
            displayNoCurrentCall(false);
            if (isVideoEnabled(LinphoneManager.getLc().getCurrentCall()) && !isConferenceRunning
                    && pausedCalls.size() == 0) {
                displayVideoCall(false);
            } else {
                displayAudioCall();
            }
        } else {
            showAudioView();
            displayNoCurrentCall(true);
            if (LinphoneManager.getLc().getCallsNb() == 1) {
                callsList.setVisibility(View.VISIBLE);
            }
        }

        //Conference
        if (isConferenceRunning) {
            displayConference(true);
        } else {
            displayConference(false);
        }

        if (callsList != null) {
            callsList.removeAllViews();
            int index = 0;

            if (LinphoneManager.getLc().getCallsNb() == 0) {
                goBackToDialer();
                return;
            }

            boolean isConfPaused = false;
            for (LinphoneCall call : LinphoneManager.getLc().getCalls()) {
                if (call.isInConference() && !isConferenceRunning) {
                    isConfPaused = true;
                    index++;
                } else {
                    if (call != LinphoneManager.getLc().getCurrentCall() && !call.isInConference()) {
                        displayPausedCalls(resources, call, index);
                        index++;
                    } else {
                        displayCurrentCall(call);
                    }
                }
            }

            if (!isConferenceRunning) {
                if (isConfPaused) {
                    callsList.setVisibility(View.VISIBLE);
                    displayPausedCalls(resources, null, index);
                }

            }

        }

        //Paused by remote
        if (pausedCalls.size() == 1) {
            displayCallPaused(true);
        } else {
            displayCallPaused(false);
        }
    }

    //Conference
    private void exitConference(final LinphoneCall call) {
        LinphoneCore lc = LinphoneManager.getLc();

        if (call.isInConference()) {
            lc.removeFromConference(call);
            if (lc.getConferenceSize() <= 1) {
                lc.leaveConference();
            }
        }
        refreshIncallUi();
    }

    private void enterConference() {
        LinphoneManager.getLc().addAllToConference();
    }

    public void pauseOrResumeConference() {
        LinphoneCore lc = LinphoneManager.getLc();
        conferenceStatus = (ImageView) findViewById(R.id.conference_pause);
        if (conferenceStatus != null) {
            if (lc.isInConference()) {
                conferenceStatus.setImageResource(R.drawable.pause_big_over_selected);
                lc.leaveConference();
            } else {
                conferenceStatus.setImageResource(R.drawable.pause_big_default);
                lc.enterConference();
            }
        }
        refreshCallList(getResources());
    }

    private void displayConferenceParticipant(int index, final LinphoneCall call) {
        LinearLayout confView = (LinearLayout) inflater.inflate(R.layout.conf_call_control_row, container, false);
        conferenceList.setId(index + 1);
        TextView contact = (TextView) confView.findViewById(R.id.contactNameOrNumber);

        LinphoneContact lContact = ContactsManager.getInstance().findContactFromAddress(call.getRemoteAddress());
        if (lContact == null) {
            contact.setText(call.getRemoteAddress().getUserName());
        } else {
            contact.setText(lContact.getFullName());
        }

        registerCallDurationTimer(confView, call);

        ImageView quitConference = (ImageView) confView.findViewById(R.id.quitConference);
        quitConference.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                exitConference(call);
            }
        });
        conferenceList.addView(confView);

    }

    private void displayConferenceHeader() {
        conferenceList.setVisibility(View.VISIBLE);
        RelativeLayout headerConference = (RelativeLayout) inflater.inflate(R.layout.conference_header, container,
                false);
        conferenceStatus = (ImageView) headerConference.findViewById(R.id.conference_pause);
        conferenceStatus.setOnClickListener(this);
        conferenceList.addView(headerConference);

    }

    private void displayConference(boolean isInConf) {
        if (isInConf) {
            mControlsLayout.setVisibility(View.VISIBLE);
            mActiveCallHeader.setVisibility(View.GONE);
            mNoCurrentCall.setVisibility(View.GONE);
            conferenceList.removeAllViews();

            //Conference Header
            displayConferenceHeader();

            //Conference participant
            int index = 1;
            for (LinphoneCall call : LinphoneManager.getLc().getCalls()) {
                if (call.isInConference()) {
                    displayConferenceParticipant(index, call);
                    index++;
                }
            }
            conferenceList.setVisibility(View.VISIBLE);
        } else {
            conferenceList.setVisibility(View.GONE);
        }
    }

    private void displayMissedChats() {
        int count = 0;
        LinphoneChatRoom[] chats = LinphoneManager.getLc().getChatRooms();
        for (LinphoneChatRoom chatroom : chats) {
            count += chatroom.getUnreadMessagesCount();
        }

        if (count > 0) {
            missedChats.setText(count + "");
            missedChats.setVisibility(View.VISIBLE);
        } else {
            missedChats.clearAnimation();
            missedChats.setVisibility(View.GONE);
        }
    }

    @SuppressWarnings("deprecation")
    private void formatText(TextView tv, String name, String value) {
        tv.setText(Html.fromHtml("<b>" + name + " </b>" + value));
    }

    private String getEncoderText(String mime) {
        String ret = mEncoderTexts.get(mime);
        if (ret == null) {
            org.linphone.mediastream.Factory msfactory = LinphoneManager.getLc().getMSFactory();
            ret = msfactory.getEncoderText(mime);
            mEncoderTexts.put(mime, ret);
        }
        return ret;
    }

    private String getDecoderText(String mime) {
        String ret = mDecoderTexts.get(mime);
        if (ret == null) {
            org.linphone.mediastream.Factory msfactory = LinphoneManager.getLc().getMSFactory();
            ret = msfactory.getDecoderText(mime);
            mDecoderTexts.put(mime, ret);
        }
        return ret;
    }

    private void displayMediaStats(LinphoneCallParams params, LinphoneCallStats stats, PayloadType media,
            View layout, TextView title, TextView codec, TextView dl, TextView ul, TextView ice, TextView ip,
            TextView senderLossRate, TextView receiverLossRate, TextView enc, TextView dec,
            TextView videoResolutionSent, TextView videoResolutionReceived, boolean isVideo,
            TextView jitterBuffer) {
        if (stats != null) {
            String mime = null;

            layout.setVisibility(View.VISIBLE);
            title.setVisibility(TextView.VISIBLE);
            if (media != null) {
                mime = media.getMime();
                formatText(codec, getString(R.string.call_stats_codec),
                        mime + " / " + (media.getRate() / 1000) + "kHz");
            }
            if (mime != null) {
                formatText(enc, getString(R.string.call_stats_encoder_name), getEncoderText(mime));
                formatText(dec, getString(R.string.call_stats_decoder_name), getDecoderText(mime));
            }
            formatText(dl, getString(R.string.call_stats_download),
                    String.valueOf((int) stats.getDownloadBandwidth()) + " kbits/s");
            formatText(ul, getString(R.string.call_stats_upload),
                    String.valueOf((int) stats.getUploadBandwidth()) + " kbits/s");
            formatText(ice, getString(R.string.call_stats_ice), stats.getIceState().toString());
            formatText(ip, getString(R.string.call_stats_ip),
                    (stats.getIpFamilyOfRemote() == LinphoneAddressFamily.INET_6.getInt()) ? "IpV6"
                            : (stats.getIpFamilyOfRemote() == LinphoneAddressFamily.INET.getInt()) ? "IpV4"
                                    : "Unknown");
            formatText(senderLossRate, getString(R.string.call_stats_sender_loss_rate),
                    new DecimalFormat("##.##").format(stats.getSenderLossRate()) + "%");
            formatText(receiverLossRate, getString(R.string.call_stats_receiver_loss_rate),
                    new DecimalFormat("##.##").format(stats.getReceiverLossRate()) + "%");
            if (isVideo) {
                formatText(videoResolutionSent, getString(R.string.call_stats_video_resolution_sent),
                        "\u2191 " + params.getSentVideoSize().toDisplayableString());
                formatText(videoResolutionReceived, getString(R.string.call_stats_video_resolution_received),
                        "\u2193 " + params.getReceivedVideoSize().toDisplayableString());
            } else {
                formatText(jitterBuffer, getString(R.string.call_stats_jitter_buffer),
                        new DecimalFormat("##.##").format(stats.getJitterBufferSize()) + " ms");
            }
        } else {
            layout.setVisibility(View.GONE);
            title.setVisibility(TextView.GONE);
        }
    }

    public void initCallStatsRefresher(final LinphoneCall call, final View view) {
        if (mTimer != null && mTask != null) {
            return;
        }

        final TextView titleAudio = (TextView) view.findViewById(R.id.call_stats_audio);
        final TextView titleVideo = (TextView) view.findViewById(R.id.call_stats_video);
        final TextView codecAudio = (TextView) view.findViewById(R.id.codec_audio);
        final TextView codecVideo = (TextView) view.findViewById(R.id.codec_video);
        final TextView encoderAudio = (TextView) view.findViewById(R.id.encoder_audio);
        final TextView decoderAudio = (TextView) view.findViewById(R.id.decoder_audio);
        final TextView encoderVideo = (TextView) view.findViewById(R.id.encoder_video);
        final TextView decoderVideo = (TextView) view.findViewById(R.id.decoder_video);
        final TextView dlAudio = (TextView) view.findViewById(R.id.downloadBandwith_audio);
        final TextView ulAudio = (TextView) view.findViewById(R.id.uploadBandwith_audio);
        final TextView dlVideo = (TextView) view.findViewById(R.id.downloadBandwith_video);
        final TextView ulVideo = (TextView) view.findViewById(R.id.uploadBandwith_video);
        final TextView iceAudio = (TextView) view.findViewById(R.id.ice_audio);
        final TextView iceVideo = (TextView) view.findViewById(R.id.ice_video);
        final TextView videoResolutionSent = (TextView) view.findViewById(R.id.video_resolution_sent);
        final TextView videoResolutionReceived = (TextView) view.findViewById(R.id.video_resolution_received);
        final TextView senderLossRateAudio = (TextView) view.findViewById(R.id.senderLossRateAudio);
        final TextView receiverLossRateAudio = (TextView) view.findViewById(R.id.receiverLossRateAudio);
        final TextView senderLossRateVideo = (TextView) view.findViewById(R.id.senderLossRateVideo);
        final TextView receiverLossRateVideo = (TextView) view.findViewById(R.id.receiverLossRateVideo);
        final TextView ipAudio = (TextView) view.findViewById(R.id.ip_audio);
        final TextView ipVideo = (TextView) view.findViewById(R.id.ip_video);
        final TextView jitterBufferAudio = (TextView) view.findViewById(R.id.jitterBufferAudio);
        final View videoLayout = view.findViewById(R.id.callStatsVideo);
        final View audioLayout = view.findViewById(R.id.callStatsAudio);

        mTimer = new Timer();
        mTask = new TimerTask() {
            @Override
            public void run() {
                if (call == null) {
                    mTimer.cancel();
                    return;
                }

                if (titleAudio == null || codecAudio == null || dlVideo == null || iceAudio == null
                        || videoResolutionSent == null || videoLayout == null || titleVideo == null
                        || ipVideo == null || ipAudio == null || codecVideo == null || dlAudio == null
                        || ulAudio == null || ulVideo == null || iceVideo == null
                        || videoResolutionReceived == null) {
                    mTimer.cancel();
                    return;
                }

                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        if (LinphoneManager.getLcIfManagerNotDestroyedOrNull() == null)
                            return;
                        synchronized (LinphoneManager.getLc()) {
                            if (LinphoneActivity.isInstanciated()) {
                                LinphoneCallParams params = call.getCurrentParams();
                                if (params != null) {
                                    LinphoneCallStats audioStats = call.getAudioStats();
                                    LinphoneCallStats videoStats = null;

                                    if (params.getVideoEnabled())
                                        videoStats = call.getVideoStats();

                                    PayloadType payloadAudio = params.getUsedAudioCodec();
                                    PayloadType payloadVideo = params.getUsedVideoCodec();

                                    displayMediaStats(params, audioStats, payloadAudio, audioLayout, titleAudio,
                                            codecAudio, dlAudio, ulAudio, iceAudio, ipAudio, senderLossRateAudio,
                                            receiverLossRateAudio, encoderAudio, decoderAudio, null, null, false,
                                            jitterBufferAudio);

                                    displayMediaStats(params, videoStats, payloadVideo, videoLayout, titleVideo,
                                            codecVideo, dlVideo, ulVideo, iceVideo, ipVideo, senderLossRateVideo,
                                            receiverLossRateVideo, encoderVideo, decoderVideo, videoResolutionSent,
                                            videoResolutionReceived, true, null);
                                }
                            }
                        }
                    }
                });
            }
        };
        mTimer.scheduleAtFixedRate(mTask, 0, 1000);
    }
}