co.taqat.call.LinphoneActivity.java Source code

Java tutorial

Introduction

Here is the source code for co.taqat.call.LinphoneActivity.java

Source

package co.taqat.call;

/*
 LinphoneActivity.java
 Copyright (C) 2012  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 java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import co.taqat.call.LinphoneManager.AddressType;
import co.taqat.call.assistant.AssistantActivity;
import co.taqat.call.assistant.RemoteProvisioningLoginActivity;
import co.taqat.call.compatibility.Compatibility;
import org.linphone.core.CallDirection;
import org.linphone.core.LinphoneAddress;
import org.linphone.core.LinphoneAuthInfo;
import org.linphone.core.LinphoneCall;
import org.linphone.core.LinphoneCall.State;
import org.linphone.core.LinphoneCallLog;
import org.linphone.core.LinphoneCallLog.CallStatus;
import org.linphone.core.LinphoneChatMessage;
import org.linphone.core.LinphoneChatRoom;
import org.linphone.core.LinphoneCore;
import org.linphone.core.LinphoneCore.RegistrationState;
import org.linphone.core.LinphoneCoreException;
import org.linphone.core.LinphoneCoreFactory;
import org.linphone.core.LinphoneCoreListenerBase;
import org.linphone.core.LinphoneProxyConfig;
import org.linphone.core.Reason;
import org.linphone.mediastream.Log;
import co.taqat.call.purchase.InAppPurchaseActivity;
import co.taqat.call.ui.AddressText;
import co.taqat.call.xmlrpc.XmlRpcHelper;
import co.taqat.call.xmlrpc.XmlRpcListenerBase;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.DrawerLayout;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.OrientationEventListener;
import android.view.Surface;
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.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

/**
 * @author Sylvain Berfini
 */
public class LinphoneActivity extends LinphoneGenericActivity
        implements OnClickListener, ContactPicked, ActivityCompat.OnRequestPermissionsResultCallback {
    public static final String PREF_FIRST_LAUNCH = "pref_first_launch";
    private static final int SETTINGS_ACTIVITY = 123;
    private static final int CALL_ACTIVITY = 19;
    private static final int PERMISSIONS_REQUEST_OVERLAY = 206;
    private static final int PERMISSIONS_REQUEST_SYNC = 207;
    private static final int PERMISSIONS_REQUEST_CONTACTS = 208;
    private static final int PERMISSIONS_RECORD_AUDIO_ECHO_CANCELLER = 209;
    private static final int PERMISSIONS_READ_EXTERNAL_STORAGE_DEVICE_RINGTONE = 210;
    private static final int PERMISSIONS_RECORD_AUDIO_ECHO_TESTER = 211;

    private static LinphoneActivity instance;

    private StatusFragment statusFragment;
    private TextView missedCalls, missedChats;
    private RelativeLayout contacts, history, dialer, chat;
    private View contacts_selected, history_selected, dialer_selected, chat_selected;
    private RelativeLayout mTopBar;
    private ImageView cancel;
    private FragmentsAvailable pendingFragmentTransaction, currentFragment;
    private Fragment fragment;
    private List<FragmentsAvailable> fragmentsHistory;
    private Fragment.SavedState dialerSavedState;
    private boolean newProxyConfig;
    private boolean emptyFragment = false;
    private boolean isTrialAccount = false;
    private OrientationEventListener mOrientationHelper;
    private LinphoneCoreListenerBase mListener;
    private LinearLayout mTabBar;

    private DrawerLayout sideMenu;
    private RelativeLayout sideMenuContent, quitLayout, defaultAccount;
    private ListView accountsList, sideMenuItemList;
    private ImageView menu;
    private boolean fetchedContactsOnce = false;
    private boolean doNotGoToCallActivity = false;
    private List<String> sideMenuItems;
    private boolean callTransfer = false;

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

    public static final LinphoneActivity instance() {
        if (instance != null)
            return instance;
        throw new RuntimeException("LinphoneActivity not instantiated yet");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //This must be done before calling super.onCreate().
        super.onCreate(savedInstanceState);

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

        boolean useFirstLoginActivity = getResources().getBoolean(R.bool.display_account_assistant_at_first_start);
        if (LinphonePreferences.instance().isProvisioningLoginViewEnabled()) {
            Intent wizard = new Intent();
            wizard.setClass(this, RemoteProvisioningLoginActivity.class);
            wizard.putExtra("Domain", LinphoneManager.getInstance().wizardLoginViewDomain);
            startActivity(wizard);
            finish();
            return;
        } else if (savedInstanceState == null
                && (useFirstLoginActivity && LinphonePreferences.instance().isFirstLaunch())) {
            if (LinphonePreferences.instance().getAccountCount() > 0) {
                LinphonePreferences.instance().firstLaunchSuccessful();
            } else {
                startActivity(new Intent().setClass(this, AssistantActivity.class));
                finish();
                return;
            }
        }

        if (getIntent() != null && getIntent().getExtras() != null) {
            newProxyConfig = getIntent().getExtras().getBoolean("isNewProxyConfig");
        }

        if (getResources().getBoolean(R.bool.use_linphone_tag)) {
            if (getPackageManager().checkPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                    getPackageName()) != PackageManager.PERMISSION_GRANTED) {
                checkSyncPermission();
            } else {
                ContactsManager.getInstance().initializeSyncAccount(getApplicationContext(), getContentResolver());
            }
        } else {
            ContactsManager.getInstance().initializeContactManager(getApplicationContext(), getContentResolver());
        }

        setContentView(R.layout.main);
        instance = this;
        fragmentsHistory = new ArrayList<FragmentsAvailable>();
        pendingFragmentTransaction = FragmentsAvailable.UNKNOW;

        initButtons();
        initSideMenu();

        currentFragment = FragmentsAvailable.EMPTY;
        if (savedInstanceState == null) {
            changeCurrentFragment(FragmentsAvailable.DIALER, getIntent().getExtras());
        } else {
            currentFragment = (FragmentsAvailable) savedInstanceState.getSerializable("currentFragment");
        }

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

            @Override
            public void registrationState(LinphoneCore lc, LinphoneProxyConfig proxy,
                    LinphoneCore.RegistrationState state, String smessage) {
                if (state.equals(RegistrationState.RegistrationCleared)) {
                    if (lc != null) {
                        LinphoneAuthInfo authInfo = lc.findAuthInfo(proxy.getIdentity(), proxy.getRealm(),
                                proxy.getDomain());
                        if (authInfo != null)
                            lc.removeAuthInfo(authInfo);
                    }
                }

                refreshAccounts();

                if (getResources().getBoolean(R.bool.use_phone_number_validation)) {
                    if (state.equals(RegistrationState.RegistrationOk)) {
                        LinphoneManager.getInstance().isAccountWithAlias();
                    }
                }

                if (state.equals(RegistrationState.RegistrationFailed) && newProxyConfig) {
                    newProxyConfig = false;
                    if (proxy.getError() == Reason.BadCredentials) {
                        //displayCustomToast(getString(R.string.error_bad_credentials), Toast.LENGTH_LONG);
                    }
                    if (proxy.getError() == Reason.Unauthorized) {
                        displayCustomToast(getString(R.string.error_unauthorized), Toast.LENGTH_LONG);
                    }
                    if (proxy.getError() == Reason.IOError) {
                        displayCustomToast(getString(R.string.error_io_error), Toast.LENGTH_LONG);
                    }
                }
            }

            @Override
            public void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State state, String message) {
                if (state == State.IncomingReceived) {
                    startActivity(new Intent(LinphoneActivity.instance(), CallIncomingActivity.class));
                } else if (state == State.OutgoingInit || state == State.OutgoingProgress) {
                    startActivity(new Intent(LinphoneActivity.instance(), CallOutgoingActivity.class));
                } else if (state == State.CallEnd || state == State.Error || state == State.CallReleased) {
                    resetClassicMenuLayoutAndGoBackToCallIfStillRunning();
                }

                int missedCalls = LinphoneManager.getLc().getMissedCallsCount();
                displayMissedCalls(missedCalls);
            }
        };

        int missedCalls = LinphoneManager.getLc().getMissedCallsCount();
        displayMissedCalls(missedCalls);

        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        switch (rotation) {
        case Surface.ROTATION_0:
            rotation = 0;
            break;
        case Surface.ROTATION_90:
            rotation = 90;
            break;
        case Surface.ROTATION_180:
            rotation = 180;
            break;
        case Surface.ROTATION_270:
            rotation = 270;
            break;
        }

        LinphoneManager.getLc().setDeviceRotation(rotation);
        mAlwaysChangingPhoneAngle = rotation;
    }

    private void initButtons() {
        mTabBar = (LinearLayout) findViewById(R.id.footer);
        mTopBar = (RelativeLayout) findViewById(R.id.top_bar);

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

        history = (RelativeLayout) findViewById(R.id.history);
        history.setOnClickListener(this);
        contacts = (RelativeLayout) findViewById(R.id.contacts);
        contacts.setOnClickListener(this);
        dialer = (RelativeLayout) findViewById(R.id.dialer);
        dialer.setOnClickListener(this);
        chat = (RelativeLayout) findViewById(R.id.chat);
        chat.setOnClickListener(this);

        history_selected = findViewById(R.id.history_select);
        contacts_selected = findViewById(R.id.contacts_select);
        dialer_selected = findViewById(R.id.dialer_select);
        chat_selected = findViewById(R.id.chat_select);

        missedCalls = (TextView) findViewById(R.id.missed_calls);
        missedChats = (TextView) findViewById(R.id.missed_chats);
    }

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

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

        findViewById(R.id.status).setVisibility(View.GONE);
    }

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

        if (statusFragment != null && !statusFragment.isVisible()) {
            statusFragment.getView().setVisibility(View.VISIBLE);
        }
        findViewById(R.id.status).setVisibility(View.VISIBLE);
    }

    public void isNewProxyConfig() {
        newProxyConfig = true;
    }

    private void changeCurrentFragment(FragmentsAvailable newFragmentType, Bundle extras) {
        changeCurrentFragment(newFragmentType, extras, false);
    }

    private void changeCurrentFragment(FragmentsAvailable newFragmentType, Bundle extras,
            boolean withoutAnimation) {
        if (newFragmentType == currentFragment && newFragmentType != FragmentsAvailable.CHAT) {
            return;
        }

        if (currentFragment == FragmentsAvailable.DIALER) {
            try {
                DialerFragment dialerFragment = DialerFragment.instance();
                dialerSavedState = getFragmentManager().saveFragmentInstanceState(dialerFragment);
            } catch (Exception e) {
            }
        }

        fragment = null;

        switch (newFragmentType) {
        case HISTORY_LIST:
            fragment = new HistoryListFragment();
            break;
        case HISTORY_DETAIL:
            fragment = new HistoryDetailFragment();
            break;
        case CONTACTS_LIST:
            checkAndRequestReadContactsPermission();
            fragment = new ContactsListFragment();
            break;
        case CONTACT_DETAIL:
            fragment = new ContactDetailsFragment();
            break;
        case CONTACT_EDITOR:
            fragment = new ContactEditorFragment();
            break;
        case DIALER:
            fragment = new DialerFragment();
            if (extras == null) {
                fragment.setInitialSavedState(dialerSavedState);
            }
            break;
        case SETTINGS:
            fragment = new SettingsFragment();
            break;
        case ACCOUNT_SETTINGS:
            fragment = new AccountPreferencesFragment();
            break;
        case ABOUT:
            fragment = new AboutFragment();
            break;
        case EMPTY:
            fragment = new EmptyFragment();
            break;
        case CHAT_LIST:
            fragment = new ChatListFragment();
            break;
        case CHAT:
            fragment = new ChatFragment();
            break;
        default:
            break;
        }

        if (fragment != null) {
            fragment.setArguments(extras);
            if (isTablet()) {
                changeFragmentForTablets(fragment, newFragmentType, withoutAnimation);
                switch (newFragmentType) {
                case HISTORY_LIST:
                    ((HistoryListFragment) fragment).displayFirstLog();
                    break;
                case CONTACTS_LIST:
                    ((ContactsListFragment) fragment).displayFirstContact();
                    break;
                case CHAT_LIST:
                    ((ChatListFragment) fragment).displayFirstChat();
                    break;
                }
            } else {
                changeFragment(fragment, newFragmentType, withoutAnimation);
            }
        }
    }

    private void changeFragment(Fragment newFragment, FragmentsAvailable newFragmentType,
            boolean withoutAnimation) {
        FragmentManager fm = getFragmentManager();
        FragmentTransaction transaction = fm.beginTransaction();
        /*
              if (!withoutAnimation && currentFragment.shouldAnimate()) {
                 if (newFragmentType.isRightOf(currentFragment)) {
        transaction.setCustomAnimations(R.anim.slide_in_right_to_left,
              R.anim.slide_out_right_to_left,
              R.anim.slide_in_left_to_right,
              R.anim.slide_out_left_to_right);
                 } else {
        transaction.setCustomAnimations(R.anim.slide_in_left_to_right,
              R.anim.slide_out_left_to_right,
              R.anim.slide_in_right_to_left,
              R.anim.slide_out_right_to_left);
                 }
              }*/

        if (newFragmentType != FragmentsAvailable.DIALER && newFragmentType != FragmentsAvailable.CONTACTS_LIST
                && newFragmentType != FragmentsAvailable.CHAT_LIST
                && newFragmentType != FragmentsAvailable.HISTORY_LIST) {
            transaction.addToBackStack(newFragmentType.toString());
        } else {
            while (fm.getBackStackEntryCount() > 0) {
                fm.popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
            }
        }

        transaction.replace(R.id.fragmentContainer, newFragment, newFragmentType.toString());
        transaction.commitAllowingStateLoss();
        fm.executePendingTransactions();

        currentFragment = newFragmentType;
    }

    private void changeFragmentForTablets(Fragment newFragment, FragmentsAvailable newFragmentType,
            boolean withoutAnimation) {
        if (getResources().getBoolean(R.bool.show_statusbar_only_on_dialer)) {
            if (newFragmentType == FragmentsAvailable.DIALER) {
                showStatusBar();
            } else {
                hideStatusBar();
            }
        }
        emptyFragment = false;
        LinearLayout ll = (LinearLayout) findViewById(R.id.fragmentContainer2);

        FragmentTransaction transaction = getFragmentManager().beginTransaction();

        if (newFragmentType == FragmentsAvailable.EMPTY) {
            ll.setVisibility(View.VISIBLE);
            emptyFragment = true;
            transaction.replace(R.id.fragmentContainer2, newFragment);
            transaction.commitAllowingStateLoss();
            getFragmentManager().executePendingTransactions();
        } else {
            if (newFragmentType.shouldAddItselfToTheRightOf(currentFragment)) {
                ll.setVisibility(View.VISIBLE);

                if (newFragmentType == FragmentsAvailable.CONTACT_EDITOR) {
                    transaction.addToBackStack(newFragmentType.toString());
                }
                transaction.replace(R.id.fragmentContainer2, newFragment);
            } else {
                if (newFragmentType == FragmentsAvailable.EMPTY) {
                    ll.setVisibility(View.VISIBLE);
                    transaction.replace(R.id.fragmentContainer2, new EmptyFragment());
                    emptyFragment = true;
                }

                if (newFragmentType == FragmentsAvailable.DIALER || newFragmentType == FragmentsAvailable.ABOUT
                        || newFragmentType == FragmentsAvailable.SETTINGS
                        || newFragmentType == FragmentsAvailable.ACCOUNT_SETTINGS) {
                    ll.setVisibility(View.GONE);
                } else {
                    ll.setVisibility(View.VISIBLE);
                    transaction.replace(R.id.fragmentContainer2, new EmptyFragment());
                }

                /*if (!withoutAnimation && !isAnimationDisabled && currentFragment.shouldAnimate()) {
                   if (newFragmentType.isRightOf(currentFragment)) {
                      transaction.setCustomAnimations(R.anim.slide_in_right_to_left, R.anim.slide_out_right_to_left, R.anim.slide_in_left_to_right, R.anim.slide_out_left_to_right);
                   } else {
                      transaction.setCustomAnimations(R.anim.slide_in_left_to_right, R.anim.slide_out_left_to_right, R.anim.slide_in_right_to_left, R.anim.slide_out_right_to_left);
                   }
                }*/
                transaction.replace(R.id.fragmentContainer, newFragment);
            }
            transaction.commitAllowingStateLoss();
            getFragmentManager().executePendingTransactions();

            currentFragment = newFragmentType;
            if (newFragmentType == FragmentsAvailable.DIALER || newFragmentType == FragmentsAvailable.SETTINGS
                    || newFragmentType == FragmentsAvailable.CONTACTS_LIST
                    || newFragmentType == FragmentsAvailable.CHAT_LIST
                    || newFragmentType == FragmentsAvailable.HISTORY_LIST) {
                try {
                    getFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
                } catch (java.lang.IllegalStateException e) {

                }
            }
            fragmentsHistory.add(currentFragment);
        }
    }

    public void displayHistoryDetail(String sipUri, LinphoneCallLog log) {
        LinphoneAddress lAddress;
        try {
            lAddress = LinphoneCoreFactory.instance().createLinphoneAddress(sipUri);
        } catch (LinphoneCoreException e) {
            Log.e("Cannot display history details", e);
            //TODO display error message
            return;
        }
        LinphoneContact c = ContactsManager.getInstance().findContactFromAddress(lAddress);

        String displayName = c != null ? c.getFullName() : LinphoneUtils.getAddressDisplayName(sipUri);
        String pictureUri = c != null && c.getPhotoUri() != null ? c.getPhotoUri().toString() : null;

        String status;
        if (log.getDirection() == CallDirection.Outgoing) {
            status = getString(R.string.outgoing);
        } else {
            if (log.getStatus() == CallStatus.Missed) {
                status = getString(R.string.missed);
            } else {
                status = getString(R.string.incoming);
            }
        }

        String callTime = secondsToDisplayableString(log.getCallDuration());
        String callDate = String.valueOf(log.getTimestamp());

        Fragment fragment2 = getFragmentManager().findFragmentById(R.id.fragmentContainer2);
        if (fragment2 != null && fragment2.isVisible() && currentFragment == FragmentsAvailable.HISTORY_DETAIL) {
            HistoryDetailFragment historyDetailFragment = (HistoryDetailFragment) fragment2;
            historyDetailFragment.changeDisplayedHistory(lAddress.asStringUriOnly(), displayName, pictureUri,
                    status, callTime, callDate);
        } else {
            Bundle extras = new Bundle();
            extras.putString("SipUri", lAddress.asString());
            if (displayName != null) {
                extras.putString("DisplayName", displayName);
                extras.putString("PictureUri", pictureUri);
            }
            extras.putString("CallStatus", status);
            extras.putString("CallTime", callTime);
            extras.putString("CallDate", callDate);

            changeCurrentFragment(FragmentsAvailable.HISTORY_DETAIL, extras);
        }
    }

    public void displayEmptyFragment() {
        changeCurrentFragment(FragmentsAvailable.EMPTY, new Bundle());
    }

    @SuppressLint("SimpleDateFormat")
    private String secondsToDisplayableString(int secs) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
        Calendar cal = Calendar.getInstance();
        cal.set(0, 0, 0, 0, 0, secs);
        return dateFormat.format(cal.getTime());
    }

    public void displayContact(LinphoneContact contact, boolean chatOnly) {
        Fragment fragment2 = getFragmentManager().findFragmentById(R.id.fragmentContainer2);
        if (fragment2 != null && fragment2.isVisible() && currentFragment == FragmentsAvailable.CONTACT_DETAIL) {
            ContactDetailsFragment contactFragment = (ContactDetailsFragment) fragment2;
            contactFragment.changeDisplayedContact(contact);
        } else {
            Bundle extras = new Bundle();
            extras.putSerializable("Contact", contact);
            extras.putBoolean("ChatAddressOnly", chatOnly);
            changeCurrentFragment(FragmentsAvailable.CONTACT_DETAIL, extras);
        }
    }

    public void displayContacts(boolean chatOnly) {
        Bundle extras = new Bundle();
        extras.putBoolean("ChatAddressOnly", chatOnly);
        changeCurrentFragment(FragmentsAvailable.CONTACTS_LIST, extras);
    }

    public void displayContactsForEdition(String sipAddress) {
        Bundle extras = new Bundle();
        extras.putBoolean("EditOnClick", true);
        extras.putString("SipAddress", sipAddress);
        changeCurrentFragment(FragmentsAvailable.CONTACTS_LIST, extras);
    }

    public void displayAbout() {
        changeCurrentFragment(FragmentsAvailable.ABOUT, null);
    }

    public void displayAssistant() {
        startActivity(new Intent(LinphoneActivity.this, AssistantActivity.class));
    }

    public void displayInapp() {
        startActivity(new Intent(LinphoneActivity.this, InAppPurchaseActivity.class));
    }

    public int getUnreadMessageCount() {
        int count = 0;
        LinphoneChatRoom[] chats = LinphoneManager.getLc().getChatRooms();
        for (LinphoneChatRoom chatroom : chats) {
            count += chatroom.getUnreadMessagesCount();
        }
        return count;
    }

    public void displayChat(String sipUri) {
        if (getResources().getBoolean(R.bool.disable_chat)) {
            return;
        }

        String pictureUri = null;
        String thumbnailUri = null;
        String displayName = null;

        LinphoneAddress lAddress = null;
        if (sipUri != null) {
            try {
                lAddress = LinphoneManager.getLc().interpretUrl(sipUri);
            } catch (LinphoneCoreException e) {
                //TODO display error message
                Log.e("Cannot display chat", e);
                return;
            }
            LinphoneContact contact = ContactsManager.getInstance().findContactFromAddress(lAddress);
            displayName = contact != null ? contact.getFullName() : null;

            if (contact != null && contact.getPhotoUri() != null) {
                pictureUri = contact.getPhotoUri().toString();
                thumbnailUri = contact.getThumbnailUri().toString();
            }
        }

        if (currentFragment == FragmentsAvailable.CHAT_LIST || currentFragment == FragmentsAvailable.CHAT) {
            Fragment fragment2 = getFragmentManager().findFragmentById(R.id.fragmentContainer2);
            if (fragment2 != null && fragment2.isVisible() && currentFragment == FragmentsAvailable.CHAT
                    && !emptyFragment) {
                ChatFragment chatFragment = (ChatFragment) fragment2;
                chatFragment.changeDisplayedChat(sipUri, displayName, pictureUri);
            } else {
                Bundle extras = new Bundle();
                extras.putString("SipUri", sipUri);
                if (sipUri != null && lAddress.getDisplayName() != null) {
                    extras.putString("DisplayName", displayName);
                    extras.putString("PictureUri", pictureUri);
                    extras.putString("ThumbnailUri", thumbnailUri);
                }
                changeCurrentFragment(FragmentsAvailable.CHAT, extras);
            }
        } else {
            if (isTablet()) {
                changeCurrentFragment(FragmentsAvailable.CHAT_LIST, null);
                displayChat(sipUri);
            } else {
                Bundle extras = new Bundle();
                extras.putString("SipUri", sipUri);
                if (sipUri != null && lAddress.getDisplayName() != null) {
                    extras.putString("DisplayName", displayName);
                    extras.putString("PictureUri", pictureUri);
                    extras.putString("ThumbnailUri", thumbnailUri);
                }
                changeCurrentFragment(FragmentsAvailable.CHAT, extras);
            }
        }

        LinphoneService.instance().resetMessageNotifCount();
        LinphoneService.instance().removeMessageNotification();
        displayMissedChats(getUnreadMessageCount());
    }

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

        if (id == R.id.history) {
            changeCurrentFragment(FragmentsAvailable.HISTORY_LIST, null);
            history_selected.setVisibility(View.VISIBLE);
            LinphoneManager.getLc().resetMissedCallsCount();
            displayMissedCalls(0);
        } else if (id == R.id.contacts) {
            changeCurrentFragment(FragmentsAvailable.CONTACTS_LIST, null);
            contacts_selected.setVisibility(View.VISIBLE);
        } else if (id == R.id.dialer) {
            changeCurrentFragment(FragmentsAvailable.DIALER, null);
            dialer_selected.setVisibility(View.VISIBLE);
        } else if (id == R.id.chat) {
            changeCurrentFragment(FragmentsAvailable.CHAT_LIST, null);
            chat_selected.setVisibility(View.VISIBLE);
        } else if (id == R.id.cancel) {
            hideTopBar();
            displayDialer();
        }
    }

    private void resetSelection() {
        history_selected.setVisibility(View.GONE);
        contacts_selected.setVisibility(View.GONE);
        dialer_selected.setVisibility(View.GONE);
        chat_selected.setVisibility(View.GONE);
    }

    public void hideTabBar(Boolean hide) {
        if (hide) {
            mTabBar.setVisibility(View.GONE);
        } else {
            mTabBar.setVisibility(View.VISIBLE);
        }
    }

    public void hideTopBar() {
        mTopBar.setVisibility(View.GONE);
    }

    @SuppressWarnings("incomplete-switch")
    public void selectMenu(FragmentsAvailable menuToSelect) {
        currentFragment = menuToSelect;
        resetSelection();

        switch (menuToSelect) {
        case HISTORY_LIST:
        case HISTORY_DETAIL:
            history_selected.setVisibility(View.VISIBLE);
            break;
        case CONTACTS_LIST:
        case CONTACT_DETAIL:
        case CONTACT_EDITOR:
            contacts_selected.setVisibility(View.VISIBLE);
            break;
        case DIALER:
            dialer_selected.setVisibility(View.VISIBLE);
            break;
        case SETTINGS:
        case ACCOUNT_SETTINGS:
            hideTabBar(true);
            mTopBar.setVisibility(View.VISIBLE);
            break;
        case ABOUT:
            hideTabBar(true);
            break;
        case CHAT_LIST:
        case CHAT:
            chat_selected.setVisibility(View.VISIBLE);
            break;
        }
    }

    public void updateDialerFragment(DialerFragment fragment) {
        // Hack to maintain soft input flags
        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN
                | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
    }

    public void goToDialerFragment() {
        changeCurrentFragment(FragmentsAvailable.DIALER, null);
        dialer_selected.setVisibility(View.VISIBLE);
    }

    public void onMessageSent(String to, String message) {
        Fragment fragment = getFragmentManager().findFragmentById(R.id.fragmentContainer);
        if (fragment.getClass() == ChatListFragment.class) {
            ((ChatListFragment) fragment).refresh();
        }
    }

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

    public void displaySettings() {
        changeCurrentFragment(FragmentsAvailable.SETTINGS, null);
    }

    public void displayDialer() {
        changeCurrentFragment(FragmentsAvailable.DIALER, null);
    }

    public void displayAccountSettings(int accountNumber) {
        Bundle bundle = new Bundle();
        bundle.putInt("Account", accountNumber);
        changeCurrentFragment(FragmentsAvailable.ACCOUNT_SETTINGS, bundle);
        //settings.setSelected(true);
    }

    public StatusFragment getStatusFragment() {
        return statusFragment;
    }

    public List<String> getChatList() {
        ArrayList<String> chatList = new ArrayList<String>();

        LinphoneChatRoom[] chats = LinphoneManager.getLc().getChatRooms();
        List<LinphoneChatRoom> rooms = new ArrayList<LinphoneChatRoom>();

        for (LinphoneChatRoom chatroom : chats) {
            if (chatroom.getHistorySize() > 0) {
                rooms.add(chatroom);
            }
        }

        if (rooms.size() > 1) {
            Collections.sort(rooms, new Comparator<LinphoneChatRoom>() {
                @Override
                public int compare(LinphoneChatRoom a, LinphoneChatRoom b) {
                    LinphoneChatMessage[] messagesA = a.getHistory(1);
                    LinphoneChatMessage[] messagesB = b.getHistory(1);
                    long atime = messagesA[0].getTime();
                    long btime = messagesB[0].getTime();

                    if (atime > btime)
                        return -1;
                    else if (btime > atime)
                        return 1;
                    else
                        return 0;
                }
            });
        }

        for (LinphoneChatRoom chatroom : rooms) {
            chatList.add(chatroom.getPeerAddress().asStringUriOnly());
        }

        return chatList;
    }

    public void removeFromChatList(String sipUri) {
        LinphoneChatRoom chatroom = LinphoneManager.getLc().getOrCreateChatRoom(sipUri);
        chatroom.deleteHistory();
    }

    public void updateMissedChatCount() {
        displayMissedChats(getUnreadMessageCount());
    }

    public void displayMissedCalls(final int missedCallsCount) {
        if (missedCallsCount > 0) {
            missedCalls.setText(missedCallsCount + "");
            missedCalls.setVisibility(View.VISIBLE);
        } else {
            LinphoneManager.getLc().resetMissedCallsCount();
            missedCalls.clearAnimation();
            missedCalls.setVisibility(View.GONE);
        }
    }

    private void displayMissedChats(final int missedChatCount) {
        if (missedChatCount > 0) {
            missedChats.setText(missedChatCount + "");
            missedChats.setVisibility(View.VISIBLE);
        } else {
            missedChats.clearAnimation();
            missedChats.setVisibility(View.GONE);
        }
    }

    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();
    }

    public Dialog displayDialog(String text) {
        Dialog 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(text);
        return dialog;
    }

    public Dialog displayWrongPasswordDialog(final String username, final String realm, final String domain) {
        final Dialog 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.input_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(getString(R.string.error_bad_credentials));

        Button retry = (Button) dialog.findViewById(R.id.retry);
        Button cancel = (Button) dialog.findViewById(R.id.cancel);

        retry.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                String newPassword = ((EditText) dialog.findViewById(R.id.password)).getText().toString();
                LinphoneAuthInfo authInfo = LinphoneCoreFactory.instance().createAuthInfo(username, null,
                        newPassword, null, realm, domain);
                LinphoneManager.getLc().addAuthInfo(authInfo);
                LinphoneManager.getLc().refreshRegisters();
                dialog.dismiss();
            }
        });

        cancel.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                dialog.dismiss();
            }
        });

        return dialog;
    }

    @Override
    public void setAddresGoToDialerAndCall(String number, String name, Uri photo) {
        //      Bundle extras = new Bundle();
        //      extras.putString("SipUri", number);
        //      extras.putString("DisplayName", name);
        //      extras.putString("Photo", photo == null ? null : photo.toString());
        //      changeCurrentFragment(FragmentsAvailable.DIALER, extras);

        AddressType address = new AddressText(this, null);
        address.setDisplayedName(name);
        address.setText(number);
        LinphoneManager.getInstance().newOutgoingCall(address);
    }

    public void startIncallActivity(LinphoneCall currentCall) {
        Intent intent = new Intent(this, CallActivity.class);
        startOrientationSensor();
        startActivityForResult(intent, CALL_ACTIVITY);
    }

    /**
     * Register a sensor to track phoneOrientation changes
     */
    private synchronized void startOrientationSensor() {
        if (mOrientationHelper == null) {
            mOrientationHelper = new LocalOrientationEventListener(this);
        }
        mOrientationHelper.enable();
    }

    private int mAlwaysChangingPhoneAngle = -1;

    private class LocalOrientationEventListener extends OrientationEventListener {
        public LocalOrientationEventListener(Context context) {
            super(context);
        }

        @Override
        public void onOrientationChanged(final int o) {
            if (o == OrientationEventListener.ORIENTATION_UNKNOWN) {
                return;
            }

            int degrees = 270;
            if (o < 45 || o > 315)
                degrees = 0;
            else if (o < 135)
                degrees = 90;
            else if (o < 225)
                degrees = 180;

            if (mAlwaysChangingPhoneAngle == degrees) {
                return;
            }
            mAlwaysChangingPhoneAngle = degrees;

            Log.d("Phone orientation changed to ", degrees);
            int rotation = (360 - degrees) % 360;
            LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
            if (lc != null) {
                lc.setDeviceRotation(rotation);
                LinphoneCall currentCall = lc.getCurrentCall();
                if (currentCall != null && currentCall.cameraEnabled()
                        && currentCall.getCurrentParamsCopy().getVideoEnabled()) {
                    lc.updateCall(currentCall, null);
                }
            }
        }
    }

    public Boolean isCallTransfer() {
        return callTransfer;
    }

    private void initInCallMenuLayout(final boolean callTransfer) {
        selectMenu(FragmentsAvailable.DIALER);
        DialerFragment dialerFragment = DialerFragment.instance();
        if (dialerFragment != null) {
            ((DialerFragment) dialerFragment).resetLayout(callTransfer);
        }
    }

    public void resetClassicMenuLayoutAndGoBackToCallIfStillRunning() {
        DialerFragment dialerFragment = DialerFragment.instance();
        if (dialerFragment != null) {
            ((DialerFragment) dialerFragment).resetLayout(true);
        }

        if (LinphoneManager.isInstanciated() && LinphoneManager.getLc().getCallsNb() > 0) {
            LinphoneCall call = LinphoneManager.getLc().getCalls()[0];
            if (call.getState() == LinphoneCall.State.IncomingReceived) {
                startActivity(new Intent(LinphoneActivity.this, CallIncomingActivity.class));
            } else {
                startIncallActivity(call);
            }
        }
    }

    public FragmentsAvailable getCurrentFragment() {
        return currentFragment;
    }

    public void addContact(String displayName, String sipUri) {
        Bundle extras = new Bundle();
        extras.putSerializable("NewSipAdress", sipUri);
        changeCurrentFragment(FragmentsAvailable.CONTACT_EDITOR, extras);
    }

    public void editContact(LinphoneContact contact) {
        Bundle extras = new Bundle();
        extras.putSerializable("Contact", contact);
        changeCurrentFragment(FragmentsAvailable.CONTACT_EDITOR, extras);
    }

    public void editContact(LinphoneContact contact, String sipAddress) {
        Bundle extras = new Bundle();
        extras.putSerializable("Contact", contact);
        extras.putSerializable("NewSipAdress", sipAddress);
        changeCurrentFragment(FragmentsAvailable.CONTACT_EDITOR, extras);
    }

    public void quit() {
        finish();
        stopService(new Intent(Intent.ACTION_MAIN).setClass(this, LinphoneService.class));
        android.os.Process.killProcess(android.os.Process.myPid());
    }

    @Override
    protected void onPostResume() {
        super.onPostResume();
        if (pendingFragmentTransaction != FragmentsAvailable.UNKNOW) {
            changeCurrentFragment(pendingFragmentTransaction, null, true);
            selectMenu(pendingFragmentTransaction);
            pendingFragmentTransaction = FragmentsAvailable.UNKNOW;
        }
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (resultCode == Activity.RESULT_FIRST_USER && requestCode == SETTINGS_ACTIVITY) {
            if (data.getExtras().getBoolean("Exit", false)) {
                quit();
            } else {
                pendingFragmentTransaction = (FragmentsAvailable) data.getExtras()
                        .getSerializable("FragmentToDisplay");
            }
        } else if (resultCode == Activity.RESULT_FIRST_USER && requestCode == CALL_ACTIVITY) {
            getIntent().putExtra("PreviousActivity", CALL_ACTIVITY);
            callTransfer = data == null ? false : data.getBooleanExtra("Transfer", false);
            boolean chat = data == null ? false : data.getBooleanExtra("chat", false);
            if (chat) {
                pendingFragmentTransaction = FragmentsAvailable.CHAT_LIST;
            }
            if (LinphoneManager.getLc().getCallsNb() > 0) {
                initInCallMenuLayout(callTransfer);
            } else {
                resetClassicMenuLayoutAndGoBackToCallIfStillRunning();
            }
        } else if (requestCode == PERMISSIONS_REQUEST_OVERLAY) {
            if (Compatibility.canDrawOverlays(this)) {
                LinphonePreferences.instance().enableOverlay(true);
            }
        } else {
            super.onActivityResult(requestCode, resultCode, data);
        }
    }

    @Override
    protected void onPause() {
        getIntent().putExtra("PreviousActivity", 0);

        LinphoneCore lc = LinphoneManager.getLcIfManagerNotDestroyedOrNull();
        if (lc != null) {
            lc.removeListener(mListener);
        }
        callTransfer = false;

        super.onPause();
    }

    public boolean checkAndRequestOverlayPermission() {
        Log.i("[Permission] Draw overlays permission is "
                + (Compatibility.canDrawOverlays(this) ? "granted" : "denied"));
        if (!Compatibility.canDrawOverlays(this)) {
            Log.i("[Permission] Asking for overlay");
            Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                    Uri.parse("package:" + getPackageName()));
            startActivityForResult(intent, PERMISSIONS_REQUEST_OVERLAY);
            return false;
        }
        return true;
    }

    public void checkAndRequestReadPhoneStatePermission() {
        checkAndRequestPermission(Manifest.permission.READ_PHONE_STATE, 0);
    }

    public void checkAndRequestReadExternalStoragePermission() {
        checkAndRequestPermission(Manifest.permission.READ_EXTERNAL_STORAGE, 0);
    }

    public void checkAndRequestExternalStoragePermission() {
        checkAndRequestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, 0);
    }

    public void checkAndRequestCameraPermission() {
        checkAndRequestPermission(Manifest.permission.CAMERA, 0);
    }

    public void checkAndRequestReadContactsPermission() {
        checkAndRequestPermission(Manifest.permission.READ_CONTACTS, PERMISSIONS_REQUEST_CONTACTS);
    }

    public void checkAndRequestInappPermission() {
        checkAndRequestPermission(Manifest.permission.GET_ACCOUNTS, PERMISSIONS_REQUEST_CONTACTS);
    }

    public void checkAndRequestWriteContactsPermission() {
        checkAndRequestPermission(Manifest.permission.WRITE_CONTACTS, 0);
    }

    public void checkAndRequestRecordAudioPermissionForEchoCanceller() {
        checkAndRequestPermission(Manifest.permission.RECORD_AUDIO, PERMISSIONS_RECORD_AUDIO_ECHO_CANCELLER);
    }

    public void checkAndRequestRecordAudioPermissionsForEchoTester() {
        checkAndRequestPermission(Manifest.permission.RECORD_AUDIO, PERMISSIONS_RECORD_AUDIO_ECHO_TESTER);
    }

    public void checkAndRequestReadExternalStoragePermissionForDeviceRingtone() {
        checkAndRequestPermission(Manifest.permission.READ_EXTERNAL_STORAGE,
                PERMISSIONS_READ_EXTERNAL_STORAGE_DEVICE_RINGTONE);
    }

    public void checkAndRequestPermissionsToSendImage() {
        ArrayList<String> permissionsList = new ArrayList<String>();

        int readExternalStorage = getPackageManager().checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE,
                getPackageName());
        Log.i("[Permission] Read external storage permission is "
                + (readExternalStorage == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
        int camera = getPackageManager().checkPermission(Manifest.permission.CAMERA, getPackageName());
        Log.i("[Permission] Camera permission is "
                + (camera == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));

        if (readExternalStorage != PackageManager.PERMISSION_GRANTED) {
            if (LinphonePreferences.instance()
                    .firstTimeAskingForPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
                    || ActivityCompat.shouldShowRequestPermissionRationale(this,
                            Manifest.permission.READ_EXTERNAL_STORAGE)) {
                Log.i("[Permission] Asking for read external storage");
                permissionsList.add(Manifest.permission.READ_EXTERNAL_STORAGE);
            }
        }
        if (camera != PackageManager.PERMISSION_GRANTED) {
            if (LinphonePreferences.instance().firstTimeAskingForPermission(Manifest.permission.CAMERA)
                    || ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
                Log.i("[Permission] Asking for camera");
                permissionsList.add(Manifest.permission.CAMERA);
            }
        }
        if (permissionsList.size() > 0) {
            String[] permissions = new String[permissionsList.size()];
            permissions = permissionsList.toArray(permissions);
            ActivityCompat.requestPermissions(this, permissions, 0);
        }
    }

    private void checkSyncPermission() {
        checkAndRequestPermission(Manifest.permission.WRITE_SYNC_SETTINGS, PERMISSIONS_REQUEST_SYNC);
    }

    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) {
            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, int[] grantResults) {
        if (permissions.length <= 0)
            return;

        int readContactsI = -1;
        for (int i = 0; i < permissions.length; i++) {
            Log.i("[Permission] " + permissions[i] + " is "
                    + (grantResults[i] == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));
            if (permissions[i].compareTo(Manifest.permission.READ_CONTACTS) == 0)
                readContactsI = i;
        }

        switch (requestCode) {
        case PERMISSIONS_REQUEST_SYNC:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                ContactsManager.getInstance().initializeSyncAccount(getApplicationContext(), getContentResolver());
            } else {
                ContactsManager.getInstance().initializeContactManager(getApplicationContext(),
                        getContentResolver());
            }
            break;
        case PERMISSIONS_RECORD_AUDIO_ECHO_CANCELLER:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                ((SettingsFragment) fragment).startEchoCancellerCalibration();
            } else {
                ((SettingsFragment) fragment).echoCalibrationFail();
            }
            break;
        case PERMISSIONS_READ_EXTERNAL_STORAGE_DEVICE_RINGTONE:
            if (permissions[0].compareTo(Manifest.permission.READ_EXTERNAL_STORAGE) != 0)
                break;
            boolean enableRingtone = (grantResults[0] == PackageManager.PERMISSION_GRANTED);
            LinphonePreferences.instance().enableDeviceRingtone(enableRingtone);
            LinphoneManager.getInstance().enableDeviceRingtone(enableRingtone);
            break;
        case PERMISSIONS_RECORD_AUDIO_ECHO_TESTER:
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED)
                ((SettingsFragment) fragment).startEchoTester();
            break;
        }
        if (readContactsI >= 0 && grantResults[readContactsI] == PackageManager.PERMISSION_GRANTED) {
            ContactsManager.getInstance().enableContactsAccess();
            if (!fetchedContactsOnce) {
                ContactsManager.getInstance().enableContactsAccess();
                ContactsManager.getInstance().fetchContactsAsync();
                fetchedContactsOnce = true;
            }
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        ArrayList<String> permissionsList = new ArrayList<String>();

        int contacts = getPackageManager().checkPermission(Manifest.permission.READ_CONTACTS, getPackageName());
        Log.i("[Permission] Contacts permission is "
                + (contacts == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));

        int readPhone = getPackageManager().checkPermission(Manifest.permission.READ_PHONE_STATE, getPackageName());
        Log.i("[Permission] Read phone state permission is "
                + (readPhone == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));

        int ringtone = getPackageManager().checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE,
                getPackageName());
        Log.i("[Permission] Read external storage for ring tone permission is "
                + (ringtone == PackageManager.PERMISSION_GRANTED ? "granted" : "denied"));

        if (ringtone != PackageManager.PERMISSION_GRANTED) {
            if (LinphonePreferences.instance()
                    .firstTimeAskingForPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
                    || ActivityCompat.shouldShowRequestPermissionRationale(this,
                            Manifest.permission.READ_EXTERNAL_STORAGE)) {
                Log.i("[Permission] Asking for read external storage for ring tone");
                permissionsList.add(Manifest.permission.READ_EXTERNAL_STORAGE);
            }
        }
        if (readPhone != PackageManager.PERMISSION_GRANTED) {
            if (LinphonePreferences.instance().firstTimeAskingForPermission(Manifest.permission.READ_PHONE_STATE)
                    || ActivityCompat.shouldShowRequestPermissionRationale(this,
                            Manifest.permission.READ_PHONE_STATE)) {
                Log.i("[Permission] Asking for read phone state");
                permissionsList.add(Manifest.permission.READ_PHONE_STATE);
            }
        }
        if (contacts != PackageManager.PERMISSION_GRANTED) {
            if (LinphonePreferences.instance().firstTimeAskingForPermission(Manifest.permission.READ_CONTACTS)
                    || ActivityCompat.shouldShowRequestPermissionRationale(this,
                            Manifest.permission.READ_CONTACTS)) {
                Log.i("[Permission] Asking for contacts");
                permissionsList.add(Manifest.permission.READ_CONTACTS);
            }
        } else {
            if (!fetchedContactsOnce) {
                ContactsManager.getInstance().enableContactsAccess();
                ContactsManager.getInstance().fetchContactsAsync();
                fetchedContactsOnce = true;
            }
        }

        if (permissionsList.size() > 0) {
            String[] permissions = new String[permissionsList.size()];
            permissions = permissionsList.toArray(permissions);
            ActivityCompat.requestPermissions(this, permissions, PERMISSIONS_READ_EXTERNAL_STORAGE_DEVICE_RINGTONE);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putSerializable("currentFragment", currentFragment);
        outState.putBoolean("fetchedContactsOnce", fetchedContactsOnce);
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        fetchedContactsOnce = savedInstanceState.getBoolean("fetchedContactsOnce");
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (!LinphoneService.isReady()) {
            startService(new Intent(Intent.ACTION_MAIN).setClass(this, LinphoneService.class));
        }

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

        if (isTablet()) {
            // Prevent fragmentContainer2 to be visible when rotating the device
            LinearLayout ll = (LinearLayout) findViewById(R.id.fragmentContainer2);
            if (currentFragment == FragmentsAvailable.DIALER || currentFragment == FragmentsAvailable.ABOUT
                    || currentFragment == FragmentsAvailable.SETTINGS
                    || currentFragment == FragmentsAvailable.ACCOUNT_SETTINGS) {
                ll.setVisibility(View.GONE);
            }
        }

        refreshAccounts();

        if (getResources().getBoolean(R.bool.enable_in_app_purchase)) {
            isTrialAccount();
        }

        updateMissedChatCount();
        if (LinphonePreferences.instance().isFriendlistsubscriptionEnabled()
                && LinphoneManager.getLc().getDefaultProxyConfig() != null) {
            LinphoneManager.getInstance().subscribeFriendList(true);
        } else {
            LinphoneManager.getInstance().subscribeFriendList(false);
        }

        displayMissedCalls(LinphoneManager.getLc().getMissedCallsCount());

        LinphoneManager.getInstance().changeStatusToOnline();

        if (getIntent().getIntExtra("PreviousActivity", 0) != CALL_ACTIVITY && !doNotGoToCallActivity) {
            if (LinphoneManager.getLc().getCalls().length > 0) {
                LinphoneCall call = LinphoneManager.getLc().getCalls()[0];
                LinphoneCall.State callState = call.getState();

                if (callState == State.IncomingReceived) {
                    startActivity(new Intent(this, CallIncomingActivity.class));
                } else if (callState == State.OutgoingInit || callState == State.OutgoingProgress
                        || callState == State.OutgoingRinging) {
                    startActivity(new Intent(this, CallOutgoingActivity.class));
                } else {
                    startIncallActivity(call);
                }
            }
        }
        doNotGoToCallActivity = false;
    }

    @Override
    protected void onDestroy() {
        if (mOrientationHelper != null) {
            mOrientationHelper.disable();
            mOrientationHelper = null;
        }

        instance = null;
        super.onDestroy();

        unbindDrawables(findViewById(R.id.topLayout));
        System.gc();
    }

    private void unbindDrawables(View view) {
        if (view != null && view.getBackground() != null) {
            view.getBackground().setCallback(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
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);

        Bundle extras = intent.getExtras();
        if (extras != null && extras.getBoolean("GoToChat", false)) {
            LinphoneService.instance().removeMessageNotification();
            String sipUri = extras.getString("ChatContactSipUri");
            doNotGoToCallActivity = true;
            displayChat(sipUri);
        } else if (extras != null && extras.getBoolean("GoToHistory", false)) {
            doNotGoToCallActivity = true;
            changeCurrentFragment(FragmentsAvailable.HISTORY_LIST, null);
        } else if (extras != null && extras.getBoolean("GoToInapp", false)) {
            LinphoneService.instance().removeMessageNotification();
            doNotGoToCallActivity = true;
            displayInapp();
        } else if (extras != null && extras.getBoolean("Notification", false)) {
            if (LinphoneManager.getLc().getCallsNb() > 0) {
                LinphoneCall call = LinphoneManager.getLc().getCalls()[0];
                startIncallActivity(call);
            }
        } else {
            DialerFragment dialerFragment = DialerFragment.instance();
            if (dialerFragment != null) {
                if (extras != null && extras.containsKey("SipUriOrNumber")) {
                    if (getResources().getBoolean(R.bool.automatically_start_intercepted_outgoing_gsm_call)) {
                        ((DialerFragment) dialerFragment).newOutgoingCall(extras.getString("SipUriOrNumber"));
                    } else {
                        ((DialerFragment) dialerFragment)
                                .displayTextInAddressBar(extras.getString("SipUriOrNumber"));
                    }
                } else {
                    ((DialerFragment) dialerFragment).newOutgoingCall(intent);
                }
            }
            if (LinphoneManager.getLc().getCalls().length > 0) {
                // If a call is ringing, start incomingcallactivity
                Collection<LinphoneCall.State> incoming = new ArrayList<LinphoneCall.State>();
                incoming.add(LinphoneCall.State.IncomingReceived);
                if (LinphoneUtils.getCallsInState(LinphoneManager.getLc(), incoming).size() > 0) {
                    if (CallActivity.isInstanciated()) {
                        CallActivity.instance().startIncomingCallActivity();
                    } else {
                        startActivity(new Intent(this, CallIncomingActivity.class));
                    }
                }
            }
        }
    }

    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            if (currentFragment == FragmentsAvailable.DIALER || currentFragment == FragmentsAvailable.CONTACTS_LIST
                    || currentFragment == FragmentsAvailable.HISTORY_LIST
                    || currentFragment == FragmentsAvailable.CHAT_LIST) {
                boolean isBackgroundModeActive = LinphonePreferences.instance().isBackgroundModeEnabled();
                if (!isBackgroundModeActive) {
                    stopService(new Intent(Intent.ACTION_MAIN).setClass(this, LinphoneService.class));
                    finish();
                } else if (LinphoneUtils.onKeyBackGoHome(this, keyCode, event)) {
                    return true;
                }
            }
        }
        return super.onKeyDown(keyCode, event);
    }

    //SIDE MENU
    public void openOrCloseSideMenu(boolean open) {
        if (open) {
            sideMenu.openDrawer(sideMenuContent);
        } else {
            sideMenu.closeDrawer(sideMenuContent);
        }
    }

    public void initSideMenu() {
        sideMenu = (DrawerLayout) findViewById(R.id.side_menu);
        sideMenuItems = new ArrayList<String>();
        sideMenuItems.add(getResources().getString(R.string.menu_assistant));
        sideMenuItems.add(getResources().getString(R.string.menu_settings));
        if (getResources().getBoolean(R.bool.enable_in_app_purchase)) {
            sideMenuItems.add(getResources().getString(R.string.inapp));
        }
        sideMenuItems.add(getResources().getString(R.string.menu_about));
        sideMenuContent = (RelativeLayout) findViewById(R.id.side_menu_content);
        sideMenuItemList = (ListView) findViewById(R.id.item_list);
        menu = (ImageView) findViewById(R.id.side_menu_button);

        sideMenuItemList.setAdapter(new ArrayAdapter<String>(this, R.layout.side_menu_item_cell, sideMenuItems));
        sideMenuItemList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                if (sideMenuItemList.getAdapter().getItem(i).toString().equals(getString(R.string.menu_settings))) {
                    LinphoneActivity.instance().displaySettings();
                }
                if (sideMenuItemList.getAdapter().getItem(i).toString().equals(getString(R.string.menu_about))) {
                    LinphoneActivity.instance().displayAbout();
                }
                if (sideMenuItemList.getAdapter().getItem(i).toString()
                        .equals(getString(R.string.menu_assistant))) {
                    LinphoneActivity.instance().displayAssistant();
                }
                if (getResources().getBoolean(R.bool.enable_in_app_purchase)) {
                    if (sideMenuItemList.getAdapter().getItem(i).toString().equals(getString(R.string.inapp))) {
                        LinphoneActivity.instance().displayInapp();
                    }
                }
                openOrCloseSideMenu(false);
            }
        });

        initAccounts();

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

        quitLayout = (RelativeLayout) findViewById(R.id.side_menu_quit);
        quitLayout.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                LinphoneActivity.instance().quit();
            }
        });
    }

    private int getStatusIconResource(LinphoneCore.RegistrationState state) {
        try {
            if (state == RegistrationState.RegistrationOk) {
                return R.drawable.led_connected;
            } else if (state == RegistrationState.RegistrationProgress) {
                return R.drawable.led_inprogress;
            } else if (state == RegistrationState.RegistrationFailed) {
                return R.drawable.led_error;
            } else {
                return R.drawable.led_disconnected;
            }
        } catch (Exception e) {
            Log.e(e);
        }

        return R.drawable.led_disconnected;
    }

    private void displayMainAccount() {
        defaultAccount.setVisibility(View.VISIBLE);
        ImageView status = (ImageView) defaultAccount.findViewById(R.id.main_account_status);
        TextView address = (TextView) defaultAccount.findViewById(R.id.main_account_address);
        TextView displayName = (TextView) defaultAccount.findViewById(R.id.main_account_display_name);

        LinphoneProxyConfig proxy = LinphoneManager.getLc().getDefaultProxyConfig();
        if (proxy == null) {
            displayName.setText(getString(R.string.no_account));
            status.setVisibility(View.GONE);
            address.setText("");
            statusFragment.resetAccountStatus();
            LinphoneManager.getInstance().subscribeFriendList(false);

            defaultAccount.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View view) {
                    LinphoneActivity.instance().displayAccountSettings(0);
                    openOrCloseSideMenu(false);
                }
            });
        } else {
            //address.setText(proxy.getAddress().asStringUriOnly());
            displayName.setText(LinphoneUtils.getAddressDisplayName(proxy.getAddress()));
            status.setImageResource(getStatusIconResource(proxy.getState()));
            status.setVisibility(View.VISIBLE);

            defaultAccount.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View view) {
                    LinphoneActivity.instance()
                            .displayAccountSettings(LinphonePreferences.instance().getDefaultAccountIndex());
                    openOrCloseSideMenu(false);
                }
            });
        }
    }

    public void refreshAccounts() {
        if (LinphoneManager.getLc().getProxyConfigList().length > 1) {
            accountsList.setVisibility(View.VISIBLE);
            accountsList.setAdapter(new AccountsListAdapter());
            accountsList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                    if (view != null && view.getTag() != null) {
                        int position = Integer.parseInt(view.getTag().toString());
                        LinphoneActivity.instance().displayAccountSettings(position);
                    }
                    openOrCloseSideMenu(false);
                }
            });
        } else {
            accountsList.setVisibility(View.GONE);
        }
        displayMainAccount();
    }

    private void initAccounts() {
        accountsList = (ListView) findViewById(R.id.accounts_list);
        defaultAccount = (RelativeLayout) findViewById(R.id.default_account);
    }

    class AccountsListAdapter extends BaseAdapter {
        List<LinphoneProxyConfig> proxy_list;

        AccountsListAdapter() {
            proxy_list = new ArrayList<LinphoneProxyConfig>();
            refresh();
        }

        public void refresh() {
            proxy_list = new ArrayList<LinphoneProxyConfig>();
            for (LinphoneProxyConfig proxyConfig : LinphoneManager.getLc().getProxyConfigList()) {
                if (proxyConfig != LinphoneManager.getLc().getDefaultProxyConfig()) {
                    proxy_list.add(proxyConfig);
                }
            }
        }

        public int getCount() {
            if (proxy_list != null) {
                return proxy_list.size();
            } else {
                return 0;
            }
        }

        public Object getItem(int position) {
            return proxy_list.get(position);
        }

        public long getItemId(int position) {
            return position;
        }

        public View getView(final int position, View convertView, ViewGroup parent) {
            View view = null;
            LinphoneProxyConfig lpc = (LinphoneProxyConfig) getItem(position);
            if (convertView != null) {
                view = convertView;
            } else {
                view = getLayoutInflater().inflate(R.layout.side_menu_account_cell, parent, false);
            }

            ImageView status = (ImageView) view.findViewById(R.id.account_status);
            TextView address = (TextView) view.findViewById(R.id.account_address);
            String sipAddress = lpc.getAddress().asStringUriOnly();

            address.setText(sipAddress);

            int nbAccounts = LinphonePreferences.instance().getAccountCount();
            int accountIndex = 0;

            for (int i = 0; i < nbAccounts; i++) {
                String username = LinphonePreferences.instance().getAccountUsername(i);
                String domain = LinphonePreferences.instance().getAccountDomain(i);
                String id = "sip:" + username + "@" + domain;
                if (id.equals(sipAddress)) {
                    accountIndex = i;
                    view.setTag(accountIndex);
                    break;
                }
            }
            status.setImageResource(getStatusIconResource(lpc.getState()));
            return view;
        }
    }

    //Inapp Purchase
    private void isTrialAccount() {
        if (LinphoneManager.getLc().getDefaultProxyConfig() != null
                && LinphonePreferences.instance().getInappPopupTime() != null) {
            XmlRpcHelper helper = new XmlRpcHelper();
            helper.isTrialAccountAsync(new XmlRpcListenerBase() {
                @Override
                public void onTrialAccountFetched(boolean isTrial) {
                    isTrialAccount = isTrial;
                    getExpirationAccount();
                }

                @Override
                public void onError(String error) {
                }
            }, LinphonePreferences.instance()
                    .getAccountUsername(LinphonePreferences.instance().getDefaultAccountIndex()),
                    LinphonePreferences.instance()
                            .getAccountHa1(LinphonePreferences.instance().getDefaultAccountIndex()));
        }
    }

    private void getExpirationAccount() {
        if (LinphoneManager.getLc().getDefaultProxyConfig() != null
                && LinphonePreferences.instance().getInappPopupTime() != null) {
            XmlRpcHelper helper = new XmlRpcHelper();
            helper.getAccountExpireAsync(new XmlRpcListenerBase() {
                @Override
                public void onAccountExpireFetched(String result) {
                    if (result != null) {
                        long timestamp = Long.parseLong(result);

                        Calendar calresult = Calendar.getInstance();
                        calresult.setTimeInMillis(timestamp);

                        int diff = getDiffDays(calresult, Calendar.getInstance());
                        if (diff != -1 && diff <= getResources().getInteger(R.integer.days_notification_shown)) {
                            displayInappNotification(timestampToHumanDate(calresult));
                        }
                    }
                }

                @Override
                public void onError(String error) {
                }
            }, LinphonePreferences.instance()
                    .getAccountUsername(LinphonePreferences.instance().getDefaultAccountIndex()),
                    LinphonePreferences.instance()
                            .getAccountHa1(LinphonePreferences.instance().getDefaultAccountIndex()));
        }
    }

    public void displayInappNotification(String date) {
        Timestamp now = new Timestamp(new Date().getTime());
        if (LinphonePreferences.instance().getInappPopupTime() != null
                && Long.parseLong(LinphonePreferences.instance().getInappPopupTime()) > now.getTime()) {
            return;
        } else {
            long newDate = now.getTime() + getResources().getInteger(R.integer.time_between_inapp_notification);
            LinphonePreferences.instance().setInappPopupTime(String.valueOf(newDate));
        }
        if (isTrialAccount) {
            LinphoneService.instance().displayInappNotification(
                    String.format(getString(R.string.inapp_notification_trial_expire), date));
        } else {
            LinphoneService.instance().displayInappNotification(
                    String.format(getString(R.string.inapp_notification_account_expire), date));
        }

    }

    private String timestampToHumanDate(Calendar cal) {
        SimpleDateFormat dateFormat;
        dateFormat = new SimpleDateFormat(getResources().getString(R.string.inapp_popup_date_format));
        return dateFormat.format(cal.getTime());
    }

    private int getDiffDays(Calendar cal1, Calendar cal2) {
        if (cal1 == null || cal2 == null) {
            return -1;
        }
        if (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA)
                && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR)) {
            return cal1.get(Calendar.DAY_OF_YEAR) - cal2.get(Calendar.DAY_OF_YEAR);
        }
        return -1;
    }
}

interface ContactPicked {
    void setAddresGoToDialerAndCall(String number, String name, Uri photo);
}