service: refactor to DRingService

* Remove SipService
* DRingService is now just an async Java wrapper around dring
* Model is now built in LocalService

This presents the DRing interface through Android AIDL.
It allows lighter and more reactive UI code by reducing
the amount to async operations.
All the data modeling is also done in the same memory space,
improving coherence and reducing IPC overhead.

Tuleap: #102
Change-Id: I842f89ec109683722799837b301a3ffee2a9db75
diff --git a/ring-android/app/src/main/AndroidManifest.xml b/ring-android/app/src/main/AndroidManifest.xml
index 1741a9c..fa0667c 100644
--- a/ring-android/app/src/main/AndroidManifest.xml
+++ b/ring-android/app/src/main/AndroidManifest.xml
@@ -169,10 +169,10 @@
             </intent-filter>
         </service>
         <service
-            android:name=".service.SipService"
+            android:name=".service.DRingService"
             android:exported="false" >
             <intent-filter>
-                <action android:name=".service.SipService" />
+                <action android:name=".service.DRingService" />
             </intent-filter>
         </service>
     </application>
diff --git a/ring-android/app/src/main/java/cx/ring/client/AccountEditionActivity.java b/ring-android/app/src/main/java/cx/ring/client/AccountEditionActivity.java
index 8e5822b..d53f4cb 100644
--- a/ring-android/app/src/main/java/cx/ring/client/AccountEditionActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/client/AccountEditionActivity.java
@@ -53,7 +53,7 @@
 import cx.ring.fragments.NestedSettingsFragment;
 import cx.ring.fragments.SecurityAccountFragment;
 import cx.ring.model.account.Account;
-import cx.ring.service.ISipService;
+import cx.ring.service.IDRingService;
 import cx.ring.service.LocalService;
 import com.astuetz.PagerSlidingTabStrip;
 import java.util.ArrayList;
@@ -254,7 +254,7 @@
     }
 
     @Override
-    public ISipService getRemoteService() {
+    public IDRingService getRemoteService() {
         return service.getRemoteService();
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/client/AccountWizard.java b/ring-android/app/src/main/java/cx/ring/client/AccountWizard.java
index 931f47b..3ce8865 100644
--- a/ring-android/app/src/main/java/cx/ring/client/AccountWizard.java
+++ b/ring-android/app/src/main/java/cx/ring/client/AccountWizard.java
@@ -36,7 +36,7 @@
 import android.view.MenuItem;
 import cx.ring.R;
 import cx.ring.fragments.AccountCreationFragment;
-import cx.ring.service.ISipService;
+import cx.ring.service.IDRingService;
 import cx.ring.service.LocalService;
 
 import java.util.ArrayList;
@@ -158,7 +158,7 @@
     }
 
     @Override
-    public ISipService getRemoteService() {
+    public IDRingService getRemoteService() {
         return service.getRemoteService();
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/client/CallActivity.java b/ring-android/app/src/main/java/cx/ring/client/CallActivity.java
index 9c9a25c..8a2314b 100644
--- a/ring-android/app/src/main/java/cx/ring/client/CallActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/client/CallActivity.java
@@ -45,7 +45,7 @@
 import cx.ring.model.Conference;
 import cx.ring.model.SipCall;
 import cx.ring.model.account.AccountDetailBasic;
-import cx.ring.service.ISipService;
+import cx.ring.service.IDRingService;
 import cx.ring.service.LocalService;
 import cx.ring.utils.CallProximityManager;
 
@@ -167,15 +167,9 @@
 
             if (mDisplayedConference.getState().contentEquals("NONE")) {
                 SipCall call = mDisplayedConference.getParticipants().get(0);
-                try {
-                    String callId = service.getRemoteService().placeCall(call);
-                    if (callId == null || callId.isEmpty()) {
-                        CallActivity.this.terminateCall();
-                    }
-                    mDisplayedConference = service.getRemoteService().getConference(callId);
-                } catch (RemoteException e) {
-                    e.printStackTrace();
-                }
+                mDisplayedConference = service.placeCall(call);
+                if (mDisplayedConference == null)
+                    CallActivity.this.terminateCall();
             }
 
             setContentView(R.layout.activity_call_layout);
@@ -224,7 +218,7 @@
     }
 
     @Override
-    public ISipService getRemoteService() {
+    public IDRingService getRemoteService() {
         return service.getRemoteService();
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/client/DetailHistoryActivity.java b/ring-android/app/src/main/java/cx/ring/client/DetailHistoryActivity.java
index 89625f4..d61628a 100644
--- a/ring-android/app/src/main/java/cx/ring/client/DetailHistoryActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/client/DetailHistoryActivity.java
@@ -36,8 +36,8 @@
 import cx.ring.fragments.HistoryFragment;
 import cx.ring.model.Conference;
 import cx.ring.model.SipCall;
-import cx.ring.service.ISipService;
-import cx.ring.service.SipService;
+import cx.ring.service.DRingService;
+import cx.ring.service.IDRingService;
 
 import android.app.Activity;
 import android.app.Fragment;
@@ -54,7 +54,7 @@
 public class DetailHistoryActivity extends Activity implements DetailsHistoryEntryFragment.Callbacks {
 
     private boolean mBound = false;
-    private ISipService service;
+    private IDRingService service;
     private String TAG = DetailHistoryActivity.class.getSimpleName();
 
     @Override
@@ -62,7 +62,7 @@
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_holder);
 
-        Intent intent = new Intent(this, SipService.class);
+        Intent intent = new Intent(this, DRingService.class);
         bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
         getActionBar().setDisplayHomeAsUpEnabled(true);
     }
@@ -79,7 +79,7 @@
     }
 
     @Override
-    public ISipService getService() {
+    public IDRingService getService() {
         return service;
     }
 
@@ -97,7 +97,7 @@
 
         @Override
         public void onServiceConnected(ComponentName className, IBinder binder) {
-            service = ISipService.Stub.asInterface(binder);
+            service = IDRingService.Stub.asInterface(binder);
 
             FragmentTransaction ft = getFragmentManager().beginTransaction();
 
diff --git a/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java b/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java
index de2090d..88cf9b5 100644
--- a/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/client/HomeActivity.java
@@ -52,7 +52,7 @@
 import cx.ring.model.account.Account;
 import cx.ring.model.Conference;
 import cx.ring.model.SipCall;
-import cx.ring.service.ISipService;
+import cx.ring.service.IDRingService;
 import cx.ring.service.LocalService;
 
 import android.app.Fragment;
@@ -176,9 +176,6 @@
             ActivityCompat.requestPermissions(this, toRequest, LocalService.PERMISSIONS_REQUEST);
         } else if (!mBound) {
             Log.i(TAG, "onCreate: Binding service...");
-            /*Intent intent = new Intent(this, SipService.class);
-            startService(intent);
-            bindService(intent, mConnection, Context.BIND_AUTO_CREATE);*/
             Intent intent = new Intent(this, LocalService.class);
             startService(intent);
             bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
@@ -385,9 +382,6 @@
             unbindService(mConnection);
             mBound = false;
         }
-        //Log.i(TAG, "onDestroy: destroying service...");
-        //Intent sipServiceIntent = new Intent(this, SipService.class);
-        //stopService(sipServiceIntent);
     }
 
     public void launchCallActivity(SipCall infos) {
@@ -471,7 +465,7 @@
     }
 
     @Override
-    public ISipService getRemoteService() {
+    public IDRingService getRemoteService() {
         return service.getRemoteService();
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/client/NewConversationActivity.java b/ring-android/app/src/main/java/cx/ring/client/NewConversationActivity.java
index 3f6ef59..440da28 100644
--- a/ring-android/app/src/main/java/cx/ring/client/NewConversationActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/client/NewConversationActivity.java
@@ -19,7 +19,7 @@
 import cx.ring.R;
 import cx.ring.fragments.ContactListFragment;
 import cx.ring.model.CallContact;
-import cx.ring.service.ISipService;
+import cx.ring.service.IDRingService;
 import cx.ring.service.LocalService;
 
 public class NewConversationActivity extends Activity implements ContactListFragment.Callbacks {
@@ -132,7 +132,7 @@
     }
 
     @Override
-    public ISipService getRemoteService() {
+    public IDRingService getRemoteService() {
         return service.getRemoteService();
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/AccountCreationFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/AccountCreationFragment.java
index 2419666..07e0d53 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/AccountCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/AccountCreationFragment.java
@@ -25,7 +25,6 @@
 import cx.ring.R;
 import cx.ring.model.account.AccountDetailBasic;
 import cx.ring.client.HomeActivity;
-import cx.ring.service.ISipService;
 
 import android.app.Activity;
 import android.app.Fragment;
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/AudioManagementFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/AudioManagementFragment.java
index 4f90c00..d41cfe4 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/AudioManagementFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/AudioManagementFragment.java
@@ -41,7 +41,7 @@
 import cx.ring.model.account.AccountDetailAdvanced;
 import cx.ring.model.account.Account;
 import cx.ring.model.Codec;
-import cx.ring.service.ISipService;
+import cx.ring.service.IDRingService;
 import cx.ring.service.LocalService;
 import cx.ring.views.dragsortlv.DragSortListView;
 
@@ -76,7 +76,7 @@
     CodecAdapter listAdapter;
     private static final Callbacks sDummyCallbacks = new Callbacks() {
         @Override
-        public ISipService getRemoteService() {
+        public IDRingService getRemoteService() {
             return null;
         }
         @Override
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java
index 6b29850..252de35 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.java
@@ -32,9 +32,7 @@
 package cx.ring.fragments;
 
 import android.app.Activity;
-import android.app.FragmentManager;
 import android.net.Uri;
-import android.support.design.widget.FloatingActionButton;
 import android.support.v4.app.NotificationCompat;
 import android.support.v4.app.NotificationManagerCompat;
 import android.app.PendingIntent;
@@ -54,7 +52,6 @@
 import android.util.Log;
 import android.view.*;
 import android.view.View.OnClickListener;
-import android.view.inputmethod.InputMethodManager;
 import android.widget.*;
 import android.widget.CompoundButton.OnCheckedChangeListener;
 import cx.ring.R;
@@ -64,18 +61,16 @@
 import cx.ring.client.HomeActivity;
 import cx.ring.interfaces.CallInterface;
 
-import java.util.ArrayList;
 import java.util.Locale;
 import java.util.Random;
 
-import cx.ring.model.BubbleContact;
 import cx.ring.model.CallContact;
 import cx.ring.model.Conference;
 import cx.ring.model.SecureSipCall;
 import cx.ring.model.SipCall;
 import cx.ring.model.account.Account;
+import cx.ring.service.DRingService;
 import cx.ring.service.LocalService;
-import cx.ring.service.SipService;
 
 public class CallFragment extends CallableWrapperFragment implements CallInterface {
 
@@ -564,8 +559,8 @@
                         new Intent(getActivity(), CallActivity.class).putExtra("conference", getConference()), PendingIntent.FLAG_ONE_SHOT))
                 .addAction(R.drawable.ic_call_end_white_24dp, "Hangup",
                         PendingIntent.getService(getActivity(), new Random().nextInt(),
-                                new Intent(getActivity(), SipService.class)
-                                        .setAction(SipService.ACTION_CALL_END)
+                                new Intent(getActivity(), DRingService.class)
+                                        .setAction(DRingService.ACTION_CALL_END)
                                         .putExtra("conf", call.getCallId()),
                                 PendingIntent.FLAG_ONE_SHOT));
         Log.w("CallNotification ", "Updating " + getConference().notificationId + " for " + contact.getDisplayName());
@@ -720,14 +715,14 @@
                             new Intent(getActivity(), CallActivity.class).putExtra("conference", getConference()), PendingIntent.FLAG_ONE_SHOT))
                     .addAction(R.drawable.ic_action_accept, "Accept",
                             PendingIntent.getService(getActivity(), new Random().nextInt(),
-                                    new Intent(getActivity(), SipService.class)
-                                            .setAction(SipService.ACTION_CALL_ACCEPT)
+                                    new Intent(getActivity(), DRingService.class)
+                                            .setAction(DRingService.ACTION_CALL_ACCEPT)
                                             .putExtra("conf", call.getCallId()),
                                     PendingIntent.FLAG_ONE_SHOT))
                     .addAction(R.drawable.ic_call_end_white_24dp, "Refuse",
                             PendingIntent.getService(getActivity(), new Random().nextInt(),
-                                    new Intent(getActivity(), SipService.class)
-                                            .setAction(SipService.ACTION_CALL_REFUSE)
+                                    new Intent(getActivity(), DRingService.class)
+                                            .setAction(DRingService.ACTION_CALL_REFUSE)
                                             .putExtra("conf", call.getCallId()),
                                     PendingIntent.FLAG_ONE_SHOT));
             Log.w("CallNotification ", "Updating for incoming " + getConference().notificationId);
@@ -807,8 +802,8 @@
                         new Intent(getActivity(), CallActivity.class).putExtra("conference", getConference()), PendingIntent.FLAG_ONE_SHOT))
                 .addAction(R.drawable.ic_call_end_white_24dp, "Cancel",
                         PendingIntent.getService(getActivity(), new Random().nextInt(),
-                                new Intent(getActivity(), SipService.class)
-                                        .setAction(SipService.ACTION_CALL_END)
+                                new Intent(getActivity(), DRingService.class)
+                                        .setAction(DRingService.ACTION_CALL_END)
                                         .putExtra("conf", call.getCallId()),
                                 PendingIntent.FLAG_ONE_SHOT));
 
@@ -909,7 +904,7 @@
             initNormalStateDisplay();
         }
     }
-*/
+
     public void makeTransfer(BubbleContact contact) {
         FragmentManager fm = getFragmentManager();
         editName = TransferDFragment.newInstance();
@@ -925,7 +920,7 @@
         }
 
     }
-/*
+
     @Override
     public void surfaceCreated(SurfaceHolder holder) {
 
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/CallableWrapperFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/CallableWrapperFragment.java
index 3ea8dca..eba28d1 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/CallableWrapperFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/CallableWrapperFragment.java
@@ -142,27 +142,27 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (intent.getAction().contentEquals(CallManagerCallBack.INCOMING_TEXT)) {
-                incomingText((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("CallID"), intent.getStringExtra("From"), intent.getStringExtra("Msg"));
+                incomingText((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("call"), intent.getStringExtra("from"), intent.getStringExtra("txt"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.CALL_STATE_CHANGED)) {
-                callStateChanged((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("CallID"), intent.getStringExtra("State"));
+                callStateChanged((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("call"), intent.getStringExtra("state"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.CONF_CREATED)) {
-                confCreated((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("confID"));
+                confCreated((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("conference"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.CONF_REMOVED)) {
-                confRemoved((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("confID"));
+                confRemoved((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("conference"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.CONF_CHANGED)) {
-                confChanged((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("confID"), intent.getStringExtra("state"));
+                confChanged((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("conference"), intent.getStringExtra("state"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.RECORD_STATE_CHANGED)) {
-                recordingChanged((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("callID"), intent.getStringExtra("file"));
+                recordingChanged((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("call"), intent.getStringExtra("file"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.ZRTP_OFF)) {
-                secureZrtpOff((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("callID"));
+                secureZrtpOff((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("call"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.ZRTP_ON)) {
-                secureZrtpOn((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("callID"));
+                secureZrtpOn((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("call"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.DISPLAY_SAS)) {
-                displaySAS((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("callID"));
+                displaySAS((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("call"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.ZRTP_NEGOTIATION_FAILED)) {
-                zrtpNegotiationFailed((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("callID"));
+                zrtpNegotiationFailed((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("call"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.ZRTP_NOT_SUPPORTED)) {
-                zrtpNotSupported((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("callID"));
+                zrtpNotSupported((Conference) intent.getParcelableExtra("conference"), intent.getStringExtra("call"));
             } else if (intent.getAction().contentEquals(CallManagerCallBack.RTCP_REPORT_RECEIVED)) {
                 rtcpReportReceived(null, null); // FIXME
             } else {
@@ -172,4 +172,4 @@
         }
 
     }
-}
\ No newline at end of file
+}
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/DetailsHistoryEntryFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/DetailsHistoryEntryFragment.java
index 5af66eb..038b91a 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/DetailsHistoryEntryFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/DetailsHistoryEntryFragment.java
@@ -48,7 +48,7 @@
 import cx.ring.history.HistoryEntry;
 import cx.ring.model.account.Account;
 import cx.ring.model.SipCall;
-import cx.ring.service.ISipService;
+import cx.ring.service.IDRingService;
 
 import java.util.ArrayList;
 import java.util.Map;
@@ -72,7 +72,7 @@
     private static Callbacks sDummyCallbacks = new Callbacks() {
 
         @Override
-        public ISipService getService() {
+        public IDRingService getService() {
             return null;
         }
 
@@ -84,9 +84,9 @@
 
     public interface Callbacks {
 
-        public ISipService getService();
+        IDRingService getService();
 
-        public void onCall(SipCall call);
+        void onCall(SipCall call);
 
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/NestedSettingsFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/NestedSettingsFragment.java
index 6d192f1..0108955 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/NestedSettingsFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/NestedSettingsFragment.java
@@ -46,7 +46,7 @@
 import cx.ring.model.account.SRTPManager;
 import cx.ring.model.account.TLSManager;
 import cx.ring.model.account.Account;
-import cx.ring.service.ISipService;
+import cx.ring.service.IDRingService;
 import cx.ring.service.LocalService;
 
 import java.util.ArrayList;
@@ -64,7 +64,7 @@
 
     private static Callbacks sDummyCallbacks = new Callbacks() {
         @Override
-        public ISipService getRemoteService() {
+        public IDRingService getRemoteService() {
             return null;
         }
         @Override
diff --git a/ring-android/app/src/main/java/cx/ring/loaders/AccountsLoader.java b/ring-android/app/src/main/java/cx/ring/loaders/AccountsLoader.java
index b96b666..3c94e08 100644
--- a/ring-android/app/src/main/java/cx/ring/loaders/AccountsLoader.java
+++ b/ring-android/app/src/main/java/cx/ring/loaders/AccountsLoader.java
@@ -42,17 +42,17 @@
 import java.util.Map;
 
 import cx.ring.model.account.Account;
-import cx.ring.service.ISipService;
+import cx.ring.service.IDRingService;
 
 public class AccountsLoader extends AsyncTaskLoader<Bundle> {
 
     private static final String TAG = AccountsLoader.class.getSimpleName();
     public static final String ACCOUNTS = "accounts";
     public static final String ACCOUNT_IP2IP = "IP2IP";
-    ISipService service;
+    IDRingService service;
     Bundle mData;
 
-    public AccountsLoader(Context context, ISipService ref) {
+    public AccountsLoader(Context context, IDRingService ref) {
         super(context);
         service = ref;
     }
diff --git a/ring-android/app/src/main/java/cx/ring/loaders/AccountsStateLoader.java b/ring-android/app/src/main/java/cx/ring/loaders/AccountsStateLoader.java
index 9f1908b..14a40fb 100644
--- a/ring-android/app/src/main/java/cx/ring/loaders/AccountsStateLoader.java
+++ b/ring-android/app/src/main/java/cx/ring/loaders/AccountsStateLoader.java
@@ -33,7 +33,7 @@
 
 import java.util.Map;
 
-import cx.ring.service.ISipService;
+import cx.ring.service.IDRingService;
 
 import android.content.AsyncTaskLoader;
 import android.content.Context;
@@ -45,10 +45,10 @@
     private static final String TAG = AccountsStateLoader.class.getSimpleName();
     public static final String ACCOUNTS = "accounts";
     public static final String ACCOUNT_IP2IP = "IP2IP";
-    final ISipService service;
+    final IDRingService service;
     final String accountId;
 
-    public AccountsStateLoader(Context context, ISipService ref, String accId) {
+    public AccountsStateLoader(Context context, IDRingService ref, String accId) {
         super(context);
         service = ref;
         accountId = accId;
diff --git a/ring-android/app/src/main/java/cx/ring/model/Conversation.java b/ring-android/app/src/main/java/cx/ring/model/Conversation.java
index 715dc3e..6401f27 100644
--- a/ring-android/app/src/main/java/cx/ring/model/Conversation.java
+++ b/ring-android/app/src/main/java/cx/ring/model/Conversation.java
@@ -46,6 +46,14 @@
         return null;
     }
 
+    public void addConference(Conference c) {
+        current_calls.add(c);
+    }
+
+    public void removeConference(Conference c) {
+        current_calls.remove(c);
+    }
+
     public Pair<HistoryEntry, HistoryCall> findHistoryByCallId(String id) {
         for (HistoryEntry e : history.values()) {
             for (HistoryCall c : e.getCalls().values()) {
@@ -197,9 +205,6 @@
             return null;
         return current_calls.get(0);
     }
-    public void setCurrentCall(Conference c) {
-        current_calls.add(c);
-    }
 
     @Override
     public int describeContents() {
diff --git a/ring-android/app/src/main/java/cx/ring/model/SipCall.java b/ring-android/app/src/main/java/cx/ring/model/SipCall.java
index e178269..05693b8 100644
--- a/ring-android/app/src/main/java/cx/ring/model/SipCall.java
+++ b/ring-android/app/src/main/java/cx/ring/model/SipCall.java
@@ -36,6 +36,8 @@
 import android.os.Parcelable;
 import android.util.Log;
 
+import java.util.Map;
+
 public class SipCall implements Parcelable {
 
     public static String ID = "id";
@@ -51,6 +53,8 @@
     private String mAccount = "";
     private CallContact mContact = null;
     private String mNumber = "";
+    private boolean isPeerHolding = false;
+    private boolean isAudioMuted = false;
     private boolean isRecording = false;
     private long timestampStart_ = 0;
     private long timestampEnd_ = 0;
@@ -104,6 +108,16 @@
         mNumber = args.getString(NUMBER);
     }
 
+    public SipCall(String callId, Map<String, String> call_details) {
+        mCallID = callId;
+        mAccount = call_details.get("ACCOUNTID");
+        mCallType = Integer.parseInt(call_details.get("CALL_TYPE"));
+        mCallState = stateFromString(call_details.get("CALL_STATE"));
+        mNumber = call_details.get("PEER_NUMBER");
+        isPeerHolding = call_details.get("PEER_HOLDING").contentEquals("true");
+        isAudioMuted = call_details.get("AUDIO_MUTED").contentEquals("true");
+    }
+
     public String getRecordPath() {
         return "";
     }
@@ -128,20 +142,22 @@
     }
 
     public interface Direction {
-        int INCOMING = 1;
-        int OUTGOING = 2;
+        int INCOMING = 0;
+        int OUTGOING = 1;
     }
 
     public interface State {
         int NONE = 0;
-        int CONNECTING = 1;
-        int RINGING = 2;
-        int CURRENT = 3;
-        int HUNGUP = 4;
-        int BUSY = 5;
-        int FAILURE = 6;
-        int HOLD = 7;
-        int UNHOLD = 8;
+        int INCOMING = 1;
+        int CONNECTING = 2;
+        int RINGING = 3;
+        int CURRENT = 4;
+        int HUNGUP = 5;
+        int BUSY = 6;
+        int FAILURE = 7;
+        int HOLD = 8;
+        int UNHOLD = 9;
+        int INACTIVE = 10;
     }
 
     @Override
@@ -236,39 +252,61 @@
     }
 
     public String getCallStateString() {
+        return getCallStateString(mCallState);
+    }
 
-        String text_state;
-
-        switch (mCallState) {
-            case State.NONE:
-                text_state = "NONE";
-                break;
+    public static String getCallStateString(int state) {
+        switch (state) {
+            case State.INCOMING:
+                return "INCOMING";
+            case State.CONNECTING:
+                return "CONNECTING";
             case State.RINGING:
-                text_state = "RINGING";
-                break;
+                return "RINGING";
             case State.CURRENT:
-                text_state = "CURRENT";
-                break;
+                return "CURRENT";
             case State.HUNGUP:
-                text_state = "HUNGUP";
-                break;
+                return "HUNGUP";
             case State.BUSY:
-                text_state = "BUSY";
-                break;
+                return "BUSY";
             case State.FAILURE:
-                text_state = "FAILURE";
-                break;
+                return "FAILURE";
             case State.HOLD:
-                text_state = "HOLD";
-                break;
+                return "HOLD";
             case State.UNHOLD:
-                text_state = "UNHOLD";
-                break;
+                return "UNHOLD";
+            case State.NONE:
             default:
-                text_state = "NULL";
+                return "NONE";
         }
+    }
 
-        return text_state;
+    public static int stateFromString(String state) {
+        switch (state) {
+            case "INCOMING":
+                return State.INCOMING;
+            case "CONNECTING":
+                return State.CONNECTING;
+            case "RINGING":
+                return State.RINGING;
+            case "CURRENT":
+                return State.CURRENT;
+            case "HUNGUP":
+                return State.HUNGUP;
+            case "BUSY":
+                return State.BUSY;
+            case "FAILURE":
+                return State.FAILURE;
+            case "HOLD":
+                return State.HOLD;
+            case "UNHOLD":
+                return State.UNHOLD;
+            case "INACTIVE":
+                return State.INACTIVE;
+            case "NONE":
+            default:
+                return State.NONE;
+        }
     }
 
     public boolean isRecording() {
@@ -282,7 +320,7 @@
     public void printCallInfo() {
         Log.i(TAG, "CallInfo: CallID: " + mCallID);
         Log.i(TAG, "          AccountID: " + mAccount);
-        Log.i(TAG, "          CallState: " + mCallState);
+        Log.i(TAG, "          CallState: " + getCallStateString());
         Log.i(TAG, "          CallType: " + mCallType);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/service/CallManagerCallBack.java b/ring-android/app/src/main/java/cx/ring/service/CallManagerCallBack.java
index c0b1615..297f4fb 100644
--- a/ring-android/app/src/main/java/cx/ring/service/CallManagerCallBack.java
+++ b/ring-android/app/src/main/java/cx/ring/service/CallManagerCallBack.java
@@ -1,31 +1,15 @@
 package cx.ring.service;
 
-import android.support.v4.app.NotificationCompat;
-import android.app.PendingIntent;
 import android.content.Intent;
-import android.os.Bundle;
 import android.util.Log;
 
-import cx.ring.R;
-import cx.ring.client.CallActivity;
 import cx.ring.history.HistoryText;
-import cx.ring.model.CallContact;
 import cx.ring.model.TextMessage;
-import cx.ring.model.account.Account;
-import cx.ring.model.account.AccountDetailSrtp;
-import cx.ring.utils.SwigNativeConverter;
-
-import java.util.ArrayList;
-import java.util.Map;
-
-import cx.ring.model.Conference;
-import cx.ring.model.SecureSipCall;
-import cx.ring.model.SipCall;
 
 public class CallManagerCallBack extends Callback {
 
     private static final String TAG = "CallManagerCallBack";
-    private SipService mService;
+    private DRingService mService;
 
     static public final String CALL_STATE_CHANGED = "call-State-changed";
     static public final String INCOMING_CALL = "incoming-call";
@@ -44,7 +28,7 @@
     static public final String RTCP_REPORT_RECEIVED = "on_rtcp_report_received";
 
 
-    public CallManagerCallBack(SipService context) {
+    public CallManagerCallBack(DRingService context) {
         super();
         mService = context;
     }
@@ -52,67 +36,10 @@
     @Override
     public void callStateChanged(String callID, String newState, int detail_code) {
         Log.w(TAG, "on_call_state_changed : (" + callID + ", " + newState + ")");
-
-        Conference toUpdate = mService.findConference(callID);
-
-        if (toUpdate == null) {
-            Log.w(TAG, "callStateChanged: can't find call " + callID);
-            return;
-        }
-
         Intent intent = new Intent(CALL_STATE_CHANGED);
-        intent.putExtra("CallID", callID);
-        intent.putExtra("State", newState);
-        intent.putExtra("DetailCode", detail_code);
-
-        if (toUpdate.isRinging() && !newState.equals("RINGING")) {
-            Log.w(TAG, "Setting call start date " + callID);
-            toUpdate.getCallById(callID).setTimestampStart(System.currentTimeMillis());
-        }
-
-        switch (newState) {
-            case "CONNECTING":
-                toUpdate.setCallState(callID, SipCall.State.CONNECTING); break;
-            case "RINGING":
-                toUpdate.setCallState(callID, SipCall.State.RINGING); break;
-            case "CURRENT":
-                toUpdate.setCallState(callID, SipCall.State.CURRENT); break;
-            case "HOLD":
-                toUpdate.setCallState(callID, SipCall.State.HOLD); break;
-            case "UNHOLD":
-                toUpdate.setCallState(callID, SipCall.State.CURRENT); break;
-            case "HUNGUP":
-            case "INACTIVE":
-                Log.d(TAG, "Hanging up " + callID);
-                Log.w("CallNotification ", "Canceling " + toUpdate.notificationId);
-                mService.mNotificationManager.notificationManager.cancel(toUpdate.notificationId);
-                SipCall call = toUpdate.getCallById(callID);
-                if (!toUpdate.hasMultipleParticipants()) {
-                    if (toUpdate.isRinging() && toUpdate.isIncoming()) {
-                        mService.mNotificationManager.publishMissedCallNotification(mService.getConferences().get(callID));
-                    }
-                    toUpdate.setCallState(callID, SipCall.State.HUNGUP);
-                    mService.mHistoryManager.insertNewEntry(toUpdate);
-                    mService.getConferences().remove(toUpdate.getId());
-                } else {
-                    toUpdate.setCallState(callID, SipCall.State.HUNGUP);
-                    mService.mHistoryManager.insertNewEntry(call);
-                }
-                break;
-            case "BUSY":
-                mService.mNotificationManager.notificationManager.cancel(toUpdate.notificationId);
-                toUpdate.setCallState(callID, SipCall.State.BUSY);
-                mService.getConferences().remove(toUpdate.getId());
-                break;
-            case "FAILURE":
-                Log.w("CallNotification ", "Canceling " + toUpdate.notificationId);
-                mService.mNotificationManager.notificationManager.cancel(toUpdate.notificationId);
-                toUpdate.setCallState(callID, SipCall.State.FAILURE);
-                mService.getConferences().remove(toUpdate.getId());
-                Ringservice.hangUp(callID);
-                break;
-        }
-        intent.putExtra("conference", toUpdate);
+        intent.putExtra("call", callID);
+        intent.putExtra("state", newState);
+        intent.putExtra("detail_code", detail_code);
         mService.sendBroadcast(intent);
     }
 
@@ -122,53 +49,13 @@
         Log.w(TAG, "on_incoming_call(" + accountID + ", " + callID + ", " + from + ")");
 
         try {
-            StringMap details = Ringservice.getAccountDetails(accountID);
-            //VectMap credentials = Ringservice.getCredentials(accountID);
-            //StringMap state = Ringservice.getVolatileAccountDetails(accountID);
-            Account acc = new Account(accountID, details.toNative(), null, null);
-
             Intent toSend = new Intent(CallManagerCallBack.INCOMING_CALL);
-            toSend.setClass(mService, CallActivity.class);
-            toSend.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
-            CallContact unknown = CallContact.buildUnknown(from);
-
-            SipCall newCall = new SipCall(callID, accountID, from, SipCall.Direction.INCOMING);
-            newCall.setContact(unknown);
-            newCall.setCallState(SipCall.State.RINGING);
-            newCall.setTimestampStart(System.currentTimeMillis());
-
-            Conference toAdd;
-            if (acc.useSecureLayer()) {
-               SecureSipCall secureCall = new SecureSipCall(newCall, acc.getSrtpDetails().getDetailString(AccountDetailSrtp.CONFIG_SRTP_KEY_EXCHANGE));
-                toAdd = new Conference(secureCall);
-            } else {
-                toAdd = new Conference(newCall);
-            }
-
-            mService.getConferences().put(toAdd.getId(), toAdd);
-
-            NotificationCompat.Builder noti = new NotificationCompat.Builder(mService)
-                    .setContentTitle("Incoming call with " + from)
-                    .setContentText("incoming call")
-                    .setOngoing(true)
-                    .setSmallIcon(R.drawable.ic_launcher)
-                    .addAction(R.drawable.ic_call_end_white_24dp, "End call",
-                            PendingIntent.getService(mService, 4278,
-                                new Intent(mService, SipService.class)
-                                        .setAction(SipService.ACTION_CALL_END)
-                                        .putExtra("conf", toAdd.getId()),
-                                    PendingIntent.FLAG_ONE_SHOT));
-
-            //mService.startForeground(toAdd.notificationId, noti);
-            Log.w("CallNotification ", "Adding for incoming " + toAdd.notificationId);
-            mService.mNotificationManager.notificationManager.notify(toAdd.notificationId, noti.build());
-
-            Bundle bundle = new Bundle();
-            bundle.putParcelable("conference", toAdd);
+            toSend.putExtra("call", callID);
+            toSend.putExtra("account", accountID);
+            toSend.putExtra("from", from);
             toSend.putExtra("resuming", false);
-            toSend.putExtras(bundle);
-            mService.startActivity(toSend);
+            mService.sendBroadcast(toSend);
+
             mService.mMediaManager.startRing("");
             mService.mMediaManager.obtainAudioFocus(true);
         } catch (Exception e) {
@@ -180,29 +67,7 @@
     public void conferenceCreated(final String confID) {
         Log.w(TAG, "CONFERENCE CREATED:" + confID);
         Intent intent = new Intent(CONF_CREATED);
-        Conference created = new Conference(confID);
-
-        StringVect all_participants = Ringservice.getParticipantList(confID);
-        Log.w(TAG, "all_participants:" + all_participants.size());
-        for (int i = 0; i < all_participants.size(); ++i) {
-            if (mService.getConferences().get(all_participants.get(i)) != null) {
-                created.addParticipant(mService.getConferences().get(all_participants.get(i)).getCallById(all_participants.get(i)));
-                mService.getConferences().remove(all_participants.get(i));
-            } else {
-                for (Map.Entry<String, Conference> stringConferenceEntry : mService.getConferences().entrySet()) {
-                    Conference tmp = stringConferenceEntry.getValue();
-                    for (SipCall c : tmp.getParticipants()) {
-                        if (c.getCallId().contentEquals(all_participants.get(i))) {
-                            created.addParticipant(c);
-                            mService.getConferences().get(tmp.getId()).removeParticipant(c);
-                        }
-                    }
-                }
-            }
-        }
-        intent.putExtra("conference", created);
-        intent.putExtra("confID", created.getId());
-        mService.getConferences().put(created.getId(), created);
+        intent.putExtra("conference", confID);
         mService.sendBroadcast(intent);
     }
 
@@ -214,30 +79,15 @@
         if (msg == null)
             return;
 
-        Conference conf = mService.getConferences().get(id);
-        if (conf == null) {
-            for (Conference tmp : mService.getConferences().values())
-                if (tmp.getCallById(id) != null) {
-                    conf = tmp;
-                    break;
-                }
-            if (conf == null) {
-                Log.w(TAG, "Discarding message for unknown call " + id);
-                return;
-            }
-        }
-
-        TextMessage message = new TextMessage(true, msg, from, id, conf.hasMultipleParticipants() ? null : conf.getParticipants().get(0).getAccount());
-        if (!conf.hasMultipleParticipants())
-            message.setContact(conf.getParticipants().get(0).getContact());
-
-        conf.addSipMessage(message);
+        TextMessage message = new TextMessage(true, msg, from, id, null/*, conf.hasMultipleParticipants() ? null : conf.getParticipants().get(0).getAccount()*/);
 
         mService.mHistoryManager.insertNewTextMessage(new HistoryText(message));
 
         Intent intent = new Intent(INCOMING_TEXT);
+        intent.putExtra("call", id);
+        intent.putExtra("from", from);
         intent.putExtra("txt", message);
-        intent.putExtra("conference", conf);
+        //intent.putExtra("conference", conf);
         mService.sendBroadcast(intent);
     }
 
@@ -245,69 +95,25 @@
     public void conferenceRemoved(String confID) {
         Log.i(TAG, "on_conference_removed:");
         Intent intent = new Intent(CONF_REMOVED);
-        intent.putExtra("confID", confID);
-
-        Conference toReInsert = mService.getConferences().get(confID);
-        for (SipCall call : toReInsert.getParticipants()) {
-            mService.getConferences().put(call.getCallId(), new Conference(call));
-        }
-
-        Conference conf = mService.getConferences().get(confID);
-
-        Log.w("CallNotification ", "Canceling " + conf.notificationId);
-        //NotificationManager mNotifyMgr = (NotificationManager) mService.getSystemService(Context.NOTIFICATION_SERVICE);
-        mService.mNotificationManager.notificationManager.cancel(conf.notificationId);
-
-        intent.putExtra("conference", conf);
-        mService.getConferences().remove(confID);
+        intent.putExtra("conference", confID);
         mService.sendBroadcast(intent);
-
-        if (mService.getConferences().size() == 0) {
-            mService.stopForeground(true);
-        }
-
     }
 
     @Override
     public void conferenceChanged(String confID, String state) {
         Log.i(TAG, "on_conference_state_changed:");
-        Intent intent = new Intent(CONF_CHANGED);
-        intent.putExtra("confID", confID);
-        intent.putExtra("State", 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(Ringservice.getParticipantList(intent.getStringExtra("confID")));
-
-        if (toModify.getParticipants().size() < newParticipants.size()) {
-            // We need to add the new participant to the conf
-            for (String newParticipant : newParticipants) {
-                if (toModify.getCallById(newParticipant) == null) {
-                    mService.addCallToConference(toModify.getId(), newParticipant);
-                }
-            }
-        } else if (toModify.getParticipants().size() > newParticipants.size()) {
-            Log.i(TAG, "toModify.getParticipants().size() > newParticipants.size()");
-            for (SipCall participant : toModify.getParticipants()) {
-                if (!newParticipants.contains(participant.getCallId())) {
-                    mService.detachCallFromConference(toModify.getId(), participant);
-                    break;
-                }
-            }
-        }
-
+        Intent intent = new Intent(CONF_CHANGED);
+        intent.putExtra("conference", confID);
+        intent.putExtra("state", state);
         mService.sendBroadcast(intent);
     }
 
     @Override
     public void recordPlaybackFilepath(String id, String filename) {
         Intent intent = new Intent();
-        intent.putExtra("callID", id);
+        intent.putExtra("call", id);
         intent.putExtra("file", filename);
         mService.sendBroadcast(intent);
     }
@@ -315,28 +121,25 @@
     @Override
     public void secureSdesOn(String callID) {
         Log.i(TAG, "on_secure_sdes_on");
-        SecureSipCall call = (SecureSipCall) mService.getCallById(callID);
+        /*SecureSipCall call = (SecureSipCall) mService.getCallById(callID);
         call.setInitialized();
-        call.useSecureSDES(true);
+        call.useSecureSDES(true);*/
     }
 
     @Override
     public void secureSdesOff(String callID) {
         Log.i(TAG, "on_secure_sdes_off");
-        SecureSipCall call = (SecureSipCall) mService.getCallById(callID);
+        /*SecureSipCall call = (SecureSipCall) mService.getCallById(callID);
         call.setInitialized();
-        call.useSecureSDES(false);
+        call.useSecureSDES(false);*/
     }
 
     @Override
     public void secureZrtpOn(String callID, String cipher) {
         Log.i(TAG, "on_secure_zrtp_on");
         Intent intent = new Intent(ZRTP_ON);
-        SecureSipCall call = (SecureSipCall) mService.getCallById(callID);
-        call.setInitialized();
-        call.setZrtpSupport(true);
-        intent.putExtra("callID", callID);
-        intent.putExtra("conference", mService.findConference(callID));
+        intent.putExtra("call", callID);
+        intent.putExtra("cipher", cipher);
         mService.sendBroadcast(intent);
     }
 
@@ -344,15 +147,7 @@
     public void secureZrtpOff(String callID) {
         Log.i(TAG, "on_secure_zrtp_off");
         Intent intent = new Intent(ZRTP_OFF);
-        intent.putExtra("callID", callID);
-        SecureSipCall call = (SecureSipCall) mService.getCallById(callID);
-        // Security can be off because call was hung up
-        if (call == null)
-            return;
-
-        call.setInitialized();
-        call.setZrtpSupport(false);
-        intent.putExtra("conference", mService.findConference(callID));
+        intent.putExtra("call", callID);
         mService.sendBroadcast(intent);
     }
 
@@ -360,14 +155,9 @@
     public void showSAS(String callID, String sas, int verified) {
         Log.i(TAG, "on_show_sas:" + sas);
         Intent intent = new Intent(DISPLAY_SAS);
-        SecureSipCall call = (SecureSipCall) mService.getCallById(callID);
-        call.setSAS(sas);
-        call.sasConfirmedByZrtpLayer(verified);
-
-        intent.putExtra("callID", callID);
-        intent.putExtra("SAS", sas);
+        intent.putExtra("call", callID);
+        intent.putExtra("sas", sas);
         intent.putExtra("verified", verified);
-        intent.putExtra("conference", mService.findConference(callID));
         mService.sendBroadcast(intent);
     }
 
@@ -375,11 +165,7 @@
     public void zrtpNotSuppOther(String callID) {
         Log.i(TAG, "on_zrtp_not_supported");
         Intent intent = new Intent(ZRTP_NOT_SUPPORTED);
-        SecureSipCall call = (SecureSipCall) mService.getCallById(callID);
-        call.setInitialized();
-        call.setZrtpSupport(false);
-        intent.putExtra("callID", callID);
-        intent.putExtra("conference", mService.findConference(callID));
+        intent.putExtra("call", callID);
         mService.sendBroadcast(intent);
     }
 
@@ -387,11 +173,7 @@
     public void zrtpNegotiationFailed(String callID, String reason, String severity) {
         Log.i(TAG, "on_zrtp_negociation_failed");
         Intent intent = new Intent(ZRTP_NEGOTIATION_FAILED);
-        SecureSipCall call = (SecureSipCall) mService.getCallById(callID);
-        call.setInitialized();
-        call.setZrtpSupport(false);
-        intent.putExtra("callID", callID);
-        intent.putExtra("conference", mService.findConference(callID));
+        intent.putExtra("call", callID);
         mService.sendBroadcast(intent);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/service/ConfigurationManagerCallback.java b/ring-android/app/src/main/java/cx/ring/service/ConfigurationManagerCallback.java
index e852a0d..dba874d 100644
--- a/ring-android/app/src/main/java/cx/ring/service/ConfigurationManagerCallback.java
+++ b/ring-android/app/src/main/java/cx/ring/service/ConfigurationManagerCallback.java
@@ -31,14 +31,14 @@
 
 public class ConfigurationManagerCallback extends ConfigurationCallback {
 
-    private  SipService mService;
+    private DRingService mService;
     private static final String TAG = "ConfigurationManagerCb";
 
     static public final String ACCOUNTS_CHANGED = "accounts-changed";
     static public final String ACCOUNT_STATE_CHANGED = "account-State-changed";
     static public final String INCOMING_TEXT = "incoming--txt-msg";
 
-    public ConfigurationManagerCallback(SipService context) {
+    public ConfigurationManagerCallback(DRingService context) {
         super();
         mService = context;
     }
@@ -84,8 +84,8 @@
 
     private void sendAccountStateChangedMessage(String accoundID, String state, int code) {
         Intent intent = new Intent(ACCOUNT_STATE_CHANGED);
-        intent.putExtra("Account", accoundID);
-        intent.putExtra("State", state);
+        intent.putExtra("account", accoundID);
+        intent.putExtra("state", state);
         intent.putExtra("code", code);
         mService.sendBroadcast(intent);
     }
diff --git a/ring-android/app/src/main/java/cx/ring/service/SipService.java b/ring-android/app/src/main/java/cx/ring/service/DRingService.java
similarity index 72%
rename from ring-android/app/src/main/java/cx/ring/service/SipService.java
rename to ring-android/app/src/main/java/cx/ring/service/DRingService.java
index 81ed886..0842227 100644
--- a/ring-android/app/src/main/java/cx/ring/service/SipService.java
+++ b/ring-android/app/src/main/java/cx/ring/service/DRingService.java
@@ -58,18 +58,19 @@
 import cx.ring.model.SipCall;
 
 
-public class SipService extends Service {
+public class DRingService extends Service {
 
-    static final String TAG = "SipService";
+    static final String TAG = "DRingService";
     private SipServiceExecutor mExecutor;
     private static HandlerThread executorThread;
 
     static public final String ACTION_CALL_ACCEPT = BuildConfig.APPLICATION_ID + ".action.CALL_ACCEPT";
     static public final String ACTION_CALL_REFUSE = BuildConfig.APPLICATION_ID + ".action.CALL_REFUSE";
-    //static public final String ACTION_CALL_REFUSE = BuildConfig.APPLICATION_ID + ".action.CALL_REFUSE";
 
     static public final String ACTION_CALL_END = BuildConfig.APPLICATION_ID + ".action.CALL_END";
 
+    static public final String DRING_CONNECTION_CHANGED = BuildConfig.APPLICATION_ID + ".event.DRING_CONNECTION_CHANGE";
+
     private Handler handler = new Handler();
     private static int POLLING_TIMEOUT = 50;
     private Runnable pollEvents = new Runnable() {
@@ -86,45 +87,12 @@
     };
     private boolean isPjSipStackStarted = false;
 
-    protected SipNotifications mNotificationManager;
     protected HistoryManager mHistoryManager;
     protected MediaManager mMediaManager;
 
-    private final HashMap<String, Conference> mConferences = new HashMap<>();
     private ConfigurationManagerCallback configurationCallback;
     private CallManagerCallBack callManagerCallBack;
 
-    public HashMap<String, Conference> getConferences() {
-        return mConferences;
-    }
-
-    public void addCallToConference(String confId, String callId) {
-        if(mConferences.get(callId) != null){
-            // We add a simple call to a conference
-            Log.i(TAG, "// We add a simple call to a conference");
-            mConferences.get(confId).addParticipant(mConferences.get(callId).getParticipants().get(0));
-            mConferences.remove(callId);
-        } else {
-            Log.i(TAG, "addCallToConference");
-            for (Entry<String, Conference> stringConferenceEntry : mConferences.entrySet()) {
-                Conference tmp = stringConferenceEntry.getValue();
-                for (SipCall c : tmp.getParticipants()) {
-                    if (c.getCallId().contentEquals(callId)) {
-                        mConferences.get(confId).addParticipant(c);
-                        mConferences.get(tmp.getId()).removeParticipant(c);
-                    }
-                }
-            }
-        }
-    }
-
-    public void detachCallFromConference(String confId, SipCall call) {
-        Log.i(TAG, "detachCallFromConference");
-        Conference separate = new Conference(call);
-        mConferences.put(separate.getId(), separate);
-        mConferences.get(confId).removeParticipant(call);
-    }
-
     @Override
     public boolean onUnbind(Intent i) {
         super.onUnbind(i);
@@ -145,13 +113,9 @@
 
         getExecutor().execute(new StartRunnable());
 
-        mNotificationManager = new SipNotifications(this);
         mMediaManager = new MediaManager(this);
         mHistoryManager = new HistoryManager(this);
-
-        mNotificationManager.onServiceCreate();
         mMediaManager.startService();
-
     }
 
     /* called for each startService() */
@@ -161,26 +125,17 @@
         String action = intent == null ? null : intent.getAction();
         try {
             if (action != null) {
-                if (action.equals(ACTION_CALL_END)) {
-                    Conference c = findConference(intent.getStringExtra("conf"));
-                    if (c != null) {
-                        for (SipCall call : c.getParticipants()) {
-                            mBinder.hangUp(call.getCallId());
-                        }
-                        mBinder.hangUpConference(c.getId());
-                        Log.w("CallNotification ", "Canceling " + c.notificationId);
-                        mNotificationManager.notificationManager.cancel(c.notificationId);
-                    }
-                } else if (action.equals(ACTION_CALL_ACCEPT)) {
-                    Conference c = findConference(intent.getStringExtra("conf"));
-                    if (c != null) {
-                        mBinder.accept(c.getParticipants().get(0).getCallId());
-                    }
-                } else if (action.equals(ACTION_CALL_REFUSE)) {
-                    Conference c = findConference(intent.getStringExtra("conf"));
-                    if (c != null) {
-                        mBinder.refuse(c.getParticipants().get(0).getCallId());
-                    }
+                String callId = intent.getStringExtra("conf");
+                switch (action) {
+                    case ACTION_CALL_END:
+                        mBinder.hangUpConference(callId);
+                        break;
+                    case ACTION_CALL_ACCEPT:
+                        mBinder.accept(callId);
+                        break;
+                    case ACTION_CALL_REFUSE:
+                        mBinder.refuse(callId);
+                        break;
                 }
             }
         } catch (Exception e) {
@@ -193,8 +148,6 @@
     @Override
     public void onDestroy() {
         Log.i(TAG, "onDestroy");
-        /* called once by stopService() */
-        mNotificationManager.onServiceDestroy();
         mMediaManager.stopService();
         getExecutor().execute(new FinalizeRunnable());
         super.onDestroy();
@@ -211,7 +164,7 @@
         if (executorThread == null) {
             Log.d(TAG, "Creating new handler thread");
             // ADT gives a fake warning due to bad parse rule.
-            executorThread = new HandlerThread("SipService.Executor");
+            executorThread = new HandlerThread("DRingService.Executor");
             executorThread.start();
         }
         return executorThread.getLooper();
@@ -225,21 +178,6 @@
         return mExecutor;
     }
 
-    public SipCall getCallById(String callID) {
-        if (getConferences().get(callID) != null) {
-            return getConferences().get(callID).getCallById(callID);
-        } else {
-            // Check if call is in a conference
-            for (Entry<String, Conference> stringConferenceEntry : getConferences().entrySet()) {
-                Conference tmp = stringConferenceEntry.getValue();
-                SipCall c = tmp.getCallById(callID);
-                if (c != null)
-                    return c;
-            }
-        }
-        return null;
-    }
-
     // Executes immediate tasks in a single executorThread.
     public static class SipServiceExecutor extends Handler {
 
@@ -357,6 +295,9 @@
             Ringservice.fini();
             isPjSipStackStarted = false;
             Log.i(TAG, "PjSIPStack stopped");
+            Intent intent = new Intent(DRING_CONNECTION_CHANGED);
+            intent.putExtra("connected", isPjSipStackStarted);
+            sendBroadcast(intent);
         }
     }
 
@@ -382,6 +323,9 @@
         Ringservice.init(configurationCallback, callManagerCallBack);
         handler.postDelayed(pollEvents, POLLING_TIMEOUT);
         Log.i(TAG, "PjSIPStack started");
+        Intent intent = new Intent(DRING_CONNECTION_CHANGED);
+        intent.putExtra("connected", isPjSipStackStarted);
+        sendBroadcast(intent);
     }
 
     // Enforce same thread contract to ensure we do not call from somewhere else
@@ -410,7 +354,6 @@
 
     public abstract class SipRunnableWithReturn<T> implements Runnable {
         private T obj = null;
-        //boolean done = false;
 
         protected abstract T doRun() throws SameThreadException, RemoteException;
 
@@ -455,7 +398,7 @@
      * *********************************
      */
 
-    private final ISipService.Stub mBinder = new ISipService.Stub() {
+    private final IDRingService.Stub mBinder = new IDRingService.Stub() {
 
         @Override
         public String placeCall(final SipCall call) {
@@ -463,9 +406,7 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<String>() {
                 @Override
                 protected String doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.placeCall() thread running...");
-                    Conference toAdd;
-                    //mConferences.put(toAdd.getId(), toAdd);
+                    Log.i(TAG, "DRingService.placeCall() thread running...");
                     mMediaManager.obtainAudioFocus(false);
 
                     String number = call.getNumber();
@@ -473,37 +414,8 @@
                         number = call.getContact().getPhones().get(0).getNumber();
                     }
 
-                    Log.i(TAG, "SipService.placeCall() calling... " + number);
-                    String call_id = Ringservice.placeCall(call.getAccount(), number);
-                    call.setCallID(call_id);
-                    if (!call_id.isEmpty()) {
-                        final Map<String, String> details = getAccountDetails(call.getAccount());
-                        if(details.get(AccountDetailBasic.CONFIG_ACCOUNT_TYPE).contentEquals(AccountDetailBasic.ACCOUNT_TYPE_RING)
-                                || details.get(AccountDetailSrtp.CONFIG_SRTP_ENABLE).contentEquals(AccountDetail.TRUE_STR)
-                                || details.get(AccountDetailTls.CONFIG_TLS_ENABLE).contentEquals(AccountDetail.TRUE_STR)) {
-                            Log.i(TAG, "SipService.placeCall() call is secure");
-                            SecureSipCall secureCall = new SecureSipCall(call, details.get(AccountDetailSrtp.CONFIG_SRTP_KEY_EXCHANGE));
-                            toAdd = new Conference(secureCall);
-                        } else {
-                            toAdd = new Conference(call);
-                        }
-                        Log.i(TAG, "SipService.placeCall() returned with call id " + call_id);
-                        mConferences.put(call_id, toAdd);
-                        Notification noti = new Notification.Builder(SipService.this)
-                                .setContentTitle("Ongoing call with " + call.getContact().getDisplayName())
-                                .setContentText("outgoing call")
-                                .setOngoing(true)
-                                .setSmallIcon(R.drawable.ic_launcher)
-                                //.setContentIntent()
-                                /*.setContentText(subject)
-                                .setSmallIcon(R.drawable.new_mail)
-                                .setLargeIcon(aBitmap)*/
-                                .build();
-                        //startForeground(toAdd.notificationId, noti);
-                        Log.w("CallNotification ", "Adding for outgoing " + toAdd.notificationId);
-                        mNotificationManager.notificationManager.notify(toAdd.notificationId, noti);
-                    }
-                    return call_id;
+                    Log.i(TAG, "DRingService.placeCall() calling... " + number);
+                    return Ringservice.placeCall(call.getAccount(), number);
                 }
             });
         }
@@ -515,7 +427,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.refuse() thread running...");
+                    Log.i(TAG, "DRingService.refuse() thread running...");
                     Ringservice.refuse(callID);
                     Ringservice.hangUp(callID);
                 }
@@ -529,7 +441,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.accept() thread running...");
+                    Log.i(TAG, "DRingService.accept() thread running...");
                     Ringservice.accept(callID);
                     mMediaManager.RouteToInternalSpeaker();
                 }
@@ -543,13 +455,8 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.hangUp() thread running...");
+                    Log.i(TAG, "DRingService.hangUp() thread running...");
                     Ringservice.hangUp(callID);
-                    removeCall(callID);
-                    if(mConferences.size() == 0) {
-                        Log.i(TAG, "No more calls!");
-                        mMediaManager.abandonAudioFocus();
-                    }
                 }
             });
         }
@@ -559,7 +466,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.hold() thread running...");
+                    Log.i(TAG, "DRingService.hold() thread running...");
                     Ringservice.hold(callID);
                 }
             });
@@ -570,18 +477,23 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.unhold() thread running...");
+                    Log.i(TAG, "DRingService.unhold() thread running...");
                     Ringservice.unhold(callID);
                 }
             });
         }
 
         @Override
+        public boolean isStarted() throws RemoteException {
+            return isPjSipStackStarted;
+        }
+
+        @Override
         public Map<String, String> getCallDetails(final String callID) throws RemoteException {
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<Map<String, String>>() {
                 @Override
                 protected Map<String, String> doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.getCallDetails() thread running...");
+                    Log.i(TAG, "DRingService.getCallDetails() thread running...");
                     return Ringservice.getCallDetails(callID).toNative();
                 }
             });
@@ -592,7 +504,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.setAudioPlugin() thread running...");
+                    Log.i(TAG, "DRingService.setAudioPlugin() thread running...");
                     Ringservice.setAudioPlugin(audioPlugin);
                 }
             });
@@ -603,7 +515,7 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<String>() {
                 @Override
                 protected String doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.getCurrentAudioOutputPlugin() thread running...");
+                    Log.i(TAG, "DRingService.getCurrentAudioOutputPlugin() thread running...");
                     return Ringservice.getCurrentAudioOutputPlugin();
                 }
             });
@@ -614,7 +526,7 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<List<String>>() {
                 @Override
                 protected List<String> doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.getAccountList() thread running...");
+                    Log.i(TAG, "DRingService.getAccountList() thread running...");
                     return new ArrayList<>(Ringservice.getAccountList());
                 }
             });
@@ -625,7 +537,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.setAccountsOrder() thread running...");
+                    Log.i(TAG, "DRingService.setAccountsOrder() thread running...");
                     Ringservice.setAccountsOrder(order);
                 }
             });
@@ -636,7 +548,7 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<Map<String, String>>() {
                 @Override
                 protected Map<String, String> doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.getAccountDetails() thread running...");
+                    Log.i(TAG, "DRingService.getAccountDetails() thread running...");
                     return Ringservice.getAccountDetails(accountID).toNative();
                 }
             });
@@ -646,7 +558,7 @@
         // Hashmap runtime cast
         @Override
         public void setAccountDetails(final String accountId, final Map map) {
-            Log.i(TAG, "SipService.setAccountDetails() " + map.get("Account.hostname"));
+            Log.i(TAG, "DRingService.setAccountDetails() " + map.get("Account.hostname"));
             final StringMap swigmap = StringMap.toSwig(map);
 
             getExecutor().execute(new SipRunnable() {
@@ -654,7 +566,7 @@
                 protected void doRun() throws SameThreadException {
 
                     Ringservice.setAccountDetails(accountId, swigmap);
-                    Log.i(TAG, "SipService.setAccountDetails() thread running... " + swigmap.get("Account.hostname"));
+                    Log.i(TAG, "DRingService.setAccountDetails() thread running... " + swigmap.get("Account.hostname"));
                 }
 
             });
@@ -665,7 +577,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.setAccountActive() thread running... " + accountId + " -> " + active);
+                    Log.i(TAG, "DRingService.setAccountActive() thread running... " + accountId + " -> " + active);
                     Ringservice.setAccountActive(accountId, active);
                 }
             });
@@ -676,7 +588,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.setAccountsActive() thread running... " + active);
+                    Log.i(TAG, "DRingService.setAccountsActive() thread running... " + active);
                     StringVect list = Ringservice.getAccountList();
                     for (int i=0, n=list.size(); i<n; i++)
                         Ringservice.setAccountActive(list.get(i), active);
@@ -689,7 +601,7 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<Map<String, String>>() {
                 @Override
                 protected Map<String, String> doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.getVolatileAccountDetails() thread running...");
+                    Log.i(TAG, "DRingService.getVolatileAccountDetails() thread running...");
                     return Ringservice.getVolatileAccountDetails(accountId).toNative();
                 }
             });
@@ -700,7 +612,7 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<Map<String, String>>() {
                 @Override
                 protected Map<String, String> doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.getAccountTemplate() thread running...");
+                    Log.i(TAG, "DRingService.getAccountTemplate() thread running...");
                     return Ringservice.getAccountTemplate(accountType).toNative();
                 }
             });
@@ -713,7 +625,7 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<String>() {
                 @Override
                 protected String doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.addAccount() thread running...");
+                    Log.i(TAG, "DRingService.addAccount() thread running...");
                     return Ringservice.addAccount(StringMap.toSwig(map));
                 }
             });
@@ -724,7 +636,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.setAccountDetails() thread running...");
+                    Log.i(TAG, "DRingService.setAccountDetails() thread running...");
                     Ringservice.removeAccount(accountId);
                 }
             });
@@ -739,7 +651,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.transfer() thread running...");
+                    Log.i(TAG, "DRingService.transfer() thread running...");
                     if (Ringservice.transfer(callID, to)) {
                         Bundle bundle = new Bundle();
                         bundle.putString("CallID", callID);
@@ -759,7 +671,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.attendedTransfer() thread running...");
+                    Log.i(TAG, "DRingService.attendedTransfer() thread running...");
                     if (Ringservice.attendedTransfer(transferID, targetID)) {
                         Log.i(TAG, "OK");
                     } else
@@ -778,7 +690,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.createConference() thread running...");
+                    Log.i(TAG, "DRingService.createConference() thread running...");
                     Ringservice.removeConference(confID);
                 }
             });
@@ -790,7 +702,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.joinParticipant() thread running...");
+                    Log.i(TAG, "DRingService.joinParticipant() thread running...");
                     Ringservice.joinParticipant(sel_callID, drag_callID);
                     // Generate a CONF_CREATED callback
                 }
@@ -803,9 +715,8 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.addParticipant() thread running...");
+                    Log.i(TAG, "DRingService.addParticipant() thread running...");
                     Ringservice.addParticipant(call.getCallId(), confID);
-                    mConferences.get(confID).getParticipants().add(call);
                 }
             });
 
@@ -816,7 +727,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.addMainParticipant() thread running...");
+                    Log.i(TAG, "DRingService.addMainParticipant() thread running...");
                     Ringservice.addMainParticipant(confID);
                 }
             });
@@ -828,19 +739,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.detachParticipant() thread running...");
-                    Log.i(TAG, "Detaching " + callID);
-                    Iterator<Entry<String, Conference>> it = mConferences.entrySet().iterator();
-                    Log.i(TAG, "mConferences size " + mConferences.size());
-                    while (it.hasNext()) {
-                        Conference tmp = it.next().getValue();
-                        Log.i(TAG, "conf has " + tmp.getParticipants().size() + " participants");
-                        if (tmp.contains(callID)) {
-                            Conference toDetach = new Conference(tmp.getCallById(callID));
-                            mConferences.put(toDetach.getId(), toDetach);
-                            Log.i(TAG, "Call found and put in current_calls");
-                        }
-                    }
+                    Log.i(TAG, "DRingService.detachParticipant() thread running... " + callID);
                     Ringservice.detachParticipant(callID);
                 }
             });
@@ -852,7 +751,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.joinConference() thread running...");
+                    Log.i(TAG, "DRingService.joinConference() thread running...");
                     Ringservice.joinConference(sel_confID, drag_confID);
                 }
             });
@@ -865,7 +764,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.joinConference() thread running...");
+                    Log.i(TAG, "DRingService.joinConference() thread running...");
                     Ringservice.hangUpConference(confID);
                 }
             });
@@ -877,7 +776,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.holdConference() thread running...");
+                    Log.i(TAG, "DRingService.holdConference() thread running...");
                     Ringservice.holdConference(confID);
                 }
             });
@@ -889,7 +788,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.unholdConference() thread running...");
+                    Log.i(TAG, "DRingService.unholdConference() thread running...");
                     Ringservice.unholdConference(confID);
                 }
             });
@@ -901,36 +800,27 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<Boolean>() {
                 @Override
                 protected Boolean doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.isRecording() thread running...");
+                    Log.i(TAG, "DRingService.isRecording() thread running...");
                     return Ringservice.isConferenceParticipant(callID);
                 }
             });
         }
 
         @Override
-        public HashMap<String, Conference> getConferenceList() throws RemoteException {
-            // class ConfList extends SipRunnableWithReturn {
-            // @Override
-            // protected StringVect doRun() throws SameThreadException {
-            // Log.i(TAG, "SipService.getConferenceList() thread running...");
-            // return callManagerJNI.getConferenceList();
-            // }
-            // }
-            // ;
-            // ConfList runInstance = new ConfList();
-            // getExecutor().execute(runInstance);
-            // while (!runInstance.isDone()) {
-            // // Log.w(TAG, "Waiting for getConferenceList");
-            // }
-            // StringVect swigvect = (StringVect) runInstance.getVal();
-            //
-            // ArrayList<String> nativelist = new ArrayList<String>();
-            //
-            // for (int i = 0; i < swigvect.size(); i++)
-            // nativelist.add(swigvect.get(i));
-            //
-            // return nativelist;
-            return mConferences;
+        public Map<String, Map<String, String>> getConferenceList() throws RemoteException {
+            return getExecutor().executeAndReturn(new SipRunnableWithReturn<Map<String, Map<String, String>>>() {
+                @Override
+                protected Map<String, Map<String, String>> doRun() throws SameThreadException {
+                    Log.i(TAG, "DRingService.getConferenceList() thread running...");
+                    StringVect ids = Ringservice.getConferenceList();
+                    HashMap<String, Map<String, String>> confs = new HashMap<>(ids.size());
+                    for (int i=0; i<ids.size(); i++) {
+                        String id = ids.get(i);
+                        confs.put(id, Ringservice.getConferenceDetails(id).toNative());
+                    }
+                    return confs;
+                }
+            });
         }
 
         @Override
@@ -938,7 +828,7 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<List<String>>() {
                 @Override
                 protected List<String> doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.getParticipantList() thread running...");
+                    Log.i(TAG, "DRingService.getParticipantList() thread running...");
                     return new ArrayList<>(Ringservice.getParticipantList(confID));
                 }
             });
@@ -955,7 +845,7 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<String>() {
                 @Override
                 protected String doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.getConferenceDetails() thread running...");
+                    Log.i(TAG, "DRingService.getConferenceDetails() thread running...");
                     return Ringservice.getConferenceDetails(callID).get("CONF_STATE");
                 }
             });
@@ -966,7 +856,7 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<String>() {
                 @Override
                 protected String doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.getRecordPath() thread running...");
+                    Log.i(TAG, "DRingService.getRecordPath() thread running...");
                     return Ringservice.getRecordPath();
                 }
             });
@@ -977,18 +867,8 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<Boolean>() {
                 @Override
                 protected Boolean doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.toggleRecordingCall() thread running...");
-                    boolean result = Ringservice.toggleRecording(id);
-
-                    if (getConferences().containsKey(id)) {
-                        getConferences().get(id).setRecording(result);
-                    } else {
-                        for (Conference c : getConferences().values()) {
-                            if (c.getCallById(id) != null)
-                                c.getCallById(id).setRecording(result);
-                        }
-                    }
-                    return result;
+                    Log.i(TAG, "DRingService.toggleRecordingCall() thread running...");
+                    return Ringservice.toggleRecording(id);
                 }
             });
         }
@@ -998,7 +878,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.setRecordingCall() thread running...");
+                    Log.i(TAG, "DRingService.setRecordingCall() thread running...");
                     Ringservice.startRecordedFilePlayback(filepath);
                 }
             });
@@ -1010,7 +890,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.stopRecordedFilePlayback() thread running...");
+                    Log.i(TAG, "DRingService.stopRecordedFilePlayback() thread running...");
                     Ringservice.stopRecordedFilePlayback(filepath);
                 }
             });
@@ -1021,7 +901,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.setRecordPath() " + path + " thread running...");
+                    Log.i(TAG, "DRingService.setRecordPath() " + path + " thread running...");
                     Ringservice.setRecordPath(path);
                 }
             });
@@ -1032,18 +912,12 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.sendTextMessage() thread running...");
+                    Log.i(TAG, "DRingService.sendTextMessage() thread running...");
                     message.setCallId(callID);
-                    //Conference conf = findConference(callID);
                     mHistoryManager.insertNewTextMessage(new HistoryText(message));
                     StringMap messages  = new StringMap();
                     messages.set("text/plain", message.getMessage());
                     Ringservice.sendTextMessage(callID, messages, "", false);
-                    if (getConferences().get(callID) != null)
-                        getConferences().get(callID).addSipMessage(message);
-                    Intent intent = new Intent(CallManagerCallBack.INCOMING_TEXT);
-                    intent.putExtra("txt", message);
-                    sendBroadcast(intent);
                 }
             });
         }
@@ -1053,7 +927,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.sendAccountTextMessage() thread running... " + accountID + " " + to + " " + msg);
+                    Log.i(TAG, "DRingService.sendAccountTextMessage() thread running... " + accountID + " " + to + " " + msg);
                     TextMessage message = new TextMessage(false, msg, to, null, accountID);
                     mHistoryManager.insertNewTextMessage(new HistoryText(message));
                     Ringservice.sendAccountTextMessage(accountID, to, msg);
@@ -1069,12 +943,12 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<ArrayList<Codec>>() {
                 @Override
                 protected ArrayList<Codec> doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.getAudioCodecList() thread running...");
+                    Log.i(TAG, "DRingService.getAudioCodecList() thread running...");
                     ArrayList<Codec> results = new ArrayList<>();
 
                     UintVect active_payloads = Ringservice.getActiveCodecList(accountID);
                     for (int i = 0; i < active_payloads.size(); ++i) {
-                        Log.i(TAG, "SipService.getCodecDetails(" + accountID +", "+ active_payloads.get(i) +")");
+                        Log.i(TAG, "DRingService.getCodecDetails(" + accountID +", "+ active_payloads.get(i) +")");
                         results.add(new Codec(active_payloads.get(i), Ringservice.getCodecDetails(accountID, active_payloads.get(i)), true));
 
                     }
@@ -1107,7 +981,7 @@
 
                 @Override
                 protected StringMap doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.getRingtoneList() thread running...");
+                    Log.i(TAG, "DRingService.getRingtoneList() thread running...");
                     return Ringservice.getR();
                 }
             }
@@ -1132,7 +1006,7 @@
 
                 @Override
                 protected Boolean doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.isCaptureMuted() thread running...");
+                    Log.i(TAG, "DRingService.isCaptureMuted() thread running...");
                     return Ringservice.sflph_config_check_for_private_key(pemPath);
                 }
             }
@@ -1151,7 +1025,7 @@
 
                 @Override
                 protected Boolean doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.isCaptureMuted() thread running...");
+                    Log.i(TAG, "DRingService.isCaptureMuted() thread running...");
                     return Ringservice.sflph_config_check_certificate_validity(pemPath, pemPath);
                 }
             }
@@ -1170,7 +1044,7 @@
 
                 @Override
                 protected Boolean doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.isCaptureMuted() thread running...");
+                    Log.i(TAG, "DRingService.isCaptureMuted() thread running...");
                     return Ringservice.sflph_config_check_hostname_certificate(host, port);
                 }
             }
@@ -1189,7 +1063,7 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<Map<String, String>>() {
                 @Override
                 protected Map<String, String> doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.validateCertificatePath() thread running...");
+                    Log.i(TAG, "DRingService.validateCertificatePath() thread running...");
                     return Ringservice.validateCertificatePath(accountID, certificatePath, privateKeyPath, "", "").toNative();
                 }
             });
@@ -1200,7 +1074,7 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<Map<String, String>>() {
                 @Override
                 protected Map<String, String> doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.validateCertificate() thread running...");
+                    Log.i(TAG, "DRingService.validateCertificate() thread running...");
                     return Ringservice.validateCertificate(accountID, certificate).toNative();
                 }
             });
@@ -1211,7 +1085,7 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<Map<String, String>>() {
                 @Override
                 protected Map<String, String> doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.getCertificateDetailsPath() thread running...");
+                    Log.i(TAG, "DRingService.getCertificateDetailsPath() thread running...");
                     return Ringservice.getCertificateDetails(certificatePath).toNative();
                 }
             });
@@ -1222,7 +1096,7 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<Map<String, String>>() {
                 @Override
                 protected Map<String, String> doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.getCertificateDetails() thread running...");
+                    Log.i(TAG, "DRingService.getCertificateDetails() thread running...");
                     return Ringservice.getCertificateDetails(certificateRaw).toNative();
                 }
             });
@@ -1233,7 +1107,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.setActiveAudioCodecList() thread running...");
+                    Log.i(TAG, "DRingService.setActiveAudioCodecList() thread running...");
                     UintVect list = new UintVect();
                     for (Object codec : codecs) {
                         list.add((Long) codec);
@@ -1243,41 +1117,26 @@
             });
         }
 
-
-        @Override
-        public Conference getCurrentCall() throws RemoteException {
-            for (Conference conf : mConferences.values()) {
-                if (conf.isIncoming())
-                    return conf;
-            }
-
-            for (Conference conf : mConferences.values()) {
-                if (conf.isOnGoing())
-                    return conf;
-            }
-
-            return null;
-        }
-
         @Override
         public void playDtmf(final String key) throws RemoteException {
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.playDtmf() thread running...");
+                    Log.i(TAG, "DRingService.playDtmf() thread running...");
                     Ringservice.playDTMF(key);
                 }
             });
         }
 
         @Override
-        public List<Conference> getConcurrentCalls() throws RemoteException {
-            return new ArrayList<>(mConferences.values());
-        }
-
-        @Override
-        public Conference getConference(String id) throws RemoteException {
-            return mConferences.get(id);
+        public Map<String, String> getConference(final String id) throws RemoteException {
+            return getExecutor().executeAndReturn(new SipRunnableWithReturn<Map<String, String>>() {
+                @Override
+                protected Map<String, String> doRun() throws SameThreadException {
+                    Log.i(TAG, "DRingService.getCredentials() thread running...");
+                    return Ringservice.getConferenceDetails(id).toNative();
+                }
+            });
         }
 
         @Override
@@ -1285,7 +1144,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.setMuted() thread running...");
+                    Log.i(TAG, "DRingService.setMuted() thread running...");
                     Ringservice.muteCapture(mute);
                 }
             });
@@ -1297,7 +1156,7 @@
 
                 @Override
                 protected Boolean doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.isCaptureMuted() thread running...");
+                    Log.i(TAG, "DRingService.isCaptureMuted() thread running...");
                     return Ringservice.isCaptureMuted();
                 }
             });
@@ -1308,9 +1167,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.confirmSAS() thread running...");
-                    SecureSipCall call = (SecureSipCall) getCallById(callID);
-                    call.setSASConfirmed(true);
+                    Log.i(TAG, "DRingService.confirmSAS() thread running...");
                     Ringservice.setSASVerified(callID);
                 }
             });
@@ -1322,7 +1179,7 @@
             return getExecutor().executeAndReturn(new SipRunnableWithReturn<List<String>>() {
                 @Override
                 protected List<String> doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.getCredentials() thread running...");
+                    Log.i(TAG, "DRingService.getCredentials() thread running...");
                     return SwigNativeConverter.convertSwigToNative(Ringservice.getSupportedTlsMethod());
                 }
             });
@@ -1334,7 +1191,7 @@
 
                 @Override
                 protected List doRun() throws SameThreadException {
-                    Log.i(TAG, "SipService.getCredentials() thread running...");
+                    Log.i(TAG, "DRingService.getCredentials() thread running...");
                     return Ringservice.getCredentials(accountID).toNative();
                 }
             }
@@ -1349,7 +1206,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.setCredentials() thread running...");
+                    Log.i(TAG, "DRingService.setCredentials() thread running...");
                     Ringservice.setCredentials(accountID, SwigNativeConverter.convertFromNativeToSwig(creds));
                 }
             });
@@ -1360,7 +1217,7 @@
             getExecutor().execute(new SipRunnable() {
                 @Override
                 protected void doRun() throws SameThreadException, RemoteException {
-                    Log.i(TAG, "SipService.registerAllAccounts() thread running...");
+                    Log.i(TAG, "DRingService.registerAllAccounts() thread running...");
                     Ringservice.registerAllAccounts();
                 }
             });
@@ -1375,31 +1232,4 @@
         }
 
     };
-
-    private void removeCall(String callID) {
-        Conference conf = findConference(callID);
-        if(conf == null)
-            return;
-        if(conf.getParticipants().size() == 1)
-            getConferences().remove(conf.getId());
-        else
-            conf.removeParticipant(conf.getCallById(callID));
-        Log.w("CallNotification ", "Canceling " + conf.notificationId);
-        mNotificationManager.notificationManager.cancel(conf.notificationId);
-    }
-
-    protected Conference findConference(String callID) {
-        Conference result = getConferences().get(callID);
-        if (result != null)
-            return result;
-        for (Entry<String, Conference> stringConferenceEntry : getConferences().entrySet()) {
-            Conference tmp = stringConferenceEntry.getValue();
-            for (SipCall c : tmp.getParticipants()) {
-                if (c.getCallId() != null && callID.contentEquals(c.getCallId())) {
-                    return tmp;
-                }
-            }
-        }
-        return null;
-    }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/service/ISipService.aidl b/ring-android/app/src/main/java/cx/ring/service/IDRingService.aidl
similarity index 94%
rename from ring-android/app/src/main/java/cx/ring/service/ISipService.aidl
rename to ring-android/app/src/main/java/cx/ring/service/IDRingService.aidl
index bd77ecf..d51a998 100644
--- a/ring-android/app/src/main/java/cx/ring/service/ISipService.aidl
+++ b/ring-android/app/src/main/java/cx/ring/service/IDRingService.aidl
@@ -2,10 +2,11 @@
 
 import cx.ring.model.SipCall;
 import cx.ring.model.TextMessage;
-import cx.ring.model.Conference;
 
-interface ISipService {
-    
+interface IDRingService {
+
+    boolean isStarted();
+
     Map getCallDetails(in String callID);
     String placeCall(in SipCall call);
     void refuse(in String callID);
@@ -83,10 +84,7 @@
     List getParticipantList(in String confID);
     String getConferenceId(in String callID);
     String getConferenceDetails(in String callID);
-    
-    Conference getCurrentCall();
-    List getConcurrentCalls();
 
-    Conference getConference(in String id);
+    Map getConference(in String id);
 
 }
diff --git a/ring-android/app/src/main/java/cx/ring/service/LocalService.java b/ring-android/app/src/main/java/cx/ring/service/LocalService.java
index 3da1a13..1c79d80 100644
--- a/ring-android/app/src/main/java/cx/ring/service/LocalService.java
+++ b/ring-android/app/src/main/java/cx/ring/service/LocalService.java
@@ -46,6 +46,7 @@
 import android.provider.Contacts;
 import android.provider.ContactsContract;
 import android.support.annotation.NonNull;
+import android.support.v4.app.NotificationManagerCompat;
 import android.support.v4.content.ContextCompat;
 import android.util.Log;
 import android.util.LongSparseArray;
@@ -72,10 +73,13 @@
 import cx.ring.model.CallContact;
 import cx.ring.model.Conference;
 import cx.ring.model.Conversation;
+import cx.ring.model.SecureSipCall;
 import cx.ring.model.SipCall;
 import cx.ring.model.SipUri;
 import cx.ring.model.TextMessage;
 import cx.ring.model.account.Account;
+import cx.ring.model.account.AccountDetailSrtp;
+import cx.ring.model.account.AccountDetailTls;
 
 
 public class LocalService extends Service
@@ -90,7 +94,7 @@
 
     public final static String[] REQUIRED_RUNTIME_PERMISSIONS = {Manifest.permission.READ_CONTACTS, Manifest.permission.RECORD_AUDIO};
 
-    private ISipService mService = null;
+    private IDRingService mService = null;
     private final ContactsContentObserver contactContentObserver = new ContactsContentObserver();
 
     // Binder given to clients
@@ -139,13 +143,42 @@
         return isWifiConn;
     }
 
+    public Conference placeCall(SipCall call) {
+        Conference conf = null;
+        CallContact contact = call.getContact();
+        Conversation conv = startConversation(contact);
+        try {
+            String callId = mService.placeCall(call);
+            if (callId == null || callId.isEmpty()) {
+                //CallActivity.this.terminateCall();
+                return null;
+            }
+            call.setCallID(callId);
+            Account acc = getAccount(call.getAccount());
+            if(acc.isRing()
+                    || acc.getSrtpDetails().getDetailBoolean(AccountDetailSrtp.CONFIG_SRTP_ENABLE)
+                    || acc.getTlsDetails().getDetailBoolean(AccountDetailTls.CONFIG_TLS_ENABLE)) {
+                Log.i(TAG, "DRingService.placeCall() call is secure");
+                SecureSipCall secureCall = new SecureSipCall(call, acc.getSrtpDetails().getDetailString(AccountDetailSrtp.CONFIG_SRTP_KEY_EXCHANGE));
+                conf = new Conference(secureCall);
+            } else {
+                conf = new Conference(call);
+            }
+            conf.getParticipants().get(0).setContact(contact);
+            conv.addConference(conf);
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+        return conf;
+    }
+
     public interface Callbacks {
-        ISipService getRemoteService();
+        IDRingService getRemoteService();
         LocalService getService();
     }
     public static class DummyCallbacks implements Callbacks {
         @Override
-        public ISipService getRemoteService() {
+        public IDRingService getRemoteService() {
             return null;
         }
         @Override
@@ -170,7 +203,7 @@
         };
 
         historyManager = new HistoryManager(this);
-        Intent intent = new Intent(this, SipService.class);
+        Intent intent = new Intent(this, DRingService.class);
         startService(intent);
         bindService(intent, mConnection, BIND_AUTO_CREATE | BIND_IMPORTANT | BIND_ABOVE_CLIENT);
 
@@ -220,7 +253,12 @@
             for (CallContact c : data.contacts)
                 systemContactCache.put(c.getId(), c);
 
-            sendBroadcast(new Intent(ACTION_CONF_UPDATE));
+            new ConversationLoader(LocalService.this, systemContactCache){
+                @Override
+                protected void onPostExecute(Map<String, Conversation> res) {
+                    updated(res);
+                }
+            }.execute();
         }
     };
 
@@ -228,12 +266,18 @@
         @Override
         public void onServiceConnected(ComponentName className, IBinder service) {
             Log.w(TAG, "onServiceConnected " + className.getClassName());
-            mService = ISipService.Stub.asInterface(service);
+            mService = IDRingService.Stub.asInterface(service);
             //mBound = true;
             mAccountLoader = new AccountsLoader(LocalService.this);
             mAccountLoader.registerListener(1, onAccountsLoaded);
-            mAccountLoader.startLoading();
-            mAccountLoader.forceLoad();
+            try {
+                if (mService.isStarted()) {
+                    mAccountLoader.startLoading();
+                    mAccountLoader.forceLoad();
+                }
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
 
             mSystemContactLoader = new ContactsLoader(LocalService.this);
             mSystemContactLoader.registerListener(1, onSystemContactsLoaded);
@@ -303,7 +347,7 @@
         return perms.toArray(new String[perms.size()]);
     }
 
-    public ISipService getRemoteService() {
+    public IDRingService getRemoteService() {
         return mService;
     }
 
@@ -674,140 +718,151 @@
         protected Map<String, Conversation> doInBackground(Void... params) {
             List<HistoryCall> history = null;
             List<HistoryText> historyTexts = null;
-            Map<String, Conference> confs = null;
+            Map<String, Map<String, String>> confs = null;
             final Map<String, Conversation> ret = new HashMap<>();
             final HashMap<String, CallContact> localNumberCache = new HashMap<>(64);
 
-
             try {
                 history = historyManager.getAll();
                 historyTexts = historyManager.getAllTextMessages();
                 confs = mService.getConferenceList();
+
+                for (HistoryCall call : history) {
+                    //Log.w(TAG, "History call : " + call.getNumber() + " " + call.call_start + " " + call.call_end + " " + call.getEndDate().toString());
+                    CallContact contact;
+                    if (call.getContactID() <= CallContact.DEFAULT_ID) {
+                        contact = getByNumber(localNumberCache, call.getNumber());
+                    } else {
+                        contact = localContactCache.get(call.getContactID());
+                        if (contact == null) {
+                            contact = findById(cr, call.getContactID());
+                            if (contact != null)
+                                contact.addPhoneNumber(call.getNumber(), 0);
+                            else {
+                                Log.w(TAG, "Can't find contact with id " + call.getContactID());
+                                contact = getByNumber(localNumberCache, call.getNumber());
+                            }
+                            localContactCache.put(contact.getId(), contact);
+                        }
+                    }
+
+                    Map.Entry<String, Conversation> merge = null;
+                    for (Map.Entry<String, Conversation> ce : ret.entrySet()) {
+                        Conversation c = ce.getValue();
+                        if ((contact.getId() > 0 && contact.getId() == c.contact.getId()) || c.contact.hasNumber(call.getNumber())) {
+                            merge = ce;
+                            break;
+                        }
+                    }
+                    if (merge != null) {
+                        Conversation c = merge.getValue();
+                        //Log.w(TAG, "        Join to " + merge.getKey() + " " + c.getContact().getDisplayName() + " " + call.getNumber());
+                        if (c.getContact().getId() <= 0 && contact.getId() > 0) {
+                            c.contact = contact;
+                            ret.remove(merge.getKey());
+                            ret.put(contact.getIds().get(0), c);
+                        }
+                        c.addHistoryCall(call);
+                        continue;
+                    }
+                    String key = contact.getIds().get(0);
+                    if (ret.containsKey(key)) {
+                        ret.get(key).addHistoryCall(call);
+                    } else {
+                        Conversation c = new Conversation(contact);
+                        c.addHistoryCall(call);
+                        ret.put(key, c);
+                    }
+                }
+
+                for (HistoryText htext : historyTexts) {
+                    CallContact contact;
+
+                    if (htext.getContactID() <= CallContact.DEFAULT_ID) {
+                        contact = getByNumber(localNumberCache, htext.getNumber());
+                    } else {
+                        contact = localContactCache.get(htext.getContactID());
+                        if (contact == null) {
+                            contact = findById(cr, htext.getContactID());
+                            if (contact != null)
+                                contact.addPhoneNumber(htext.getNumber(), 0);
+                            else {
+                                Log.w(TAG, "Can't find contact with id " + htext.getContactID());
+                                contact = getByNumber(localNumberCache, htext.getNumber());
+                            }
+                            localContactCache.put(contact.getId(), contact);
+                        }
+                    }
+
+                    Pair<HistoryEntry, HistoryCall> p = findHistoryByCallId(ret, htext.getCallId());
+
+                    if (contact == null && p != null)
+                        contact = p.first.getContact();
+                    if (contact == null)
+                        continue;
+
+                    TextMessage msg = new TextMessage(htext);
+                    msg.setContact(contact);
+
+                    if (p  != null) {
+                        if (msg.getNumber() == null || msg.getNumber().isEmpty())
+                            msg.setNumber(p.second.getNumber());
+                        p.first.addTextMessage(msg);
+                    }
+
+                    String key = contact.getIds().get(0);
+                    if (ret.containsKey(key)) {
+                        ret.get(key).addTextMessage(msg);
+                    } else {
+                        Conversation c = new Conversation(contact);
+                        c.addTextMessage(msg);
+                        ret.put(key, c);
+                    }
+                }
+
+                for (Map.Entry<String, Map<String, String>> c : confs.entrySet()) {
+                    String conf_id = c.getKey();
+                    Map<String, String> conf_details = c.getValue();
+                    List<String> callsIds = mService.getParticipantList(conf_id);
+                    Conference conf = new Conference(conf_id);
+                    for (String callId : callsIds) {
+                        Map<String, String> call_details = mService.getCallDetails(callId);
+                        SipCall call = new SipCall(callId, call_details);
+                        Account acc = getAccount(call.getAccount());
+                        if(acc.isRing()
+                                || acc.getSrtpDetails().getDetailBoolean(AccountDetailSrtp.CONFIG_SRTP_ENABLE)
+                                || acc.getTlsDetails().getDetailBoolean(AccountDetailTls.CONFIG_TLS_ENABLE)) {
+                            Log.i(TAG, "DRingService.placeCall() call is secure");
+                            call = new SecureSipCall(call, acc.getSrtpDetails().getDetailString(AccountDetailSrtp.CONFIG_SRTP_KEY_EXCHANGE));
+                        }
+                        conf.addParticipant(call);
+                    }
+                    List<SipCall> calls = conf.getParticipants();
+                    if (calls.size() == 1) {
+                        SipCall call = calls.get(0);
+                        Conversation conv = null;
+                        String number = call.getNumber();
+                        CallContact contact = findContactByNumber(number);
+                        ArrayList<String> ids = contact.getIds();
+                        for (String id : ids) {
+                            //Log.w(TAG, "    uri attempt : " + id);
+                            conv = ret.get(id);
+                            if (conv != null) break;
+                        }
+                        if (conv != null) {
+                            conv.addConference(conf);
+                        } else {
+                            conv = new Conversation(contact);
+                            conv.addConference(conf);
+                            ret.put(ids.get(0), conv);
+                        }
+                    }
+                }
+                for (Conversation c : ret.values())
+                    Log.w(TAG, "Conversation : " + c.getContact().getId() + " " + c.getContact().getDisplayName() + " " + c.getContact().getPhones().get(0).getNumber() + " " + c.getLastInteraction().toString());
             } catch (RemoteException | SQLException e) {
                 e.printStackTrace();
             }
-
-            for (HistoryCall call : history) {
-                //Log.w(TAG, "History call : " + call.getNumber() + " " + call.call_start + " " + call.call_end + " " + call.getEndDate().toString());
-                CallContact contact;
-                if (call.getContactID() <= CallContact.DEFAULT_ID) {
-                    contact = getByNumber(localNumberCache, call.getNumber());
-                } else {
-                    contact = localContactCache.get(call.getContactID());
-                    if (contact == null) {
-                        contact = findById(cr, call.getContactID());
-                        if (contact != null)
-                            contact.addPhoneNumber(call.getNumber(), 0);
-                        else {
-                            Log.w(TAG, "Can't find contact with id " + call.getContactID());
-                            contact = getByNumber(localNumberCache, call.getNumber());
-                        }
-                        localContactCache.put(contact.getId(), contact);
-                    }
-                }
-
-                Map.Entry<String, Conversation> merge = null;
-                for (Map.Entry<String, Conversation> ce : ret.entrySet()) {
-                    Conversation c = ce.getValue();
-                    if ((contact.getId() > 0 && contact.getId() == c.contact.getId()) || c.contact.hasNumber(call.getNumber())) {
-                        merge = ce;
-                        break;
-                    }
-                }
-                if (merge != null) {
-                    Conversation c = merge.getValue();
-                    //Log.w(TAG, "        Join to " + merge.getKey() + " " + c.getContact().getDisplayName() + " " + call.getNumber());
-                    if (c.getContact().getId() <= 0 && contact.getId() > 0) {
-                        c.contact = contact;
-                        ret.remove(merge.getKey());
-                        ret.put(contact.getIds().get(0), c);
-                    }
-                    c.addHistoryCall(call);
-                    continue;
-                }
-                String key = contact.getIds().get(0);
-                if (ret.containsKey(key)) {
-                    ret.get(key).addHistoryCall(call);
-                } else {
-                    Conversation c = new Conversation(contact);
-                    c.addHistoryCall(call);
-                    ret.put(key, c);
-                }
-            }
-
-            for (HistoryText htext : historyTexts) {
-                CallContact contact;
-
-                if (htext.getContactID() <= CallContact.DEFAULT_ID) {
-                    contact = getByNumber(localNumberCache, htext.getNumber());
-                } else {
-                    contact = localContactCache.get(htext.getContactID());
-                    if (contact == null) {
-                        contact = findById(cr, htext.getContactID());
-                        if (contact != null)
-                            contact.addPhoneNumber(htext.getNumber(), 0);
-                        else {
-                            Log.w(TAG, "Can't find contact with id " + htext.getContactID());
-                            contact = getByNumber(localNumberCache, htext.getNumber());
-                        }
-                        localContactCache.put(contact.getId(), contact);
-                    }
-                }
-
-                Pair<HistoryEntry, HistoryCall> p = findHistoryByCallId(ret, htext.getCallId());
-
-                if (contact == null && p != null)
-                    contact = p.first.getContact();
-                if (contact == null)
-                    continue;
-
-                TextMessage msg = new TextMessage(htext);
-                msg.setContact(contact);
-
-                if (p  != null) {
-                    if (msg.getNumber() == null || msg.getNumber().isEmpty())
-                        msg.setNumber(p.second.getNumber());
-                    p.first.addTextMessage(msg);
-                }
-
-                String key = contact.getIds().get(0);
-                if (ret.containsKey(key)) {
-                    ret.get(key).addTextMessage(msg);
-                } else {
-                    Conversation c = new Conversation(contact);
-                    c.addTextMessage(msg);
-                    ret.put(key, c);
-                }
-            }
-
-            /*context.clear();
-            ctx = null;*/
-            for (Map.Entry<String, Conference> c : confs.entrySet()) {
-                //Log.w(TAG, "ConversationLoader handling " + c.getKey() + " " + c.getValue().getId());
-                Conference conf = c.getValue();
-                ArrayList<SipCall> calls = conf.getParticipants();
-                if (calls.size() >= 1) {
-                    CallContact contact = calls.get(0).getContact();
-                    //Log.w(TAG, "Contact : " + contact.getId() + " " + contact.getDisplayName());
-                    Conversation conv = null;
-                    ArrayList<String> ids = contact.getIds();
-                    for (String id : ids) {
-                        //Log.w(TAG, "    uri attempt : " + id);
-                        conv = ret.get(id);
-                        if (conv != null) break;
-                    }
-                    if (conv != null) {
-                        //Log.w(TAG, "Adding conference to existing conversation ");
-                        conv.current_calls.add(conf);
-                    } else {
-                        conv = new Conversation(contact);
-                        conv.current_calls.add(conf);
-                        ret.put(ids.get(0), conv);
-                    }
-                }
-            }
-            for (Conversation c : ret.values())
-                Log.w(TAG, "Conversation : " + c.getContact().getId() + " " + c.getContact().getDisplayName() + " " + c.getContact().getPhones().get(0).getNumber() + " " + c.getLastInteraction().toString());
             return ret;
         }
     }
@@ -885,17 +940,29 @@
     private final BroadcastReceiver receiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
+            Log.w(TAG, "BroadcastReceiver onReceive " + intent.getAction());
             switch(intent.getAction()) {
+                case DRingService.DRING_CONNECTION_CHANGED: {
+                    boolean connected = intent.getBooleanExtra("connected", false);
+                    if (connected) {
+                        mAccountLoader.onContentChanged();
+                        mAccountLoader.startLoading();
+                        mAccountLoader.forceLoad();
+                    } else {
+                        Log.w(TAG, "DRing connection lost ");
+                    }
+                    break;
+                }
                 case ConnectivityManager.CONNECTIVITY_ACTION:
                     Log.w(TAG, "ConnectivityManager.CONNECTIVITY_ACTION " + " " + intent.getStringExtra(ConnectivityManager.EXTRA_EXTRA_INFO) + " " + intent.getStringExtra(ConnectivityManager.EXTRA_EXTRA_INFO));
                     updateConnectivityState();
                     break;
                 case ConfigurationManagerCallback.ACCOUNT_STATE_CHANGED:
-                    Log.w(TAG, "Received " + intent.getAction() + " " + intent.getStringExtra("Account") + " " + intent.getStringExtra("State") + " " + intent.getIntExtra("code", 0));
+                    Log.w(TAG, "Received " + intent.getAction() + " " + intent.getStringExtra("account") + " " + intent.getStringExtra("state") + " " + intent.getIntExtra("code", 0));
                     //accountStateChanged(intent.getStringExtra("Account"), intent.getStringExtra("State"), intent.getIntExtra("code", 0));
                     for (Account a : accounts) {
-                        if (a.getAccountID().contentEquals(intent.getStringExtra("Account"))) {
-                            a.setRegistrationState(intent.getStringExtra("State"), intent.getIntExtra("code", 0));
+                        if (a.getAccountID().contentEquals(intent.getStringExtra("account"))) {
+                            a.setRegistrationState(intent.getStringExtra("state"), intent.getIntExtra("code", 0));
                             //notifyDataSetChanged();
                             sendBroadcast(new Intent(ACTION_ACCOUNT_UPDATE));
                             break;
@@ -903,24 +970,21 @@
                     }
                     break;
                 case ConfigurationManagerCallback.ACCOUNTS_CHANGED:
-                    Log.w(TAG, "Received" + intent.getAction());
                     //accountsChanged();
                     mAccountLoader.onContentChanged();
                     mAccountLoader.startLoading();
+                    mAccountLoader.forceLoad();
                     break;
                 case CallManagerCallBack.INCOMING_TEXT:
                 case ConfigurationManagerCallback.INCOMING_TEXT: {
                     TextMessage txt = intent.getParcelableExtra("txt");
                     String call = txt.getCallId();
+                    Conversation conv;
                     if (call != null && !call.isEmpty()) {
-                        Conversation conv = getConversationByCallId(call);
+                        conv = getConversationByCallId(call);
                         conv.addTextMessage(txt);
-                        /*Conference conf = conv.getConference(call);
-                        conf.addSipMessage(txt);
-                        Conversation conv = getByContact(conf.)*/
                     } else {
-                        CallContact contact = findContactByNumber(txt.getNumber());
-                        Conversation conv = startConversation(contact);
+                        conv = startConversation(findContactByNumber(txt.getNumber()));
                         txt.setContact(conv.getContact());
                         Log.w(TAG, "New text messsage " + txt.getAccount() + " " + txt.getContact().getId() + " " + txt.getMessage());
                         conv.addTextMessage(txt);
@@ -928,8 +992,75 @@
                     sendBroadcast(new Intent(ACTION_CONF_UPDATE));
                     break;
                 }
+                case CallManagerCallBack.INCOMING_CALL: {
+                    String callId = intent.getStringExtra("call");
+                    String accountId = intent.getStringExtra("account");
+                    String number = intent.getStringExtra("from");
+                    CallContact contact = findContactByNumber(number);
+                    Conversation conv = startConversation(contact);
+
+                    SipCall call = new SipCall(callId, accountId, number, SipCall.Direction.INCOMING);
+                    call.setContact(contact);
+
+                    Account account = getAccount(accountId);
+
+                    Conference toAdd;
+                    if (account.useSecureLayer()) {
+                        SecureSipCall secureCall = new SecureSipCall(call, account.getSrtpDetails().getDetailString(AccountDetailSrtp.CONFIG_SRTP_KEY_EXCHANGE));
+                        toAdd = new Conference(secureCall);
+                    } else {
+                        toAdd = new Conference(call);
+                    }
+
+                    conv.addConference(toAdd);
+                    break;
+                }
+                case CallManagerCallBack.CALL_STATE_CHANGED: {
+                    String callid = intent.getStringExtra("call");
+                    Conversation conversation = null;
+                    Conference found = null;
+
+                    for (Conversation conv : conversations.values()) {
+                        Conference tconf = conv.getConference(callid);
+                        if (tconf != null) {
+                            conversation = conv;
+                            found = tconf;
+                            break;
+                        }
+                    }
+
+                    if (found == null) {
+                        Log.w(TAG, "CALL_STATE_CHANGED : Can't find conference " + callid);
+                    } else {
+                        SipCall call = found.getCallById(callid);
+                        int old_state = call.getCallState();
+                        int new_state = SipCall.stateFromString(intent.getStringExtra("state"));
+
+                        if (new_state != old_state) {
+                            Log.w(TAG, "CALL_STATE_CHANGED : updating call state to " + new_state);
+                            call.setCallState(new_state);
+                        }
+                        if (new_state == SipCall.State.HUNGUP
+                                || new_state == SipCall.State.BUSY
+                                || new_state == SipCall.State.FAILURE
+                                || new_state == SipCall.State.INACTIVE) {
+                            Log.w(TAG, "Removing call and notification " + found.getId());
+                            NotificationManagerCompat notificationManager = NotificationManagerCompat.from(LocalService.this);
+                            notificationManager.cancel(found.notificationId);
+                            found.removeParticipant(call);
+                        }
+                        if (new_state == SipCall.State.HUNGUP) {
+                            call.setTimestampEnd(System.currentTimeMillis());
+                            conversation.addHistoryCall(new HistoryCall(call));
+                        }
+                        if (found.getParticipants().isEmpty()) {
+                            conversation.removeConference(found);
+                        }
+                    }
+                    sendBroadcast(new Intent(ACTION_CONF_UPDATE));
+                    break;
+                }
                 default:
-                    Log.w(TAG, "onReceive " + intent.getAction() + " " + intent.getDataString());
                     new ConversationLoader(context, systemContactCache){
                         @Override
                         protected void onPostExecute(Map<String, Conversation> res) {
@@ -955,6 +1086,9 @@
         }.execute();
 
         IntentFilter intentFilter = new IntentFilter();
+
+        intentFilter.addAction(DRingService.DRING_CONNECTION_CHANGED);
+
         intentFilter.addAction(ConfigurationManagerCallback.ACCOUNT_STATE_CHANGED);
         intentFilter.addAction(ConfigurationManagerCallback.ACCOUNTS_CHANGED);
         intentFilter.addAction(ConfigurationManagerCallback.INCOMING_TEXT);
diff --git a/ring-android/app/src/main/java/cx/ring/utils/MediaManager.java b/ring-android/app/src/main/java/cx/ring/utils/MediaManager.java
index c9b59cb..d3842a4 100644
--- a/ring-android/app/src/main/java/cx/ring/utils/MediaManager.java
+++ b/ring-android/app/src/main/java/cx/ring/utils/MediaManager.java
@@ -31,7 +31,7 @@
 
 package cx.ring.utils;
 
-import cx.ring.service.SipService;
+import cx.ring.service.DRingService;
 
 import android.content.Context;
 import android.media.AudioManager;
@@ -43,14 +43,14 @@
 public class MediaManager implements OnAudioFocusChangeListener, BluetoothWrapper.BluetoothChangeListener {
 
     private static final String TAG = MediaManager.class.getSimpleName();
-    private SipService mService;
+    private DRingService mService;
     private SettingsContentObserver mSettingsContentObserver;
     AudioManager mAudioManager;
     private Ringer ringer;
     //Bluetooth related
     private BluetoothWrapper bluetoothWrapper;
 
-    public MediaManager(SipService aService) {
+    public MediaManager(DRingService aService) {
         mService = aService;
         mSettingsContentObserver = new SettingsContentObserver(mService, new Handler());
         mAudioManager = (AudioManager) aService.getSystemService(Context.AUDIO_SERVICE);
diff --git a/ring-android/app/src/main/java/cx/ring/utils/SettingsContentObserver.java b/ring-android/app/src/main/java/cx/ring/utils/SettingsContentObserver.java
index 018cf28..08e330a 100644
--- a/ring-android/app/src/main/java/cx/ring/utils/SettingsContentObserver.java
+++ b/ring-android/app/src/main/java/cx/ring/utils/SettingsContentObserver.java
@@ -31,7 +31,7 @@
 
 package cx.ring.utils;
 
-import cx.ring.service.SipService;
+import cx.ring.service.DRingService;
 
 import android.content.Context;
 import android.database.ContentObserver;
@@ -41,10 +41,10 @@
 
 public class SettingsContentObserver extends ContentObserver {
     double previousVolume;
-    SipService context;
+    DRingService context;
     private static final String TAG = "Settings";
 
-    public SettingsContentObserver(SipService c, Handler handler) {
+    public SettingsContentObserver(DRingService c, Handler handler) {
         super(handler);
         context=c;  
         AudioManager audio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);