sipcall: Modify calls handling process

Integration of new security features implies modifications in call handling.
By default, when handling a call,  a SipCall object is created, but if ZRTP hooks
are activated, the call is dynamically subclassed, and becomes a SecureSipCall.

Refs #40939
diff --git a/src/org/sflphone/adapters/DiscussArrayAdapter.java b/src/org/sflphone/adapters/DiscussArrayAdapter.java
index 5399c0a..f7489ae 100644
--- a/src/org/sflphone/adapters/DiscussArrayAdapter.java
+++ b/src/org/sflphone/adapters/DiscussArrayAdapter.java
@@ -82,7 +82,7 @@
     public View getView(int position, View convertView, ViewGroup parent) {
         View row = convertView;
         if (row == null) {
-            LayoutInflater inflater = (LayoutInflater) LayoutInflater.from(mContext);
+            LayoutInflater inflater = LayoutInflater.from(mContext);
             row = inflater.inflate(R.layout.item_message, parent, false);
         }
 
@@ -100,10 +100,6 @@
         return row;
     }
 
-    public Bitmap decodeToBitmap(byte[] decodedByte) {
-        return BitmapFactory.decodeByteArray(decodedByte, 0, decodedByte.length);
-    }
-
     @Override
     public long getItemId(int position) {
         return 0;
diff --git a/src/org/sflphone/client/CallActivity.java b/src/org/sflphone/client/CallActivity.java
index 4242390..6e7143a 100644
--- a/src/org/sflphone/client/CallActivity.java
+++ b/src/org/sflphone/client/CallActivity.java
@@ -33,12 +33,10 @@
 
 package org.sflphone.client;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Timer;
-import java.util.TimerTask;
+import java.util.*;
 
 import android.support.v4.app.FragmentActivity;
+import android.util.Log;
 import org.sflphone.R;
 import org.sflphone.fragments.CallFragment;
 import org.sflphone.fragments.IMFragment;
@@ -191,27 +189,33 @@
                     ArrayList<HashMap<String, String>> credentials = (ArrayList<HashMap<String, String>>) mService.getCredentials(accountID);
                     Account acc = new Account(accountID, details, credentials);
 
-                    SipCall call = SipCall.SipCallBuilder.getInstance().startCallCreation().setContact(c).setAccount(acc)
-                            .setCallType(SipCall.direction.CALL_TYPE_OUTGOING).build();
+                    Bundle args = new Bundle();
+                    args.putString(SipCall.ID, Integer.toString(Math.abs(new Random().nextInt())));
+                    args.putParcelable(SipCall.ACCOUNT, acc);
+                    args.putInt(SipCall.STATE, SipCall.state.CALL_STATE_RINGING);
+                    args.putInt(SipCall.TYPE, SipCall.direction.CALL_TYPE_OUTGOING);
+                    args.putParcelable(SipCall.CONTACT, c);
+
                     mDisplayedConference = new Conference(Conference.DEFAULT_ID);
-                    mDisplayedConference.getParticipants().add(call);
+                    mDisplayedConference.getParticipants().add(new SipCall(args));
                 } catch (RemoteException e) {
                     e.printStackTrace();
                 } catch (Exception e) {
                     e.printStackTrace();
                 }
             } else {
+                mDisplayedConference = getIntent().getParcelableExtra("conference");
                 if (getIntent().getBooleanExtra("resuming", false)) {
-
-                    mDisplayedConference = getIntent().getParcelableExtra("conference");
-
                     Bundle IMBundle = new Bundle();
                     IMBundle.putParcelableArrayList("messages", mDisplayedConference.getMessages());
                     mIMFragment.setArguments(IMBundle);
-
                 } else {
-                    mDisplayedConference = getIntent().getParcelableExtra("conference");
                     Bundle IMBundle = new Bundle();
+                    try {
+                        mService.placeCall(mDisplayedConference.getParticipants().get(0));
+                    } catch (RemoteException e) {
+                        e.printStackTrace();
+                    }
                     IMBundle.putParcelableArrayList("messages", new ArrayList<SipMessage>());
                     mIMFragment.setArguments(IMBundle);
                 }
@@ -241,6 +245,15 @@
     }
 
     @Override
+    public void updateDisplayedConference(Conference c) {
+        Log.e(TAG, "toUpdate.getParticipants() :"+ c.getParticipants().size());
+        if(mDisplayedConference.equals(c)){
+            Log.e(TAG, "It's equal");
+            mDisplayedConference = c;
+        }
+    }
+
+    @Override
     public void onBackPressed() {
         super.onBackPressed();
         Intent launchHome = new Intent(this, HomeActivity.class);
@@ -268,7 +281,8 @@
     public boolean sendIM(SipMessage msg) {
 
         try {
-            mService.sendTextMessage(mCurrentCallFragment.getConference().getId(), msg);
+            Log.i(TAG, "Sending:"+msg.comment+"to"+mDisplayedConference.getId());
+            mService.sendTextMessage(mDisplayedConference.getId(), msg);
         } catch (RemoteException e) {
             e.printStackTrace();
             return false;
diff --git a/src/org/sflphone/client/HomeActivity.java b/src/org/sflphone/client/HomeActivity.java
index 092ced0..09b77eb 100644
--- a/src/org/sflphone/client/HomeActivity.java
+++ b/src/org/sflphone/client/HomeActivity.java
@@ -37,6 +37,7 @@
 import java.io.InputStream;
 import java.io.InvalidObjectException;
 import java.io.OutputStream;
+import java.util.Random;
 import java.util.Timer;
 import java.util.TimerTask;
 
@@ -475,30 +476,32 @@
 
             @Override
             public void run() {
-                SipCall.SipCallBuilder callBuilder = SipCall.SipCallBuilder.getInstance();
-                try {
-                    callBuilder.startCallCreation().setAccount(fMenu.getSelectedAccount()).setCallType(SipCall.direction.CALL_TYPE_OUTGOING);
-                    Cursor cPhones = getContentResolver().query(Phone.CONTENT_URI, CONTACTS_PHONES_PROJECTION, Phone.CONTACT_ID + " =" + c.getId(),
-                            null, null);
 
-                    while (cPhones.moveToNext()) {
-                        c.addPhoneNumber(cPhones.getString(cPhones.getColumnIndex(Phone.NUMBER)), cPhones.getInt(cPhones.getColumnIndex(Phone.TYPE)));
-                    }
-                    cPhones.close();
+                Bundle args = new Bundle();
+                args.putString(SipCall.ID, Integer.toString(Math.abs(new Random().nextInt())));
+                args.putParcelable(SipCall.ACCOUNT, fMenu.getSelectedAccount());
+                args.putInt(SipCall.STATE, SipCall.state.CALL_STATE_RINGING);
+                args.putInt(SipCall.TYPE, SipCall.direction.CALL_TYPE_OUTGOING);
 
-                    Cursor cSip = getContentResolver().query(Phone.CONTENT_URI, CONTACTS_SIP_PROJECTION, Phone.CONTACT_ID + "=" + c.getId(), null,
-                            null);
+                Cursor cPhones = getContentResolver().query(Phone.CONTENT_URI, CONTACTS_PHONES_PROJECTION, Phone.CONTACT_ID + " =" + c.getId(),
+                        null, null);
 
-                    while (cSip.moveToNext()) {
-                        c.addSipNumber(cSip.getString(cSip.getColumnIndex(SipAddress.SIP_ADDRESS)), cSip.getInt(cSip.getColumnIndex(SipAddress.TYPE)));
-                    }
-                    cSip.close();
-                    callBuilder.setContact(c);
-                    launchCallActivity(callBuilder.build());
-                } catch (InvalidObjectException e) {
-                    e.printStackTrace();
+                while (cPhones.moveToNext()) {
+                    c.addPhoneNumber(cPhones.getString(cPhones.getColumnIndex(Phone.NUMBER)), cPhones.getInt(cPhones.getColumnIndex(Phone.TYPE)));
                 }
+                cPhones.close();
 
+                Cursor cSip = getContentResolver().query(Phone.CONTENT_URI, CONTACTS_SIP_PROJECTION, Phone.CONTACT_ID + "=" + c.getId(), null,
+                        null);
+
+                while (cSip.moveToNext()) {
+                    c.addSipNumber(cSip.getString(cSip.getColumnIndex(SipAddress.SIP_ADDRESS)), cSip.getInt(cSip.getColumnIndex(SipAddress.TYPE)));
+                }
+                cSip.close();
+
+                args.putParcelable(SipCall.CONTACT, c);
+
+                launchCallActivity(new SipCall(args));
             }
         });
         launcher.start();
@@ -517,11 +520,15 @@
         }
 
         if (usedAccount.isRegistered()) {
-            SipCall.SipCallBuilder callBuilder = SipCall.SipCallBuilder.getInstance();
-            callBuilder.startCallCreation().setAccount(usedAccount).setCallType(SipCall.direction.CALL_TYPE_OUTGOING);
-            callBuilder.setContact(to.getContact());
+            Bundle args = new Bundle();
+            args.putString(SipCall.ID, Integer.toString(Math.abs(new Random().nextInt())));
+            args.putParcelable(SipCall.ACCOUNT, usedAccount);
+            args.putInt(SipCall.STATE, SipCall.state.CALL_STATE_RINGING);
+            args.putInt(SipCall.TYPE, SipCall.direction.CALL_TYPE_OUTGOING);
+            args.putParcelable(SipCall.CONTACT, to.getContact());
+
             try {
-                launchCallActivity(callBuilder.build());
+                launchCallActivity(new SipCall(args));
             } catch (Exception e) {
                 Log.e(TAG, e.toString());
             }
@@ -532,8 +539,6 @@
 
     @Override
     public void onCallDialed(String to) {
-
-
         Account usedAccount = fMenu.getSelectedAccount();
 
         if (usedAccount == null) {
@@ -542,12 +547,15 @@
         }
 
         if (fMenu.getSelectedAccount().isRegistered()) {
-            SipCall.SipCallBuilder callBuilder = SipCall.SipCallBuilder.getInstance();
-            callBuilder.startCallCreation().setAccount(usedAccount).setCallType(SipCall.direction.CALL_TYPE_OUTGOING);
-            callBuilder.setContact(CallContact.ContactBuilder.buildUnknownContact(to));
+            Bundle args = new Bundle();
+            args.putString(SipCall.ID, Integer.toString(Math.abs(new Random().nextInt())));
+            args.putParcelable(SipCall.ACCOUNT, usedAccount);
+            args.putInt(SipCall.STATE, SipCall.state.CALL_STATE_RINGING);
+            args.putInt(SipCall.TYPE, SipCall.direction.CALL_TYPE_OUTGOING);
+            args.putParcelable(SipCall.CONTACT, CallContact.ContactBuilder.buildUnknownContact(to));
 
             try {
-                launchCallActivity(callBuilder.build());
+                launchCallActivity(new SipCall(args));
             } catch (Exception e) {
                 Log.e(TAG, e.toString());
             }
diff --git a/src/org/sflphone/fragments/AccountWrapperFragment.java b/src/org/sflphone/fragments/AccountWrapperFragment.java
index 98dab74..646f0e0 100644
--- a/src/org/sflphone/fragments/AccountWrapperFragment.java
+++ b/src/org/sflphone/fragments/AccountWrapperFragment.java
@@ -1,3 +1,34 @@
+/*
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
+ *
+ *  Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
+ *
+ *  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 3 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
 package org.sflphone.fragments;
 
 import android.content.BroadcastReceiver;
@@ -10,10 +41,7 @@
 import org.sflphone.interfaces.AccountsInterface;
 import org.sflphone.service.ConfigurationManagerCallback;
 
-/**
- * Created by lisional on 11/02/14.
- */
-public class AccountWrapperFragment extends Fragment implements AccountsInterface {
+public abstract class AccountWrapperFragment extends Fragment implements AccountsInterface {
 
 
     private AccountsReceiver mReceiver;
diff --git a/src/org/sflphone/fragments/AccountsManagementFragment.java b/src/org/sflphone/fragments/AccountsManagementFragment.java
index f6f7413..206770e 100644
--- a/src/org/sflphone/fragments/AccountsManagementFragment.java
+++ b/src/org/sflphone/fragments/AccountsManagementFragment.java
@@ -283,7 +283,7 @@
         @Override
         public View getView(final int pos, View convertView, ViewGroup parent) {
             View rowView = convertView;
-            AccountView entryView = null;
+            AccountView entryView;
 
             if (rowView == null) {
                 LayoutInflater inflater = LayoutInflater.from(mContext);
diff --git a/src/org/sflphone/fragments/CallFragment.java b/src/org/sflphone/fragments/CallFragment.java
index 382b1a6..2c306a7 100644
--- a/src/org/sflphone/fragments/CallFragment.java
+++ b/src/org/sflphone/fragments/CallFragment.java
@@ -73,7 +73,6 @@
     public static final int REQUEST_TRANSFER = 10;
 
 
-
     private TextView callStatusTxt;
     private ToggleButton speakers;
 
@@ -96,7 +95,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             WifiInfo info = wifiManager.getConnectionInfo();
-            Log.i(TAG, "Level of wifi " +info.getRssi());
+            Log.i(TAG, "Level of wifi " + info.getRssi());
         }
 
     };
@@ -121,14 +120,14 @@
         }
     }
 
-    private void initializeWiFiListener(){
+    private void initializeWiFiListener() {
         Log.i(TAG, "executing initializeWiFiListener");
 
         String connectivity_context = Context.WIFI_SERVICE;
         wifiManager = (WifiManager) getActivity().getSystemService(connectivity_context);
 
-        if(!wifiManager.isWifiEnabled()){
-            if(wifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLING){
+        if (!wifiManager.isWifiEnabled()) {
+            if (wifiManager.getWifiState() != WifiManager.WIFI_STATE_ENABLING) {
                 wifiManager.setWifiEnabled(true);
             }
         }
@@ -156,17 +155,21 @@
         }
 
         @Override
+        public void updateDisplayedConference(Conference c) {
+        }
+
+        @Override
         public void startTimer() {
         }
 
         @Override
         public void slideChatScreen() {
         }
+
     };
 
     /**
      * The Activity calling this fragment has to implement this interface
-     * 
      */
     public interface Callbacks {
 
@@ -179,6 +182,8 @@
         public void terminateCall();
 
         public Conference getDisplayedConference();
+
+        public void updateDisplayedConference(Conference c);
     }
 
     @Override
@@ -206,9 +211,9 @@
     public boolean onOptionsItemSelected(MenuItem item) {
         super.onOptionsItemSelected(item);
         switch (item.getItemId()) {
-        case R.id.menuitem_chat:
-            mCallbacks.slideChatScreen();
-            break;
+            case R.id.menuitem_chat:
+                mCallbacks.slideChatScreen();
+                break;
         }
 
         return true;
@@ -242,43 +247,63 @@
     }
 
     @Override
-    public void callStateChanged(String callID, String state) {
-        changeCallState(callID, state);
+    public void callStateChanged(Conference updated, String callID, String newState) {
+        mCallbacks.updateDisplayedConference(updated);
+        Log.i(TAG, "Call :" + callID + " " + newState);
+
+        if (getConference().isOnGoing()) {
+            initNormalStateDisplay();
+        } else if (getConference().isRinging()) {
+            callStatusTxt.setText(newState);
+
+            if (getConference().isIncoming()) {
+                initIncomingCallDisplay();
+            } else
+                initOutGoingCallDisplay();
+        } else {
+            callStatusTxt.setText(newState);
+            mCallbacks.terminateCall();
+        }
     }
 
     @Override
-    public void recordingChanged(String callID, String filename) {
-
-    }
-
-    @Override
-    public void secureZrtpOn(String id) {
+    public void secureZrtpOn(Conference updated, String id) {
         Log.i(TAG, "secureZrtpOn");
+        mCallbacks.updateDisplayedConference(updated);
         //enableSASButton();
     }
 
     @Override
-    public void secureZrtpOff(String id) {
+    public void secureZrtpOff(Conference updated, String id) {
         Log.i(TAG, "secureZrtpOff");
+        mCallbacks.updateDisplayedConference(updated);
     }
 
     @Override
-    public void displaySAS(final String callID, String SAS, boolean verified) {
+    public void displaySAS(Conference updated, final String securedCallID) {
         Log.i(TAG, "displaySAS");
-        final Button sas = (Button) getView().findViewById(R.id.confirm_sas);
-        sas.setText("Confirm SAS: " + SAS);
-        sas.setVisibility(View.VISIBLE);
-        sas.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                try {
-                    mCallbacks.getService().confirmSAS(callID);
-                    sas.setVisibility(View.INVISIBLE);
-                } catch (RemoteException e) {
-                    e.printStackTrace();
-                }
+        mCallbacks.updateDisplayedConference(updated);
+        SecureSipCall display = (SecureSipCall) getConference().getCallById(securedCallID);
+
+        if (display != null) {
+            if (!display.isConfirmedSAS()) {
+                final Button sas = (Button) getView().findViewById(R.id.confirm_sas);
+                sas.setText("Confirm SAS: " + display.getSAS());
+                sas.setVisibility(View.VISIBLE);
+                sas.setOnClickListener(new OnClickListener() {
+                    @Override
+                    public void onClick(View v) {
+                        try {
+                            mCallbacks.getService().confirmSAS(securedCallID);
+                            sas.setVisibility(View.INVISIBLE);
+                        } catch (RemoteException e) {
+                            e.printStackTrace();
+                        }
+                    }
+                });
             }
-        });
+        }
+
     }
 
     @Override
@@ -287,33 +312,33 @@
         SipCall transfer;
         if (requestCode == REQUEST_TRANSFER) {
             switch (resultCode) {
-            case TransferDFragment.RESULT_TRANSFER_CONF:
-                Conference c = data.getParcelableExtra("target");
-                transfer = data.getParcelableExtra("transfer");
-                try {
+                case TransferDFragment.RESULT_TRANSFER_CONF:
+                    Conference c = data.getParcelableExtra("target");
+                    transfer = data.getParcelableExtra("transfer");
+                    try {
 
-                    mCallbacks.getService().attendedTransfer(transfer.getCallId(), c.getParticipants().get(0).getCallId());
+                        mCallbacks.getService().attendedTransfer(transfer.getCallId(), c.getParticipants().get(0).getCallId());
 
-                } catch (RemoteException e) {
-                    e.printStackTrace();
-                }
-                break;
+                    } catch (RemoteException e) {
+                        e.printStackTrace();
+                    }
+                    break;
 
-            case TransferDFragment.RESULT_TRANSFER_NUMBER:
-                String to = data.getStringExtra("to_number");
-                transfer = data.getParcelableExtra("transfer");
-                try {
-                    mCallbacks.getService().transfer(transfer.getCallId(), to);
-                    mCallbacks.getService().hangUp(transfer.getCallId());
-                } catch (RemoteException e) {
-                    e.printStackTrace();
-                }
-                break;
-            case Activity.RESULT_CANCELED:
-            default:
-                model.clear();
-                initNormalStateDisplay();
-                break;
+                case TransferDFragment.RESULT_TRANSFER_NUMBER:
+                    String to = data.getStringExtra("to_number");
+                    transfer = data.getParcelableExtra("transfer");
+                    try {
+                        mCallbacks.getService().transfer(transfer.getCallId(), to);
+                        mCallbacks.getService().hangUp(transfer.getCallId());
+                    } catch (RemoteException e) {
+                        e.printStackTrace();
+                    }
+                    break;
+                case Activity.RESULT_CANCELED:
+                default:
+                    model.clear();
+                    initNormalStateDisplay();
+                    break;
             }
         }
     }
@@ -357,7 +382,7 @@
         return rootView;
     }
 
-    public Conference getConference(){
+    public Conference getConference() {
         return mCallbacks.getDisplayedConference();
     }
 
@@ -387,8 +412,6 @@
     private void initIncomingCallDisplay() {
         Log.i(TAG, "Start incoming display");
 
-        mCallbacks.startTimer();
-
         int radiusCalls = (int) (model.width / 2 - BUBBLE_SIZE);
         getBubbleForUser(getConference(), model.width / 2, model.height / 2 + radiusCalls);
         getBubbleFor(getConference().getParticipants().get(0), model.width / 2, model.height / 2 - radiusCalls);
@@ -397,7 +420,6 @@
         model.addAttractor(new Attractor(new PointF(model.width / 2, model.height / 2), ATTRACTOR_SIZE, new Attractor.Callback() {
             @Override
             public boolean onBubbleSucked(Bubble b) {
-
                 if (!accepted) {
                     try {
                         mCallbacks.getService().accept(b.getCallID());
@@ -422,8 +444,6 @@
     private void initOutGoingCallDisplay() {
         Log.i(TAG, "Start outgoing display");
 
-        mCallbacks.startTimer();
-
         getBubbleForUser(getConference(), model.width / 2, model.height / 2);
 
         // TODO off-thread image loading
@@ -441,13 +461,10 @@
 
     /**
      * Retrieves or create a bubble for a given contact. If the bubble exists, it is moved to the new location.
-     * 
-     * @param call
-     *            The call associated to a contact
-     * @param x
-     *            Initial or new x position.
-     * @param y
-     *            Initial or new y position.
+     *
+     * @param call The call associated to a contact
+     * @param x    Initial or new x position.
+     * @param y    Initial or new y position.
      * @return Bubble corresponding to the contact.
      */
     private Bubble getBubbleFor(SipCall call, float x, float y) {
@@ -487,39 +504,6 @@
         return contact_bubble;
     }
 
-    public void changeCallState(String callID, String newState) {
-        Log.i(TAG, "Call :" + callID + " " + newState);
-        if (newState.contentEquals("FAILURE")) {
-            try {
-                mCallbacks.getService().hangUp(callID);
-            } catch (RemoteException e) {
-                e.printStackTrace();
-            }
-        }
-        if (getConference() == null) {
-            return;
-        }
-        for (int i = 0; i < getConference().getParticipants().size(); ++i) {
-            if (callID.equals(getConference().getParticipants().get(i).getCallId())) {
-                if (newState.contentEquals("HUNGUP")) {
-                    model.removeBubble(getConference().getParticipants().get(i));
-                    getConference().getParticipants().remove(i);
-                } else {
-                    getConference().getParticipants().get(i).setCallState(newState);
-                }
-            }
-        }
-
-        if (getConference().isOnGoing()) {
-            initNormalStateDisplay();
-        }
-
-        if (getConference().getParticipants().size() == 0) {
-            callStatusTxt.setText(newState);
-            mCallbacks.terminateCall();
-        }
-    }
-
     public boolean draggingBubble() {
         return view == null ? false : view.isDraggingBubble();
     }
@@ -530,23 +514,9 @@
         if (getConference().getParticipants().size() == 1) {
             if (getConference().getParticipants().get(0).isIncoming() && getConference().getParticipants().get(0).isRinging()) {
                 initIncomingCallDisplay();
-            } else {
-                if (getConference().getParticipants().get(0).isRinging()) {
-                    initOutGoingCallDisplay();
-                }
-                try {
-                    if (getConference().getParticipants().get(0).isOutGoing()
-                            && mCallbacks.getService().getConference(getConference().getId()) == null) {
-                        mCallbacks.getService().placeCall(getConference().getParticipants().get(0));
-                        initOutGoingCallDisplay();
-                    } else if (getConference().getParticipants().get(0).isOutGoing() && getConference().getParticipants().get(0).isRinging()) {
-                        initOutGoingCallDisplay();
-                    }
-                } catch (RemoteException e) {
-                    Log.e(TAG, e.toString());
-                }
-            }
-            if (getConference().getParticipants().get(0).isOngoing()) {
+            } else if (getConference().getParticipants().get(0).isRinging()) {
+                initOutGoingCallDisplay();
+            } else if (getConference().getParticipants().get(0).isOngoing()) {
                 initNormalStateDisplay();
             }
         } else if (getConference().getParticipants().size() > 1) {
@@ -590,24 +560,28 @@
     }
 
     public void updateTime() {
-        long duration = System.currentTimeMillis() / 1000 - this.getConference().getParticipants().get(0).getTimestampStart_();
-        if (getConference().isOnGoing())
-            callStatusTxt.setText(String.format("%d:%02d:%02d", duration / 3600, duration % 3600 / 60, duration % 60));
+        if (getConference() != null) {
+            long duration = System.currentTimeMillis() - getConference().getParticipants().get(0).getTimestampStart_();
+            duration = duration / 1000;
+            if (getConference().isOnGoing())
+                callStatusTxt.setText(String.format("%d:%02d:%02d", duration / 3600, duration % 3600 / 60, duration % 60));
+        }
+
     }
 
     public void onKeyUp(int keyCode, KeyEvent event) {
         try {
 
             switch (keyCode) {
-            case KeyEvent.KEYCODE_VOLUME_DOWN:
-            case KeyEvent.KEYCODE_VOLUME_UP:
-                break;
-            default:
-                String toSend = Character.toString(event.getDisplayLabel());
-                toSend.toUpperCase(Locale.getDefault());
-                Log.d(TAG, "toSend " + toSend);
-                mCallbacks.getService().playDtmf(toSend);
-                break;
+                case KeyEvent.KEYCODE_VOLUME_DOWN:
+                case KeyEvent.KEYCODE_VOLUME_UP:
+                    break;
+                default:
+                    String toSend = Character.toString(event.getDisplayLabel());
+                    toSend.toUpperCase(Locale.getDefault());
+                    Log.d(TAG, "toSend " + toSend);
+                    mCallbacks.getService().playDtmf(toSend);
+                    break;
             }
         } catch (RemoteException e) {
             e.printStackTrace();
diff --git a/src/org/sflphone/fragments/CallListFragment.java b/src/org/sflphone/fragments/CallListFragment.java
index 82b357b..9934401 100644
--- a/src/org/sflphone/fragments/CallListFragment.java
+++ b/src/org/sflphone/fragments/CallListFragment.java
@@ -83,31 +83,31 @@
     };
 
     @Override
-    public void callStateChanged(String callID, String state) {
+    public void callStateChanged(Conference c, String callID, String state) {
         Log.i(TAG, "callStateChanged" + callID + "    " + state);
         updateLists();
     }
 
     @Override
-    public void confCreated(String id) {
+    public void confCreated(Conference c, String id) {
         Log.i(TAG, "confCreated");
         updateLists();
     }
 
     @Override
-    public void confRemoved(String id) {
+    public void confRemoved(Conference c, String id) {
         Log.i(TAG, "confRemoved");
         updateLists();
     }
 
     @Override
-    public void confChanged(String id, String state) {
+    public void confChanged(Conference c, String id, String state) {
         Log.i(TAG, "confChanged");
         updateLists();
     }
 
     @Override
-    public void recordingChanged(String callID, String filename) {
+    public void recordingChanged(Conference c, String callID, String filename) {
         Log.i(TAG, "confChanged");
         updateLists();
     }
@@ -281,7 +281,7 @@
 
             Conference call = calls.get(position);
             if (call.getParticipants().size() == 1) {
-                ((TextView) convertView.findViewById(R.id.call_title)).setText(call.getParticipants().get(0).getContact().getmDisplayName());
+                ((TextView) convertView.findViewById(R.id.call_title)).setText(call.getParticipants().get(0).getmContact().getmDisplayName());
 
                 long duration = System.currentTimeMillis() / 1000 - (call.getParticipants().get(0).getTimestampStart_());
 
@@ -389,7 +389,7 @@
                     String to = data.getStringExtra("to_number");
                     transfer = data.getParcelableExtra("transfer");
                     try {
-                        Toast.makeText(getActivity(), getString(R.string.home_transfering, transfer.getParticipants().get(0).getContact().getmDisplayName(), to),
+                        Toast.makeText(getActivity(), getString(R.string.home_transfering, transfer.getParticipants().get(0).getmContact().getmDisplayName(), to),
                                 Toast.LENGTH_SHORT).show();
                         mCallbacks.getService().transfer(transfer.getParticipants().get(0).getCallId(), to);
                         mCallbacks.getService().hangUp(transfer.getParticipants().get(0).getCallId());
diff --git a/src/org/sflphone/fragments/CallableWrapperFragment.java b/src/org/sflphone/fragments/CallableWrapperFragment.java
index e85f94f..0dc3c73 100644
--- a/src/org/sflphone/fragments/CallableWrapperFragment.java
+++ b/src/org/sflphone/fragments/CallableWrapperFragment.java
@@ -1,3 +1,34 @@
+/*
+ *  Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
+ *
+ *  Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
+ *
+ *  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 3 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Additional permission under GNU GPL version 3 section 7:
+ *
+ *  If you modify this program, or any covered work, by linking or
+ *  combining it with the OpenSSL project's OpenSSL library (or a
+ *  modified version of that library), containing parts covered by the
+ *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
+ *  grants you additional permission to convey the resulting work.
+ *  Corresponding Source for a non-source form of such a combination
+ *  shall include the source code for the parts of OpenSSL used as well
+ *  as that of the covered work.
+ */
+
 package org.sflphone.fragments;
 
 import android.content.BroadcastReceiver;
@@ -8,11 +39,10 @@
 import android.support.v4.app.Fragment;
 import android.util.Log;
 import org.sflphone.interfaces.CallInterface;
+import org.sflphone.model.Conference;
+import org.sflphone.model.SipCall;
 import org.sflphone.service.CallManagerCallBack;
 
-/**
- * Created by lisional on 10/02/14.
- */
 public abstract class CallableWrapperFragment extends Fragment implements CallInterface {
 
 
@@ -50,47 +80,47 @@
     }
 
     @Override
-    public void callStateChanged(String callID, String state) {
+    public void callStateChanged(Conference c, String callID, String state) {
 
     }
 
     @Override
-    public void incomingText(String ID, String from, String msg) {
+    public void incomingText(Conference c, String ID, String from, String msg) {
 
     }
 
     @Override
-    public void confCreated(String id) {
+    public void confCreated(Conference c, String id) {
 
     }
 
     @Override
-    public void confRemoved(String id) {
+    public void confRemoved(Conference c, String id) {
 
     }
 
     @Override
-    public void confChanged(String id, String state) {
+    public void confChanged(Conference c, String id, String state) {
 
     }
 
     @Override
-    public void recordingChanged(String callID, String filename) {
+    public void recordingChanged(Conference c, String callID, String filename) {
 
     }
 
     @Override
-    public void secureZrtpOn(String id) {
+    public void secureZrtpOn(Conference c, String id) {
 
     }
 
     @Override
-    public void secureZrtpOff(String id) {
+    public void secureZrtpOff(Conference c, String id) {
 
     }
 
     @Override
-    public void displaySAS(String callID, String SAS, boolean verified) {
+    public void displaySAS(Conference c, String securedCallID) {
 
     }
 
@@ -101,23 +131,23 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (intent.getAction().contentEquals(CallManagerCallBack.INCOMING_TEXT)) {
-                incomingText(intent.getStringExtra("CallID"), intent.getStringExtra("From"), intent.getStringExtra("Msg"));
+                incomingText((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("CallID"), intent.getStringExtra("From"), intent.getStringExtra("Msg"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.CALL_STATE_CHANGED)) {
-                callStateChanged(intent.getStringExtra("CallID"), intent.getStringExtra("State"));
+                callStateChanged((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("CallID"), intent.getStringExtra("State"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.CONF_CREATED)) {
-                confCreated(intent.getStringExtra("confID"));
+                confCreated((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("confID"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.CONF_REMOVED)) {
-                confRemoved(intent.getStringExtra("confID"));
+                confRemoved((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("confID"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.CONF_CHANGED)) {
-                confChanged(intent.getStringExtra("confID"), intent.getStringExtra("state"));
+                confChanged((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("confID"), intent.getStringExtra("state"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.RECORD_STATE_CHANGED)) {
-                recordingChanged(intent.getStringExtra("callID"), intent.getStringExtra("file"));
+                recordingChanged((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("callID"), intent.getStringExtra("file"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.ZRTP_OFF)) {
-                secureZrtpOff(intent.getStringExtra("callID"));
+                secureZrtpOff((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("callID"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.ZRTP_ON)) {
-                secureZrtpOn(intent.getStringExtra("callID"));
+                secureZrtpOn((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("callID"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.DISPLAY_SAS)) {
-                displaySAS(intent.getStringExtra("callID"), intent.getStringExtra("SAS"), intent.getBooleanExtra("verified", false));
+                displaySAS((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("callID"));
             } else {
                 Log.e(TAG, "Unknown action: " + intent.getAction());
             }
diff --git a/src/org/sflphone/fragments/ConferenceDFragment.java b/src/org/sflphone/fragments/ConferenceDFragment.java
index c7ebb17..a889ccd 100644
--- a/src/org/sflphone/fragments/ConferenceDFragment.java
+++ b/src/org/sflphone/fragments/ConferenceDFragment.java
@@ -75,7 +75,7 @@
 
         
 
-        final AlertDialog a = new AlertDialog.Builder(getActivity()).setView(rootView).setTitle("Transfer " + call_selected.getParticipants().get(0).getContact())
+        final AlertDialog a = new AlertDialog.Builder(getActivity()).setView(rootView).setTitle("Transfer " + call_selected.getParticipants().get(0).getmContact())
                 .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
                     public void onClick(DialogInterface dialog, int whichButton) {
 
@@ -136,7 +136,7 @@
             }
 
             if(calls.get(position).getParticipants().size() == 1){
-                tv.setText(calls.get(position).getParticipants().get(0).getContact().getmDisplayName());
+                tv.setText(calls.get(position).getParticipants().get(0).getmContact().getmDisplayName());
             } else {
                 tv.setText("Conference with "+ calls.get(position).getParticipants().size() + " participants");
             }
diff --git a/src/org/sflphone/fragments/DetailsHistoryEntryFragment.java b/src/org/sflphone/fragments/DetailsHistoryEntryFragment.java
index 06600d3..ded02b2 100644
--- a/src/org/sflphone/fragments/DetailsHistoryEntryFragment.java
+++ b/src/org/sflphone/fragments/DetailsHistoryEntryFragment.java
@@ -54,6 +54,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.NavigableMap;
+import java.util.Random;
 
 public class DetailsHistoryEntryFragment extends Fragment {
 
@@ -135,23 +136,20 @@
             @Override
             public void onClick(View v) {
                 try {
-                    SipCall.SipCallBuilder callBuilder = SipCall.SipCallBuilder.getInstance();
-
                     HashMap<String, String> details = (HashMap<String, String>) mCallbacks.getService().getAccountDetails(toDisplay.getAccountID());
                     ArrayList<HashMap<String, String>> creds = (ArrayList<HashMap<String, String>>) mCallbacks.getService().getCredentials(toDisplay.getAccountID());
+                    Bundle args = new Bundle();
+                    args.putString(SipCall.ID, Integer.toString(Math.abs(new Random().nextInt())));
+                    args.putParcelable(SipCall.ACCOUNT, new Account(toDisplay.getAccountID(), details, creds));
+                    args.putInt(SipCall.STATE, SipCall.state.CALL_STATE_RINGING);
+                    args.putInt(SipCall.TYPE, SipCall.direction.CALL_TYPE_OUTGOING);
+                    args.putParcelable(SipCall.CONTACT, toDisplay.getContact());
 
-                    callBuilder.startCallCreation().setAccount(new Account(toDisplay.getAccountID(), details, creds))
-                            .setCallType(SipCall.direction.CALL_TYPE_OUTGOING);
-                    callBuilder.setContact(toDisplay.getContact());
-
-                    mCallbacks.onCall(callBuilder.build());
+                    mCallbacks.onCall(new SipCall(args));
 
                 } catch (RemoteException e) {
                     // TODO Bloc catch généré automatiquement
                     e.printStackTrace();
-                } catch (InvalidObjectException e) {
-                    // TODO Bloc catch généré automatiquement
-                    e.printStackTrace();
                 }
             }
         });
diff --git a/src/org/sflphone/fragments/IMFragment.java b/src/org/sflphone/fragments/IMFragment.java
index f9e63b8..0c09181 100644
--- a/src/org/sflphone/fragments/IMFragment.java
+++ b/src/org/sflphone/fragments/IMFragment.java
@@ -68,11 +68,13 @@
     }
 
     @Override
-    public void incomingText(String ID, String from, String msg) {
-        if (mCallbacks.getDisplayedConference().getId().contentEquals(ID)) {
+    public void incomingText(Conference updated, String ID, String from, String msg) {
+        mCallbacks.updateDisplayedConference(updated);
+        if(updated.equals(mCallbacks.getDisplayedConference())){
             SipMessage sipMsg = new SipMessage(true, msg);
             putMessage(sipMsg);
         }
+
     }
 
 
@@ -96,6 +98,11 @@
             return false;
         }
 
+        @Override
+        public void updateDisplayedConference(Conference c) {
+
+        }
+
     };
 
     /**
@@ -107,6 +114,8 @@
         public Conference getDisplayedConference();
 
         public boolean sendIM(SipMessage msg);
+
+        public void updateDisplayedConference(Conference c);
     }
 
     @Override
diff --git a/src/org/sflphone/fragments/TransferDFragment.java b/src/org/sflphone/fragments/TransferDFragment.java
index 6c8bee9..b595241 100644
--- a/src/org/sflphone/fragments/TransferDFragment.java
+++ b/src/org/sflphone/fragments/TransferDFragment.java
@@ -124,7 +124,7 @@
         mEditText.setAdapter(autoCompleteAdapter);
 
         final AlertDialog a = new AlertDialog.Builder(getActivity()).setView(rootView)
-                .setTitle("Transfer " + call_selected.getContact().getmDisplayName())
+                .setTitle("Transfer " + call_selected.getmContact().getmDisplayName())
                 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int whichButton) {
@@ -281,7 +281,7 @@
                 tv = (TextView) mInflater.inflate(android.R.layout.simple_dropdown_item_1line, parent, false);
             }
 
-            tv.setText(calls.get(position).getParticipants().get(0).getContact().getmDisplayName());
+            tv.setText(calls.get(position).getParticipants().get(0).getmContact().getmDisplayName());
             return tv;
         }
 
diff --git a/src/org/sflphone/history/HistoryCall.java b/src/org/sflphone/history/HistoryCall.java
index 972a1c4..52d81a0 100644
--- a/src/org/sflphone/history/HistoryCall.java
+++ b/src/org/sflphone/history/HistoryCall.java
@@ -36,12 +36,10 @@
 import android.os.Parcelable;
 import com.j256.ormlite.field.DatabaseField;
 import org.sflphone.model.SipCall;
-import org.sflphone.service.ServiceConstants;
 
 import java.sql.Timestamp;
 import java.text.SimpleDateFormat;
 import java.util.Date;
-import java.util.HashMap;
 import java.util.Locale;
 import java.util.TimeZone;
 
@@ -78,11 +76,11 @@
         call_start = call.getTimestampStart_();
         call_end = call.getTimestampEnd_();
         accountID = call.getAccount().getAccountID();
-        number = call.getContact().getPhones().get(0).getNumber();
+        number = call.getmContact().getPhones().get(0).getNumber();
         missed = call.isRinging() && call.isIncoming();
         direction = call.getCallType();
         recordPath = call.getRecordPath();
-        contactID = call.getContact().getId();
+        contactID = call.getmContact().getId();
         callID = call.getCallId();
     }
 
diff --git a/src/org/sflphone/history/HistoryManager.java b/src/org/sflphone/history/HistoryManager.java
index bc90274..bb6dd27 100644
--- a/src/org/sflphone/history/HistoryManager.java
+++ b/src/org/sflphone/history/HistoryManager.java
@@ -53,7 +53,7 @@
 
     public boolean insertNewEntry(Conference toInsert){
         for (SipCall call : toInsert.getParticipants()) {
-            call.setTimestampEnd_(System.currentTimeMillis() * 1000);
+            call.setTimestampEnd_(System.currentTimeMillis());
             HistoryCall persistent = new HistoryCall(call);
             try {
                 getHelper().getHistoryDao().create(persistent);
diff --git a/src/org/sflphone/interfaces/CallInterface.java b/src/org/sflphone/interfaces/CallInterface.java
index 3a3fd61..3683da0 100644
--- a/src/org/sflphone/interfaces/CallInterface.java
+++ b/src/org/sflphone/interfaces/CallInterface.java
@@ -31,25 +31,27 @@
 
 package org.sflphone.interfaces;
 
+import org.sflphone.model.Conference;
+
 public interface CallInterface {
 
-    public void callStateChanged(String callID, String state);
+    public void callStateChanged(Conference c, String callID, String state);
 
-    public void incomingText(String ID, String from, String msg);
+    public void incomingText(Conference c, String ID, String from, String msg);
 
-    public void confCreated(String id);
+    public void confCreated(Conference c, String id);
 
-    public void confRemoved(String id);
+    public void confRemoved(Conference c, String id);
 
-    public void confChanged(String id, String state);
+    public void confChanged(Conference c, String id, String state);
 
-    public void recordingChanged(String callID, String filename);
+    public void recordingChanged(Conference c, String callID, String filename);
 
-    public void secureZrtpOn(String id);
+    public void secureZrtpOn(Conference c, String id);
 
-    public void secureZrtpOff(String id);
+    public void secureZrtpOff(Conference c, String id);
 
-    public void displaySAS(String callID, String SAS, boolean verified);
+    public void displaySAS(Conference c, String securedCallID);
 
 
 }
diff --git a/src/org/sflphone/model/BubbleContact.java b/src/org/sflphone/model/BubbleContact.java
index 8e2f0d3..3ad500d 100644
--- a/src/org/sflphone/model/BubbleContact.java
+++ b/src/org/sflphone/model/BubbleContact.java
@@ -57,7 +57,7 @@
     }
 
     public BubbleContact(Context context, SipCall call, float x, float y, float size) {
-        super(context, call.getContact(), x, y, size);
+        super(context, call.getmContact(), x, y, size);
         associated_call = call;
 
         buttonMsg = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.ic_action_chat);
@@ -379,7 +379,7 @@
 
     @Override
     public String getName() {
-        return associated_call.getContact().getmDisplayName();
+        return associated_call.getmContact().getmDisplayName();
     }
 
     @Override
diff --git a/src/org/sflphone/model/BubblesView.java b/src/org/sflphone/model/BubblesView.java
index 0ed2e20..ca44ee3 100644
--- a/src/org/sflphone/model/BubblesView.java
+++ b/src/org/sflphone/model/BubblesView.java
@@ -302,7 +302,7 @@
                             canvas.drawBitmap(first_plan.getDrawerBitmap(), null, first_plan.getDrawerBounds(), null);

                         }

                         canvas.drawBitmap(first_plan.getBitmap(), null, first_plan.getBounds(), null);

-                        // canvas.drawText(first_plan.associated_call.getContact().getmDisplayName(), first_plan.getPosX(),

+                        // canvas.drawText(first_plan.associated_call.getmContact().getmDisplayName(), first_plan.getPosX(),

                         // (float) (first_plan.getPosY() - first_plan.getRetractedRadius() * 1.2 * density), getNamePaint(first_plan));

 

                     }

diff --git a/src/org/sflphone/model/SipCall.java b/src/org/sflphone/model/SipCall.java
index 1a9c297..10548ce 100644
--- a/src/org/sflphone/model/SipCall.java
+++ b/src/org/sflphone/model/SipCall.java
@@ -31,20 +31,24 @@
  */
 package org.sflphone.model;
 
-import java.io.InvalidObjectException;
-import java.util.Random;
-
+import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
 
 public class SipCall implements Parcelable {
 
+    public static String ID = "id";
+    public static String ACCOUNT = "account";
+    public static String CONTACT = "contcat";
+    public static String TYPE = "type";
+    public static String STATE = "state";
+
     private static final String TAG = SipCall.class.getSimpleName();
 
     private String mCallID = "";
     private Account mAccount = null;
-    private CallContact contact = null;
+    private CallContact mContact = null;
     private boolean isRecording = false;
     private long timestampStart_ = 0;
     private long timestampEnd_ = 0;
@@ -52,42 +56,34 @@
     private int mCallType;
     private int mCallState = state.CALL_STATE_NONE;
 
-    private boolean isSecured;
-    private String SAS;
-    private boolean confirmedSAS;
-
 
     public boolean isSecured() {
-        return isSecured;
+        return false;
     }
-
     /**
      * *********************
      * Construtors
      * *********************
      */
 
-    private SipCall(Parcel in) {
+    protected SipCall(Parcel in) {
 
         mCallID = in.readString();
         mAccount = in.readParcelable(Account.class.getClassLoader());
-        contact = in.readParcelable(CallContact.class.getClassLoader());
+        mContact = in.readParcelable(CallContact.class.getClassLoader());
         isRecording = in.readByte() == 1;
         mCallType = in.readInt();
         mCallState = in.readInt();
         timestampStart_ = in.readLong();
         timestampEnd_ = in.readLong();
-        SAS = in.readString();
-        confirmedSAS = in.readByte() == 1;
-        isSecured = in.readByte() == 1;
     }
 
-    private SipCall(String id, Account account, int call_type, int call_state, CallContact c) {
-        mCallID = id;
-        mAccount = account;
-        mCallType = call_type;
-        mCallState = call_state;
-        contact = c;
+    public SipCall(Bundle args) {
+        mCallID = args.getString(ID);
+        mAccount = args.getParcelable(ACCOUNT);
+        mCallType = args.getInt(TYPE);
+        mCallState = args.getInt(STATE);
+        mContact = args.getParcelable(CONTACT);
     }
 
     public long getTimestampEnd_() {
@@ -102,10 +98,17 @@
         return mCallType;
     }
 
-    public void setSecured(boolean secured) {
-        isSecured = secured;
+    public Bundle getBundle() {
+        Bundle args = new Bundle();
+        args.putString(SipCall.ID, mCallID);
+        args.putParcelable(SipCall.ACCOUNT, mAccount);
+        args.putInt(SipCall.STATE, mCallState);
+        args.putInt(SipCall.TYPE, mCallType);
+        args.putParcelable(SipCall.CONTACT, mContact);
+        return args;
     }
 
+
     public interface direction {
         public static final int CALL_TYPE_INCOMING = 1;
         public static final int CALL_TYPE_OUTGOING = 2;
@@ -133,15 +136,12 @@
         out.writeString(mCallID);
         out.writeParcelable(mAccount, 0);
 
-        out.writeParcelable(contact, 0);
+        out.writeParcelable(mContact, 0);
         out.writeByte((byte) (isRecording ? 1 : 0));
         out.writeInt(mCallType);
         out.writeInt(mCallState);
         out.writeLong(timestampStart_);
         out.writeLong(timestampEnd_);
-        out.writeString(SAS);
-        out.writeByte((byte) (confirmedSAS ? 1 : 0));
-        out.writeByte((byte) (isSecured ? 1 : 0));
     }
 
     public static final Parcelable.Creator<SipCall> CREATOR = new Parcelable.Creator<SipCall>() {
@@ -197,12 +197,12 @@
         mCallState = callState;
     }
 
-    public CallContact getContact() {
-        return contact;
+    public CallContact getmContact() {
+        return mContact;
     }
 
-    public void setContact(CallContact contacts) {
-        contact = contacts;
+    public void setmContact(CallContact contacts) {
+        mContact = contacts;
     }
 
     public String getCallStateString() {
@@ -246,59 +246,6 @@
         this.isRecording = isRecording;
     }
 
-    public static class SipCallBuilder {
-
-        private String bCallID = "";
-        private Account bAccount = null;
-        private CallContact bContact = null;
-
-        private int bCallType;
-        private int bCallState = state.CALL_STATE_NONE;
-
-        public SipCallBuilder setCallType(int bCallType) {
-            this.bCallType = bCallType;
-            return this;
-        }
-
-        public SipCallBuilder setCallState(int state) {
-            this.bCallState = state;
-            return this;
-        }
-
-        public SipCallBuilder startCallCreation(String id) {
-            bCallID = id;
-            bCallType = direction.CALL_TYPE_INCOMING;
-            return this;
-        }
-
-        public SipCallBuilder startCallCreation() {
-            Random random = new Random();
-            bCallID = Integer.toString(Math.abs(random.nextInt()));
-            return this;
-        }
-
-        public SipCallBuilder setAccount(Account a) {
-            bAccount = a;
-            return this;
-        }
-
-        public SipCallBuilder setContact(CallContact c) {
-            bContact = c;
-            return this;
-        }
-
-        public SipCall build() throws InvalidObjectException {
-            if (bCallID.contentEquals("") || bAccount == null || bContact == null) {
-                throw new InvalidObjectException("SipCallBuilder's parameters missing");
-            }
-            return new SipCall(bCallID, bAccount, bCallType, bCallState, bContact);
-        }
-
-        public static SipCallBuilder getInstance() {
-            return new SipCallBuilder();
-        }
-    }
-
     public void printCallInfo() {
         Log.i(TAG, "CallInfo: CallID: " + mCallID);
         Log.i(TAG, "          AccountID: " + mAccount.getAccountID());
@@ -375,19 +322,5 @@
         return mCallState == state.CALL_STATE_CURRENT;
     }
 
-    public boolean isConfirmedSAS() {
-        return confirmedSAS;
-    }
 
-    public void setConfirmedSAS(boolean confirmedSAS) {
-        this.confirmedSAS = confirmedSAS;
-    }
-
-    public String getSAS() {
-        return SAS;
-    }
-
-    public void setSAS(String SAS) {
-        this.SAS = SAS;
-    }
 }
diff --git a/src/org/sflphone/service/CallManagerCallBack.java b/src/org/sflphone/service/CallManagerCallBack.java
index 97e1fab..45d709f 100644
--- a/src/org/sflphone/service/CallManagerCallBack.java
+++ b/src/org/sflphone/service/CallManagerCallBack.java
@@ -3,11 +3,13 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.util.Log;
+import org.sflphone.account.AccountDetailSrtp;
 import org.sflphone.client.CallActivity;
 import org.sflphone.model.*;
 import org.sflphone.utils.SwigNativeConverter;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 
@@ -39,128 +41,102 @@
     public void on_call_state_changed(String callID, String newState) {
         Log.d(TAG, "on_call_state_changed : (" + callID + ", " + newState + ")");
 
+        Conference toUpdate = findConference(callID);
+
+        if (toUpdate == null) {
+            return;
+        }
+
         Intent intent = new Intent(CALL_STATE_CHANGED);
         intent.putExtra("CallID", callID);
         intent.putExtra("State", newState);
+
         if (newState.equals("RINGING")) {
-            try {
-                mService.getConferences().get(callID).setCallState(callID, SipCall.state.CALL_STATE_RINGING);
-            } catch (NullPointerException e) {
-                if (mService.getConferences() == null) {
-                    return;
-                }
-                if (mService.getConferences().get(callID) == null) {
-                    Log.e(TAG, "call for " + callID + " is null");
-                    return;
-                }
-            }
-
+            toUpdate.setCallState(callID, SipCall.state.CALL_STATE_RINGING);
         } else if (newState.equals("CURRENT")) {
-            if (mService.getConferences().get(callID) != null) {
-                mService.getConferences().get(callID).setCallState(callID, SipCall.state.CALL_STATE_CURRENT);
-            } else {
-                // Check if call is in a conference
-                Iterator<Map.Entry<String, Conference>> it = mService.getConferences().entrySet().iterator();
-                while (it.hasNext()) {
-                    Conference tmp = it.next().getValue();
-                    for (SipCall c : tmp.getParticipants()) {
-                        if (c.getCallId().contentEquals(callID))
-                            c.setCallState(SipCall.state.CALL_STATE_CURRENT);
-                    }
-                }
+            if(toUpdate.isRinging()){
+                toUpdate.getCallById(callID).setTimestampStart_(System.currentTimeMillis());
             }
-
+            toUpdate.setCallState(callID, SipCall.state.CALL_STATE_CURRENT);
         } else if (newState.equals("HUNGUP")) {
             Log.d(TAG, "Hanging up " + callID);
-            if (mService.getConferences().get(callID) != null) {
-                if (mService.getConferences().get(callID).isRinging()
-                        && mService.getConferences().get(callID).isIncoming())
+            SipCall call = toUpdate.getCallById(callID);
+            if (!toUpdate.hasMultipleParticipants()) {
+                if (toUpdate.isRinging() && toUpdate.isIncoming()) {
                     mService.mNotificationManager.publishMissedCallNotification(mService.getConferences().get(callID));
-
-                mService.mHistoryManager.insertNewEntry(mService.getConferences().get(callID));
-                mService.getConferences().remove(callID);
-            } else {
-
-                Iterator<Map.Entry<String, Conference>> it = mService.getConferences().entrySet().iterator();
-                while (it.hasNext()) {
-                    Conference tmp = it.next().getValue();
-                    for (SipCall c : tmp.getParticipants()) {
-                        if (c.getCallId().contentEquals(callID)) {
-                            mService.mHistoryManager.insertNewEntry(c);
-                            mService.getConferences().get(tmp.getId()).removeParticipant(c);
-                            break;
-                        }
-                    }
                 }
+                toUpdate.setCallState(callID, SipCall.state.CALL_STATE_HUNGUP);
+                mService.mHistoryManager.insertNewEntry(toUpdate);
+                mService.getConferences().remove(toUpdate.getId());
+                Log.e(TAG, "Conferences :"+ mService.getConferences().size());
+                Log.e(TAG, "toUpdate.getParticipants() :"+ toUpdate.getParticipants().size());
+            } else {
+                toUpdate.setCallState(callID, SipCall.state.CALL_STATE_HUNGUP);
+                mService.mHistoryManager.insertNewEntry(call);
             }
-
         } else if (newState.equals("BUSY")) {
-            mService.getConferences().remove(callID);
+            toUpdate.setCallState(callID, SipCall.state.CALL_STATE_BUSY);
+            mService.getConferences().remove(toUpdate.getId());
         } else if (newState.equals("FAILURE")) {
-            mService.getConferences().remove(callID);
+            toUpdate.setCallState(callID, SipCall.state.CALL_STATE_FAILURE);
+            mService.getConferences().remove(toUpdate.getId());
         } else if (newState.equals("HOLD")) {
-            if (mService.getConferences().get(callID) != null) {
-                mService.getConferences().get(callID).setCallState(callID, SipCall.state.CALL_STATE_HOLD);
-            } else {
-                // Check if call is in a conference
-                Iterator<Map.Entry<String, Conference>> it = mService.getConferences().entrySet().iterator();
-                while (it.hasNext()) {
-                    Conference tmp = it.next().getValue();
-                    for (SipCall c : tmp.getParticipants()) {
-                        if (c.getCallId().contentEquals(callID))
-                            c.setCallState(SipCall.state.CALL_STATE_HOLD);
-                    }
-                }
-            }
+            toUpdate.setCallState(callID, SipCall.state.CALL_STATE_HOLD);
         } else if (newState.equals("UNHOLD")) {
+            toUpdate.setCallState(callID, SipCall.state.CALL_STATE_CURRENT);
+        }
+        intent.putExtra("conference", toUpdate);
+        mService.sendBroadcast(intent);
+    }
 
-            if (mService.getConferences().get(callID) != null) {
-                mService.getConferences().get(callID).setCallState(callID, SipCall.state.CALL_STATE_CURRENT);
-            } else {
-                // Check if call is in a conference
-                Iterator<Map.Entry<String, Conference>> it = mService.getConferences().entrySet().iterator();
-                while (it.hasNext()) {
-                    Conference tmp = it.next().getValue();
-                    for (SipCall c : tmp.getParticipants()) {
-                        if (c.getCallId().contentEquals(callID))
-                            c.setCallState(SipCall.state.CALL_STATE_CURRENT);
+    private Conference findConference(String callID) {
+        Conference result = null;
+        if (mService.getConferences().get(callID) != null) {
+            result = mService.getConferences().get(callID);
+        } else {
+            Iterator<Map.Entry<String, Conference>> it = mService.getConferences().entrySet().iterator();
+            while (it.hasNext()) {
+                Conference tmp = it.next().getValue();
+                for (SipCall c : tmp.getParticipants()) {
+                    if (c.getCallId().contentEquals(callID)) {
+                        result = tmp;
                     }
                 }
             }
-        } else {
-            mService.getConferences().get(callID).setCallState(callID, SipCall.state.CALL_STATE_NONE);
         }
-        mService.sendBroadcast(intent);
+        return result;
     }
 
     @Override
     public void on_incoming_call(String accountID, String callID, String from) {
         Log.d(TAG, "on_incoming_call(" + accountID + ", " + callID + ", " + from + ")");
 
-        SipCall.SipCallBuilder callBuilder = SipCall.SipCallBuilder.getInstance();
         try {
             StringMap details = mService.getConfigurationManagerJNI().getAccountDetails(accountID);
             VectMap credentials = mService.getConfigurationManagerJNI().getCredentials(accountID);
             Account acc = new Account(accountID, SwigNativeConverter.convertAccountToNative(details), SwigNativeConverter.convertCredentialsToNative(credentials));
-            callBuilder.startCallCreation(callID).setAccount(acc).setCallState(SipCall.state.CALL_STATE_RINGING)
-                    .setCallType(SipCall.direction.CALL_TYPE_INCOMING);
-            callBuilder.setContact(CallContact.ContactBuilder.buildUnknownContact(from));
+
+            Bundle args = new Bundle();
+            args.putString(SipCall.ID, callID);
+            args.putParcelable(SipCall.ACCOUNT, acc);
+            args.putInt(SipCall.STATE, SipCall.state.CALL_STATE_RINGING);
+            args.putInt(SipCall.TYPE, SipCall.direction.CALL_TYPE_INCOMING);
+
+            CallContact unknow = CallContact.ContactBuilder.buildUnknownContact(from);
+            args.putParcelable(SipCall.CONTACT, unknow);
 
             Intent toSend = new Intent(CallManagerCallBack.INCOMING_CALL);
             toSend.setClass(mService, CallActivity.class);
             toSend.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 
-            SipCall newCall = callBuilder.build();
-            StringMap callDetails = mService.getCallManagerJNI().getCallDetails(callID);
+            SipCall newCall = new SipCall(args);
 
-            newCall.setTimestampStart_(Long.parseLong(callDetails.get(ServiceConstants.call.TIMESTAMP_START)));
+            newCall.setTimestampStart_(System.currentTimeMillis());
 
             Conference toAdd = new Conference(newCall);
-
             mService.getConferences().put(toAdd.getId(), toAdd);
 
             Bundle bundle = new Bundle();
-
             bundle.putParcelable("conference", toAdd);
             toSend.putExtra("resuming", false);
             toSend.putExtras(bundle);
@@ -202,6 +178,7 @@
                 }
             }
         }
+        intent.putExtra("conference", created);
         intent.putExtra("confID", created.getId());
         mService.getConferences().put(created.getId(), created);
         mService.sendBroadcast(intent);
@@ -217,6 +194,7 @@
 
         if (mService.getConferences().get(ID) != null) {
             mService.getConferences().get(ID).addSipMessage(new SipMessage(true, msg));
+            intent.putExtra("conference", mService.getConferences().get(ID));
         } else {
             Iterator<Map.Entry<String, Conference>> it = mService.getConferences().entrySet().iterator();
             while (it.hasNext()) {
@@ -224,12 +202,12 @@
                 for (SipCall c : tmp.getParticipants()) {
                     if (c.getCallId().contentEquals(ID)) {
                         mService.getConferences().get(tmp.getId()).addSipMessage(new SipMessage(true, msg));
+                        intent.putExtra("conference", tmp);
                     }
                 }
             }
 
         }
-
         mService.sendBroadcast(intent);
     }
 
@@ -243,6 +221,7 @@
         for (SipCall call : toReInsert.getParticipants()) {
             mService.getConferences().put(call.getCallId(), new Conference(call));
         }
+        intent.putExtra("conference", mService.getConferences().get(confID));
         mService.getConferences().remove(confID);
         mService.sendBroadcast(intent);
 
@@ -254,12 +233,13 @@
         Intent intent = new Intent(CONF_CHANGED);
         intent.putExtra("confID", confID);
         intent.putExtra("State", state);
-        mService.getConferences().get(confID).setCallState(confID, state);
+
 
         Log.i(TAG, "Received:" + intent.getAction());
         Log.i(TAG, "State:" + state);
 
         Conference toModify = mService.getConferences().get(confID);
+        toModify.setCallState(confID, state);
 
         ArrayList<String> newParticipants = SwigNativeConverter.convertSwigToNative(mService.getCallManagerJNI().getParticipantList(intent.getStringExtra("confID")));
 
@@ -275,6 +255,7 @@
             for (SipCall participant : toModify.getParticipants()) {
                 if (!newParticipants.contains(participant.getCallId())) {
                     mService.detachCallFromConference(toModify.getId(), participant);
+                    break;
                 }
             }
         }
@@ -304,9 +285,17 @@
     public void on_secure_zrtp_on(String callID, String cipher) {
         Log.i(TAG, "on_secure_zrtp_on");
         SipCall call = mService.getCallById(callID);
-        call.setSecured(true);
+        Bundle secureArgs = new Bundle();
+        HashMap<String, String> details = SwigNativeConverter.convertAccountToNative(mService.getConfigurationManagerJNI().getAccountDetails(call.getAccount().getAccountID()));
+        secureArgs.putBoolean(SecureSipCall.DISPLAY_SAS, details.get(AccountDetailSrtp.CONFIG_ZRTP_DISPLAY_SAS).contentEquals("true"));
+        secureArgs.putBoolean(SecureSipCall.DISPLAY_SAS_ONCE, details.get(AccountDetailSrtp.CONFIG_ZRTP_DISPLAY_SAS_ONCE).contentEquals("true"));
+        secureArgs.putBoolean(SecureSipCall.DISPLAY_WARNING_ZRTP_NOT_SUPPORTED, details.get(AccountDetailSrtp.CONFIG_ZRTP_NOT_SUPP_WARNING).contentEquals("true"));
+        SecureSipCall replace = new SecureSipCall(call, secureArgs);
+        mService.replaceCall(replace);
+
         Intent intent = new Intent(ZRTP_ON);
-        intent.putExtra("callID", callID);
+        intent.putExtra("callID", replace.getCallId());
+        intent.putExtra("conference", findConference(callID));
         mService.sendBroadcast(intent);
     }
 
@@ -315,10 +304,12 @@
         Log.i(TAG, "on_secure_zrtp_off");
         SipCall call = mService.getCallById(callID);
 
-        if (call != null) {
-            call.setSecured(false);
+        if (call != null && call instanceof SecureSipCall) {
+            SipCall replace = new SipCall(call.getBundle());
+            mService.replaceCall(replace);
             Intent intent = new Intent(ZRTP_OFF);
             intent.putExtra("callID", callID);
+            intent.putExtra("conference", findConference(callID));
             mService.sendBroadcast(intent);
         }
 
@@ -328,13 +319,16 @@
     public void on_show_sas(String callID, String sas, boolean verified) {
         Log.i(TAG, "on_show_sas:" + sas);
         Log.i(TAG, "SAS Verified:" + verified);
-        SipCall call = mService.getCallById(callID);
-        call.setSAS(sas);
-        call.setConfirmedSAS(verified);
+
         Intent intent = new Intent(DISPLAY_SAS);
         intent.putExtra("callID", callID);
         intent.putExtra("SAS", sas);
         intent.putExtra("verified", verified);
+        SecureSipCall call = (SecureSipCall) mService.getCallById(callID);
+        intent.putExtra("conference", findConference(callID));
+
+        call.setSAS(sas);
+        call.setConfirmedSAS(verified);
 
         mService.sendBroadcast(intent);
     }
@@ -343,8 +337,6 @@
     public void on_zrtp_not_supported(String callID) {
         Log.i(TAG, "on_zrtp_not_supported");
         Intent intent = new Intent(ZRTP_NOT_SUPPORTED);
-        SipCall call = mService.getCallById(callID);
-        call.setSecured(false);
         intent.putExtra("callID", callID);
         mService.sendBroadcast(intent);
     }
@@ -353,8 +345,6 @@
     public void on_zrtp_negociation_failed(String callID, String reason, String severity) {
         Log.i(TAG, "on_zrtp_negociation_failed");
         Intent intent = new Intent(ZRTP_NEGOTIATION_FAILED);
-        SipCall call = mService.getCallById(callID);
-        call.setSecured(false);
         intent.putExtra("callID", callID);
         intent.putExtra("reason", reason);
         intent.putExtra("severity", severity);
diff --git a/src/org/sflphone/service/SipService.java b/src/org/sflphone/service/SipService.java
index a2ccf2a..258564b 100644
--- a/src/org/sflphone/service/SipService.java
+++ b/src/org/sflphone/service/SipService.java
@@ -32,10 +32,7 @@
 import java.util.Map.Entry;
 
 import org.sflphone.history.HistoryManager;
-import org.sflphone.model.Codec;
-import org.sflphone.model.Conference;
-import org.sflphone.model.SipCall;
-import org.sflphone.model.SipMessage;
+import org.sflphone.model.*;
 import org.sflphone.utils.MediaManager;
 import org.sflphone.utils.SipNotifications;
 import org.sflphone.utils.SwigNativeConverter;
@@ -201,6 +198,30 @@
         return null;
     }
 
+    /*
+    *
+    * Used when we need to transform a SipCall in a SecureSipCall or vice versa
+    *
+    * */
+    public void replaceCall(SipCall replace) {
+        if (getConferences().get(replace.getCallId()) != null) {
+            getConferences().get(replace.getCallId()).removeParticipant(replace);
+            getConferences().get(replace.getCallId()).addParticipant(replace);
+        } else {
+            // Check if call is in a conference
+            Iterator<Map.Entry<String, Conference>> it = getConferences().entrySet().iterator();
+            while (it.hasNext()) {
+                Conference tmp = it.next().getValue();
+                SipCall c = tmp.getCallById(replace.getCallId());
+                if(c != null){
+                    tmp.removeParticipant(c);
+                    tmp.addParticipant(replace);
+                    return;
+                }
+            }
+        }
+    }
+
     // Executes immediate tasks in a single executorThread.
     public static class SipServiceExecutor extends Handler {
 
@@ -355,18 +376,15 @@
 
         @Override
         public void placeCall(final SipCall call) {
+
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException {
                     Log.i(TAG, "SipService.placeCall() thread running...");
-                    callManagerJNI.placeCall(call.getAccount().getAccountID(), call.getCallId(), call.getContact().getPhones().get(0).getNumber());
-
-                    HashMap<String, String> details = SwigNativeConverter.convertCallDetailsToNative(callManagerJNI.getCallDetails(call.getCallId()));
-                    // watchout timestamp stored by sflphone is in seconds
-                    call.setTimestampStart_(Long.parseLong(details.get(ServiceConstants.call.TIMESTAMP_START)));
                     Conference toAdd = new Conference(call);
                     mConferences.put(toAdd.getId(), toAdd);
                     mMediaManager.obtainAudioFocus(false);
+                    callManagerJNI.placeCall(call.getAccount().getAccountID(), call.getCallId(), call.getmContact().getPhones().get(0).getNumber());
                 }
             });
         }
diff --git a/src/org/sflphone/utils/SipNotifications.java b/src/org/sflphone/utils/SipNotifications.java
index 47961cc..a77f9c5 100644
--- a/src/org/sflphone/utils/SipNotifications.java
+++ b/src/org/sflphone/utils/SipNotifications.java
@@ -158,7 +158,7 @@
         nb.setTicker(tickerText);
         nb.setWhen(when);
         nb.setContentTitle(context.getString(R.string.notif_missed_call_title));
-        nb.setContentText(context.getString(R.string.notif_missed_call_content, missedConf.getParticipants().get(0).getContact().getmDisplayName()));
+        nb.setContentText(context.getString(R.string.notif_missed_call_content, missedConf.getParticipants().get(0).getmContact().getmDisplayName()));
         Intent notificationIntent = new Intent(context, HomeActivity.class);
         notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
         PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);