From 4c6d29bc6033c573ac74fa6134ff4b2943158fd2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Adrien=20B=C3=A9raud?= <adrien.beraud@savoirfairelinux.com>
Date: Thu, 19 Nov 2015 18:10:35 -0500
Subject: [PATCH] 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
---
 ring-android/app/src/main/AndroidManifest.xml |   4 +-
 .../ring/client/AccountEditionActivity.java   |   4 +-
 .../java/cx/ring/client/AccountWizard.java    |   4 +-
 .../java/cx/ring/client/CallActivity.java     |  16 +-
 .../cx/ring/client/DetailHistoryActivity.java |  12 +-
 .../java/cx/ring/client/HomeActivity.java     |  10 +-
 .../ring/client/NewConversationActivity.java  |   4 +-
 .../fragments/AccountCreationFragment.java    |   1 -
 .../fragments/AudioManagementFragment.java    |   4 +-
 .../java/cx/ring/fragments/CallFragment.java  |  27 +-
 .../fragments/CallableWrapperFragment.java    |  24 +-
 .../DetailsHistoryEntryFragment.java          |   8 +-
 .../fragments/NestedSettingsFragment.java     |   4 +-
 .../java/cx/ring/loaders/AccountsLoader.java  |   6 +-
 .../cx/ring/loaders/AccountsStateLoader.java  |   6 +-
 .../main/java/cx/ring/model/Conversation.java |  11 +-
 .../src/main/java/cx/ring/model/SipCall.java  | 104 +++--
 .../cx/ring/service/CallManagerCallBack.java  | 280 ++-----------
 .../service/ConfigurationManagerCallback.java |   8 +-
 .../{SipService.java => DRingService.java}    | 396 +++++-------------
 .../{ISipService.aidl => IDRingService.aidl}  |  12 +-
 .../java/cx/ring/service/LocalService.java    | 386 +++++++++++------
 .../main/java/cx/ring/utils/MediaManager.java |   6 +-
 .../ring/utils/SettingsContentObserver.java   |   6 +-
 24 files changed, 556 insertions(+), 787 deletions(-)
 rename ring-android/app/src/main/java/cx/ring/service/{SipService.java => DRingService.java} (72%)
 rename ring-android/app/src/main/java/cx/ring/service/{ISipService.aidl => IDRingService.aidl} (94%)

diff --git a/ring-android/app/src/main/AndroidManifest.xml b/ring-android/app/src/main/AndroidManifest.xml
index 1741a9c26..fa0667cf0 100644
--- a/ring-android/app/src/main/AndroidManifest.xml
+++ b/ring-android/app/src/main/AndroidManifest.xml
@@ -169,10 +169,10 @@ as that of the covered work.
             </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 8e5822b59..d53f4cbca 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.AudioManagementFragment;
 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 @@ public class AccountEditionActivity extends Activity implements LocalService.Cal
     }
 
     @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 931f47b05..3ce8865e7 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.util.Log;
 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 @@ public class AccountWizard extends AppCompatActivity implements LocalService.Cal
     }
 
     @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 9c9a25c61..8a2314b9a 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.CallContact;
 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 @@ public class CallActivity extends AppCompatActivity implements Callbacks, CallFr
 
             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 @@ public class CallActivity extends AppCompatActivity implements Callbacks, CallFr
     }
 
     @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 89625f489..d61628a52 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.DetailsHistoryEntryFragment;
 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 @@ import android.view.MenuItem;
 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 @@ public class DetailHistoryActivity extends Activity implements DetailsHistoryEnt
         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 @@ public class DetailHistoryActivity extends Activity implements DetailsHistoryEnt
     }
 
     @Override
-    public ISipService getService() {
+    public IDRingService getService() {
         return service;
     }
 
@@ -97,7 +97,7 @@ public class DetailHistoryActivity extends Activity implements DetailsHistoryEnt
 
         @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 de2090da9..88cf9b5ba 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.CallContact;
 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 @@ public class HomeActivity extends AppCompatActivity implements LocalService.Call
             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 @@ public class HomeActivity extends AppCompatActivity implements LocalService.Call
             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 @@ public class HomeActivity extends AppCompatActivity implements LocalService.Call
     }
 
     @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 3f6ef596d..440da2893 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 android.widget.SearchView;
 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 @@ public class NewConversationActivity extends Activity implements ContactListFrag
     }
 
     @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 24196665f..07e0d5353 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 java.util.HashMap;
 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 4f90c0055..d41cfe46c 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.AccountDetail;
 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 @@ public class AudioManagementFragment extends PreferenceFragment {
     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 6b29850d8..252de3597 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.support.v7.app.ActionBar;
 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.ConversationActivity;
 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 @@ public class CallFragment extends CallableWrapperFragment implements CallInterfa
                         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 @@ public class CallFragment extends CallableWrapperFragment implements CallInterfa
                             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 @@ public class CallFragment extends CallableWrapperFragment implements CallInterfa
                         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 @@ public class CallFragment extends CallableWrapperFragment implements CallInterfa
             initNormalStateDisplay();
         }
     }
-*/
+
     public void makeTransfer(BubbleContact contact) {
         FragmentManager fm = getFragmentManager();
         editName = TransferDFragment.newInstance();
@@ -925,7 +920,7 @@ public class CallFragment extends CallableWrapperFragment implements CallInterfa
         }
 
     }
-/*
+
     @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 3ea8dcab1..eba28d114 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 @@ public abstract class CallableWrapperFragment extends Fragment implements CallIn
         @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 @@ public abstract class CallableWrapperFragment extends Fragment implements CallIn
         }
 
     }
-}
\ 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 5af66ebef..038b91a0c 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.HistoryCall;
 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 @@ public class DetailsHistoryEntryFragment extends Fragment {
     private static Callbacks sDummyCallbacks = new Callbacks() {
 
         @Override
-        public ISipService getService() {
+        public IDRingService getService() {
             return null;
         }
 
@@ -84,9 +84,9 @@ public class DetailsHistoryEntryFragment extends Fragment {
 
     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 6d192f12b..010895540 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.CredentialsManager;
 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 @@ public class NestedSettingsFragment extends PreferenceFragment {
 
     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 b96b6662c..3c94e0898 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.HashMap;
 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 9f1908b0d..14a40fb3a 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 @@ package cx.ring.loaders;
 
 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 @@ public class AccountsStateLoader extends AsyncTaskLoader<Map<String, String>> {
     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 715dc3e8e..6401f2780 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 @@ public class Conversation extends ContentObservable implements Parcelable
         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 @@ public class Conversation extends ContentObservable implements Parcelable
             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 e17826911..05693b888 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.Parcel;
 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 @@ public class SipCall implements Parcelable {
     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 @@ public class SipCall implements Parcelable {
         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 class SipCall implements Parcelable {
     }
 
     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 class SipCall implements Parcelable {
     }
 
     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 class SipCall implements Parcelable {
     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 c0b1615d9..297f4fb4e 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 @@ public class CallManagerCallBack extends Callback {
     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 @@ public class CallManagerCallBack extends Callback {
     @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 @@ public class CallManagerCallBack extends Callback {
         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 class CallManagerCallBack extends Callback {
     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 @@ public class CallManagerCallBack extends Callback {
         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 class CallManagerCallBack extends Callback {
     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 @@ public class CallManagerCallBack extends Callback {
     @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 class CallManagerCallBack extends Callback {
     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 class CallManagerCallBack extends Callback {
     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 class CallManagerCallBack extends Callback {
     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 class CallManagerCallBack extends Callback {
     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 e852a0d94..dba874d50 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 @@ import cx.ring.model.TextMessage;
 
 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 @@ public class ConfigurationManagerCallback extends ConfigurationCallback {
 
     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 81ed8862c..0842227d1 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.utils.SwigNativeConverter;
 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 @@ public class SipService extends Service {
     };
     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 @@ public class SipService extends Service {
 
         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 @@ public class SipService extends Service {
         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 @@ public class SipService extends Service {
     @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 @@ public class SipService extends Service {
         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 @@ public class SipService extends Service {
         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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
         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 class SipService extends Service {
 
     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 @@ public class SipService extends Service {
      * *********************************
      */
 
-    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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
                         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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
         // 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 @@ public class SipService extends Service {
                 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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
 
                 @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 @@ public class SipService extends Service {
 
                 @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 @@ public class SipService extends Service {
 
                 @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 @@ public class SipService extends Service {
 
                 @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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             });
         }
 
-
-        @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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
 
                 @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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
 
                 @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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
             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 @@ public class SipService extends Service {
         }
 
     };
-
-    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 bd77ecfcf..d51a998ed 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 @@ package cx.ring.service;
 
 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 @@ interface ISipService {
     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 3da1a133d..1c79d80a8 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.os.RemoteException;
 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.loaders.ContactsLoader;
 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 class LocalService extends Service
 
     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 @@ public class LocalService extends Service
         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 @@ public class LocalService extends Service
         };
 
         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 @@ public class LocalService extends Service
             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 @@ public class LocalService extends Service
         @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 @@ public class LocalService extends Service
         return perms.toArray(new String[perms.size()]);
     }
 
-    public ISipService getRemoteService() {
+    public IDRingService getRemoteService() {
         return mService;
     }
 
@@ -674,140 +718,151 @@ public class LocalService extends Service
         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();
-            } 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());
+                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);
                         }
-                        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;
+                    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);
+                    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);
                     }
-                    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());
+                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);
                         }
-                        localContactCache.put(contact.getId(), contact);
                     }
-                }
 
-                Pair<HistoryEntry, HistoryCall> p = findHistoryByCallId(ret, htext.getCallId());
+                    Pair<HistoryEntry, HistoryCall> p = findHistoryByCallId(ret, htext.getCallId());
 
-                if (contact == null && p != null)
-                    contact = p.first.getContact();
-                if (contact == null)
-                    continue;
+                    if (contact == null && p != null)
+                        contact = p.first.getContact();
+                    if (contact == null)
+                        continue;
 
-                TextMessage msg = new TextMessage(htext);
-                msg.setContact(contact);
+                    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);
-                }
+                    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);
+                    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;
+                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);
                     }
-                    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);
+                    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 (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 @@ public class LocalService extends Service
     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 @@ public class LocalService extends Service
                     }
                     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 @@ public class LocalService extends Service
                     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 @@ public class LocalService extends Service
         }.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 c9b59cb16..d3842a494 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 @@ import cx.ring.utils.bluetooth.BluetoothWrapper;
 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 018cf28b6..08e330aaa 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 @@ import android.util.Log;
 
 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);
-- 
GitLab