calls: add conference support

Change-Id: Ib72f0fa032a19aca867e155ade3df114854bae19
diff --git a/ring-android/app/build.gradle b/ring-android/app/build.gradle
index 4a259cf..f1015d6 100644
--- a/ring-android/app/build.gradle
+++ b/ring-android/app/build.gradle
@@ -78,7 +78,7 @@
 
     implementation "androidx.core:core:1.2.0-beta01"
     implementation "androidx.appcompat:appcompat:$android_support_core_version"
-    implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta2'
+    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
     implementation "androidx.legacy:legacy-support-core-utils:$android_support_version"
     implementation "androidx.cardview:cardview:$android_support_version"
     implementation "androidx.preference:preference:$android_support_core_version"
@@ -87,6 +87,7 @@
     implementation "androidx.leanback:leanback-preference:1.1.0-alpha02"
     implementation "androidx.media:media:$android_support_core_version"
     implementation "com.google.android.material:material:$material_version"
+    implementation 'com.google.android:flexbox:1.1.1'
 
     // ORM
     implementation 'com.j256.ormlite:ormlite-android:5.1'
diff --git a/ring-android/app/src/main/AndroidManifest.xml b/ring-android/app/src/main/AndroidManifest.xml
index 8d39124..a64bf27 100644
--- a/ring-android/app/src/main/AndroidManifest.xml
+++ b/ring-android/app/src/main/AndroidManifest.xml
@@ -139,7 +139,7 @@
 
             <meta-data
                 android:name="android.service.chooser.chooser_target_service"
-                android:value=".services.RingChooserTargetService" />
+                android:value=".services.JamiChooserTargetService" />
         </activity>
         <activity
             android:name=".account.AccountWizardActivity"
@@ -342,7 +342,7 @@
             android:theme="@style/AppThemeBase.Dark" />
 
         <service
-            android:name=".services.RingChooserTargetService"
+            android:name=".services.JamiChooserTargetService"
             android:label="ChooserTargetService"
             android:permission="android.permission.BIND_CHOOSER_TARGET_SERVICE">
             <intent-filter>
diff --git a/ring-android/app/src/main/java/cx/ring/about/AboutFragment.java b/ring-android/app/src/main/java/cx/ring/about/AboutFragment.java
index fce4e44..c226b90 100644
--- a/ring-android/app/src/main/java/cx/ring/about/AboutFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/about/AboutFragment.java
@@ -38,7 +38,7 @@
 import cx.ring.BuildConfig;
 import cx.ring.R;
 import cx.ring.client.HomeActivity;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.mvp.BaseSupportFragment;
 import cx.ring.mvp.RootPresenter;
 
@@ -53,7 +53,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
     }
 
     @Override
diff --git a/ring-android/app/src/main/java/cx/ring/account/AccountEditionActivity.java b/ring-android/app/src/main/java/cx/ring/account/AccountEditionActivity.java
index d235f98..05531c2 100644
--- a/ring-android/app/src/main/java/cx/ring/account/AccountEditionActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/account/AccountEditionActivity.java
@@ -51,7 +51,7 @@
 import butterknife.BindView;
 import butterknife.ButterKnife;
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.contactrequests.BlackListFragment;
 import cx.ring.fragments.AdvancedAccountFragment;
 import cx.ring.fragments.GeneralAccountFragment;
@@ -89,7 +89,7 @@
         ButterKnife.bind(this);
 
         // dependency injection
-        RingApplication.getInstance().getRingInjectionComponent().inject(this);
+        JamiApplication.getInstance().getRingInjectionComponent().inject(this);
         mEditionPresenter.bindView(this);
         String accountId = getIntent().getData().getLastPathSegment();
         mEditionPresenter.init(accountId);
diff --git a/ring-android/app/src/main/java/cx/ring/account/AccountWizardActivity.java b/ring-android/app/src/main/java/cx/ring/account/AccountWizardActivity.java
index f980d2c..81260de 100644
--- a/ring-android/app/src/main/java/cx/ring/account/AccountWizardActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/account/AccountWizardActivity.java
@@ -25,7 +25,6 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
-import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Bundle;
 
@@ -34,7 +33,6 @@
 import android.text.TextUtils;
 import android.widget.Toast;
 
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 
 import androidx.fragment.app.Fragment;
@@ -44,7 +42,7 @@
 
 import butterknife.ButterKnife;
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.client.HomeActivity;
 import cx.ring.fragments.AccountMigrationFragment;
 import cx.ring.fragments.SIPAccountCreationFragment;
@@ -55,12 +53,6 @@
 import cx.ring.utils.Log;
 import cx.ring.utils.VCardUtils;
 import ezvcard.VCard;
-import ezvcard.parameter.ImageType;
-import ezvcard.property.FormattedName;
-import ezvcard.property.Photo;
-import ezvcard.property.RawProperty;
-import ezvcard.property.Uid;
-import io.reactivex.Observable;
 import io.reactivex.Single;
 import io.reactivex.schedulers.Schedulers;
 
@@ -74,10 +66,10 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         // dependency injection
-        RingApplication.getInstance().getRingInjectionComponent().inject(this);
+        JamiApplication.getInstance().getRingInjectionComponent().inject(this);
         super.onCreate(savedInstanceState);
 
-        RingApplication.getInstance().startDaemon();
+        JamiApplication.getInstance().startDaemon();
 
         setContentView(R.layout.activity_wizard);
         ButterKnife.bind(this);
diff --git a/ring-android/app/src/main/java/cx/ring/account/HomeAccountCreationFragment.java b/ring-android/app/src/main/java/cx/ring/account/HomeAccountCreationFragment.java
index eca125a..30f514b 100644
--- a/ring-android/app/src/main/java/cx/ring/account/HomeAccountCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/account/HomeAccountCreationFragment.java
@@ -23,7 +23,6 @@
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
-import android.util.Log;
 import android.view.View;
 import android.widget.Button;
 
@@ -32,17 +31,13 @@
 
 import com.google.android.material.snackbar.Snackbar;
 
-import java.io.File;
-import java.io.IOException;
-
 import butterknife.BindView;
 import butterknife.OnClick;
 import cx.ring.R;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.mvp.BaseSupportFragment;
 import cx.ring.utils.AndroidFileUtils;
 import io.reactivex.android.schedulers.AndroidSchedulers;
-import io.reactivex.schedulers.Schedulers;
 
 public class HomeAccountCreationFragment extends BaseSupportFragment<HomeAccountCreationPresenter> implements HomeAccountCreationView {
     private static final int ARCHIVE_REQUEST_CODE = 42;
@@ -61,7 +56,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/account/JamiAccountConnectFragment.java b/ring-android/app/src/main/java/cx/ring/account/JamiAccountConnectFragment.java
index 42488f9..36a6b3b 100644
--- a/ring-android/app/src/main/java/cx/ring/account/JamiAccountConnectFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/account/JamiAccountConnectFragment.java
@@ -21,8 +21,6 @@
 
 import android.app.Activity;
 import android.text.Editable;
-import android.view.View;
-import android.view.ViewGroup;
 import android.view.inputmethod.EditorInfo;
 import android.widget.Button;
 import android.widget.EditText;
@@ -32,7 +30,7 @@
 import butterknife.OnEditorAction;
 import butterknife.OnTextChanged;
 import cx.ring.R;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.mvp.AccountCreationModel;
 import cx.ring.mvp.BaseSupportFragment;
 
@@ -66,7 +64,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/account/ProfileCreationFragment.java b/ring-android/app/src/main/java/cx/ring/account/ProfileCreationFragment.java
index 0d943f2..a1f8331 100644
--- a/ring-android/app/src/main/java/cx/ring/account/ProfileCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/account/ProfileCreationFragment.java
@@ -46,7 +46,7 @@
 import butterknife.OnClick;
 import butterknife.OnTextChanged;
 import cx.ring.R;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.model.Account;
 import cx.ring.mvp.AccountCreationModel;
 import cx.ring.mvp.BaseSupportFragment;
@@ -93,7 +93,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/account/RegisterNameDialog.java b/ring-android/app/src/main/java/cx/ring/account/RegisterNameDialog.java
index b233409..a87ce10 100644
--- a/ring-android/app/src/main/java/cx/ring/account/RegisterNameDialog.java
+++ b/ring-android/app/src/main/java/cx/ring/account/RegisterNameDialog.java
@@ -43,7 +43,7 @@
 import butterknife.ButterKnife;
 import butterknife.OnEditorAction;
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.services.AccountService;
 import cx.ring.utils.RegisteredNameFilter;
 import cx.ring.utils.RegisteredNameTextWatcher;
@@ -122,7 +122,7 @@
         ButterKnife.bind(this, view);
 
         // dependency injection
-        ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
 
         String accountId = "";
         boolean hasPassword = true;
diff --git a/ring-android/app/src/main/java/cx/ring/account/RingAccountCreationFragment.java b/ring-android/app/src/main/java/cx/ring/account/RingAccountCreationFragment.java
index 05a2231..d23c5a5 100644
--- a/ring-android/app/src/main/java/cx/ring/account/RingAccountCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/account/RingAccountCreationFragment.java
@@ -45,7 +45,7 @@
 import butterknife.OnEditorAction;
 import butterknife.OnTextChanged;
 import cx.ring.R;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.mvp.AccountCreationModel;
 import cx.ring.mvp.BaseSupportFragment;
 import cx.ring.utils.RegisteredNameFilter;
@@ -103,7 +103,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/account/RingAccountSummaryFragment.java b/ring-android/app/src/main/java/cx/ring/account/RingAccountSummaryFragment.java
index 50ba435..d19a5e3 100644
--- a/ring-android/app/src/main/java/cx/ring/account/RingAccountSummaryFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/account/RingAccountSummaryFragment.java
@@ -34,7 +34,6 @@
 import com.google.android.material.textfield.TextInputLayout;
 
 import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
 import androidx.appcompat.widget.SwitchCompat;
 
 import android.text.Layout;
@@ -63,7 +62,7 @@
 import butterknife.OnClick;
 import butterknife.OnEditorAction;
 import cx.ring.R;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.interfaces.BackHandlerInterface;
 import cx.ring.model.Account;
 import cx.ring.mvp.BaseSupportFragment;
@@ -426,7 +425,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/account/RingLinkAccountFragment.java b/ring-android/app/src/main/java/cx/ring/account/RingLinkAccountFragment.java
index f924e59..2d76156 100644
--- a/ring-android/app/src/main/java/cx/ring/account/RingLinkAccountFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/account/RingLinkAccountFragment.java
@@ -32,7 +32,7 @@
 import butterknife.OnEditorAction;
 import butterknife.OnTextChanged;
 import cx.ring.R;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.mvp.BaseSupportFragment;
 import cx.ring.mvp.AccountCreationModel;
 
@@ -69,7 +69,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/adapters/RingtoneAdapter.java b/ring-android/app/src/main/java/cx/ring/adapters/RingtoneAdapter.java
index eb49f03..1fba582 100644
--- a/ring-android/app/src/main/java/cx/ring/adapters/RingtoneAdapter.java
+++ b/ring-android/app/src/main/java/cx/ring/adapters/RingtoneAdapter.java
@@ -52,8 +52,6 @@
     private Subject<Ringtone> ringtoneSubject = PublishSubject.create();
 
     class RingtoneViewHolder extends RecyclerView.ViewHolder {
-
-
         private TextView name;
         private ImageView isSelected, isPlaying, ringtoneIcon;
 
diff --git a/ring-android/app/src/main/java/cx/ring/application/RingApplication.java b/ring-android/app/src/main/java/cx/ring/application/JamiApplication.java
similarity index 92%
rename from ring-android/app/src/main/java/cx/ring/application/RingApplication.java
rename to ring-android/app/src/main/java/cx/ring/application/JamiApplication.java
index 0e02f77..ff8564d 100644
--- a/ring-android/app/src/main/java/cx/ring/application/RingApplication.java
+++ b/ring-android/app/src/main/java/cx/ring/application/JamiApplication.java
@@ -46,22 +46,20 @@
 import javax.inject.Named;
 
 import androidx.annotation.RequiresApi;
-import androidx.appcompat.app.AppCompatDelegate;
 
 import cx.ring.BuildConfig;
 import cx.ring.R;
 import cx.ring.contacts.AvatarFactory;
 import cx.ring.daemon.Ringservice;
-import cx.ring.dependencyinjection.DaggerRingInjectionComponent;
-import cx.ring.dependencyinjection.RingInjectionComponent;
-import cx.ring.dependencyinjection.RingInjectionModule;
+import cx.ring.dependencyinjection.DaggerJamiInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionModule;
 import cx.ring.dependencyinjection.ServiceInjectionModule;
 import cx.ring.facades.ConversationFacade;
 import cx.ring.service.DRingService;
 import cx.ring.service.RingJobService;
 import cx.ring.services.AccountService;
 import cx.ring.services.CallService;
-import cx.ring.services.ConferenceService;
 import cx.ring.services.ContactService;
 import cx.ring.services.DaemonService;
 import cx.ring.services.DeviceRuntimeService;
@@ -72,12 +70,12 @@
 import io.reactivex.plugins.RxJavaPlugins;
 import io.reactivex.schedulers.Schedulers;
 
-public abstract class RingApplication extends Application {
-    private static final String TAG = RingApplication.class.getSimpleName();
+public abstract class JamiApplication extends Application {
+    private static final String TAG = JamiApplication.class.getSimpleName();
     public static final String DRING_CONNECTION_CHANGED = BuildConfig.APPLICATION_ID + ".event.DRING_CONNECTION_CHANGE";
     public static final int PERMISSIONS_REQUEST = 57;
     private static final IntentFilter RINGER_FILTER = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
-    private static RingApplication sInstance = null;
+    private static JamiApplication sInstance = null;
 
     @Inject
     @Named("DaemonExecutor")
@@ -88,8 +86,8 @@
     AccountService mAccountService;
     @Inject
     CallService mCallService;
-    @Inject
-    ConferenceService mConferenceService;
+    //@Inject
+    //ConferenceService mConferenceService;
     @Inject
     HardwareService mHardwareService;
     @Inject
@@ -101,7 +99,7 @@
     @Inject
     ConversationFacade mConversationFacade;
 
-    private RingInjectionComponent mRingInjectionComponent;
+    private JamiInjectionComponent mJamiInjectionComponent;
     private final Map<String, Boolean> mPermissionsBeingAsked = new HashMap<>();;
     private final BroadcastReceiver ringerModeListener = new BroadcastReceiver() {
         @Override
@@ -234,13 +232,13 @@
         RxJavaPlugins.setErrorHandler(e -> Log.e(TAG, "Unhandled RxJava error", e));
 
         // building injection dependency tree
-        mRingInjectionComponent = DaggerRingInjectionComponent.builder()
-                .ringInjectionModule(new RingInjectionModule(this))
+        mJamiInjectionComponent = DaggerJamiInjectionComponent.builder()
+                .jamiInjectionModule(new JamiInjectionModule(this))
                 .serviceInjectionModule(new ServiceInjectionModule(this))
                 .build();
 
         // we can now inject in our self whatever modules define
-        mRingInjectionComponent.inject(this);
+        mJamiInjectionComponent.inject(this);
 
         bootstrapDaemon();
 
@@ -259,7 +257,6 @@
         })
         .subscribeOn(Schedulers.io())
         .subscribe();
-
     }
 
     public void startDaemon() {
@@ -288,7 +285,7 @@
         }
     }
 
-    public static RingApplication getInstance() {
+    public static JamiApplication getInstance() {
         return sInstance;
     }
 
@@ -301,8 +298,8 @@
         sInstance = null;
     }
 
-    public RingInjectionComponent getRingInjectionComponent() {
-        return mRingInjectionComponent;
+    public JamiInjectionComponent getRingInjectionComponent() {
+        return mJamiInjectionComponent;
     }
 
     public boolean canAskForPermission(String permission) {
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 526488f..2dbb022 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
@@ -21,22 +21,23 @@
  */
 package cx.ring.client;
 
+import android.app.ActionBar;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.media.AudioManager;
 import android.os.Build;
 import android.os.Bundle;
+
 import androidx.appcompat.app.AppCompatActivity;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.WindowManager;
 
 import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentTransaction;
+
 import cx.ring.BuildConfig;
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.call.CallView;
 import cx.ring.fragments.CallFragment;
 import cx.ring.fragments.ConversationFragment;
@@ -59,7 +60,7 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        RingApplication.getInstance().startDaemon();
+        JamiApplication.getInstance().startDaemon();
 
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
             setTurnScreenOn(true);
@@ -85,10 +86,8 @@
         });
 
         Intent intent = getIntent();
-
         if(intent != null)
             handleNewIntent(intent);
-
     }
 
     @Override
diff --git a/ring-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.java b/ring-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.java
index 2c6359e..568f97e 100644
--- a/ring-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.java
@@ -40,7 +40,6 @@
 
 import android.util.Log;
 import android.view.LayoutInflater;
-import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Toast;
 
@@ -54,7 +53,7 @@
 import androidx.databinding.DataBindingUtil;
 import androidx.recyclerview.widget.RecyclerView;
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.databinding.ActivityContactDetailsBinding;
 import cx.ring.databinding.ItemContactActionBinding;
 import cx.ring.facades.ConversationFacade;
@@ -66,6 +65,8 @@
 import cx.ring.model.SipCall;
 import cx.ring.services.AccountService;
 import cx.ring.services.NotificationService;
+import cx.ring.utils.ContentUriHandler;
+import cx.ring.utils.ConversationPath;
 import cx.ring.views.AvatarDrawable;
 import io.reactivex.android.schedulers.AndroidSchedulers;
 import io.reactivex.disposables.CompositeDisposable;
@@ -171,7 +172,7 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         binding = DataBindingUtil.setContentView(this, R.layout.activity_contact_details);
-        RingApplication.getInstance().getRingInjectionComponent().inject(this);
+        JamiApplication.getInstance().getRingInjectionComponent().inject(this);
 
         CollapsingToolbarLayout collapsingToolbarLayout = findViewById(R.id.toolbar_layout);
         collapsingToolbarLayout.setTitle("");
@@ -297,10 +298,6 @@
     }
 
     private void goToConversationActivity(String accountId, String contactRingId) {
-        Intent intent = new Intent(Intent.ACTION_VIEW)
-                .setClass(getApplicationContext(), ConversationActivity.class)
-                .putExtra(ConversationFragment.KEY_ACCOUNT_ID, accountId)
-                .putExtra(ConversationFragment.KEY_CONTACT_RING_ID, contactRingId);
-        startActivity(intent, null);
+        startActivity(new Intent(Intent.ACTION_VIEW, ConversationPath.toUri(accountId, contactRingId), getApplicationContext(), ConversationActivity.class));
     }
 }
diff --git a/ring-android/app/src/main/java/cx/ring/client/ConversationActivity.java b/ring-android/app/src/main/java/cx/ring/client/ConversationActivity.java
index 08dba9b..16fc2e2 100644
--- a/ring-android/app/src/main/java/cx/ring/client/ConversationActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/client/ConversationActivity.java
@@ -31,6 +31,7 @@
 import android.widget.ImageButton;
 
 import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
 import androidx.appcompat.app.ActionBar;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.appcompat.view.menu.ActionMenuItemView;
@@ -44,9 +45,10 @@
 import butterknife.BindView;
 import butterknife.ButterKnife;
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.fragments.ConversationFragment;
 import cx.ring.interfaces.Colorable;
+import cx.ring.utils.ConversationPath;
 import cx.ring.utils.MediaButtonsHelper;
 
 public class ConversationActivity extends AppCompatActivity implements Colorable {
@@ -57,8 +59,9 @@
     Toolbar mToolbar;
 
     private ConversationFragment mConversationFragment;
-    private String contactUri = null;
-    private String accountId = null;
+    /*private String contactUri = null;
+    private String accountId = null;*/
+    private ConversationPath conversationPath = null;
 
     private Intent mPendingIntent = null;
 
@@ -66,7 +69,7 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        RingApplication.getInstance().startDaemon();
+        JamiApplication.getInstance().startDaemon();
 
         setContentView(R.layout.activity_conversation);
         ButterKnife.bind(this);
@@ -95,19 +98,13 @@
         String action = intent == null ? null : intent.getAction();
 
         if (intent != null) {
-            contactUri = intent.getStringExtra(ConversationFragment.KEY_CONTACT_RING_ID);
-            accountId = intent.getStringExtra(ConversationFragment.KEY_ACCOUNT_ID);
+            conversationPath = ConversationPath.fromIntent(intent);
         } else if (savedInstanceState != null) {
-            contactUri = savedInstanceState.getString(ConversationFragment.KEY_CONTACT_RING_ID);
-            accountId = savedInstanceState.getString(ConversationFragment.KEY_ACCOUNT_ID);
+            conversationPath = ConversationPath.fromBundle(savedInstanceState);
         }
         if (mConversationFragment == null) {
-            Bundle bundle = new Bundle();
-            bundle.putString(ConversationFragment.KEY_CONTACT_RING_ID, contactUri);
-            bundle.putString(ConversationFragment.KEY_ACCOUNT_ID, accountId);
-
             mConversationFragment = new ConversationFragment();
-            mConversationFragment.setArguments(bundle);
+            mConversationFragment.setArguments(conversationPath.toBundle());
             getSupportFragmentManager().beginTransaction()
                     .replace(R.id.main_frame, mConversationFragment, null)
                     .commit();
@@ -118,7 +115,7 @@
     }
 
     @Override
-    public void onContextMenuClosed(Menu menu) {
+    public void onContextMenuClosed(@NonNull Menu menu) {
         mConversationFragment.updateAdapterItem();
         super.onContextMenuClosed(menu);
     }
@@ -144,9 +141,8 @@
     }
 
     @Override
-    protected void onSaveInstanceState(Bundle outState) {
-        outState.putString(ConversationFragment.KEY_CONTACT_RING_ID, contactUri);
-        outState.putString(ConversationFragment.KEY_ACCOUNT_ID, accountId);
+    protected void onSaveInstanceState(@NonNull Bundle outState) {
+        conversationPath.toBundle(outState);
         super.onSaveInstanceState(outState);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/client/ConversationSelectionActivity.java b/ring-android/app/src/main/java/cx/ring/client/ConversationSelectionActivity.java
new file mode 100644
index 0000000..4ad662e
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/client/ConversationSelectionActivity.java
@@ -0,0 +1,149 @@
+/*
+ *  Copyright (C) 2004-2019 Savoir-faire Linux Inc.
+ *
+ *  Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package cx.ring.client;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.TextUtils;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import cx.ring.R;
+import cx.ring.adapters.SmartListAdapter;
+import cx.ring.application.JamiApplication;
+import cx.ring.facades.ConversationFacade;
+import cx.ring.fragments.CallFragment;
+import cx.ring.model.Account;
+import cx.ring.model.Conference;
+import cx.ring.model.SipCall;
+import cx.ring.services.CallService;
+import cx.ring.smartlist.SmartListViewModel;
+import cx.ring.utils.ConversationPath;
+import cx.ring.viewholders.SmartListViewHolder;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.CompositeDisposable;
+
+public class ConversationSelectionActivity extends AppCompatActivity {
+    private final static String TAG = ConversationSelectionActivity.class.getSimpleName();
+
+    private CompositeDisposable mDisposable = new CompositeDisposable();
+
+    @Inject
+    @Singleton
+    ConversationFacade mConversationFacade;
+
+    @Inject
+    @Singleton
+    CallService mCallService;
+
+    private SmartListAdapter adapter;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        JamiApplication.getInstance().getRingInjectionComponent().inject(this);
+        setContentView(R.layout.frag_selectconv);
+        RecyclerView list = findViewById(R.id.conversationList);
+
+        /*Toolbar toolbar = findViewById(R.id.toolbar);
+        setSupportActionBar(toolbar);
+        ActionBar ab = getSupportActionBar();
+        if (ab != null)
+            ab.setDisplayHomeAsUpEnabled(true);*/
+
+        adapter = new SmartListAdapter(null, new SmartListViewHolder.SmartListListeners() {
+            @Override
+            public void onItemClick(SmartListViewModel smartListViewModel) {
+                Intent intent = new Intent();
+                intent.setData(ConversationPath.toUri(smartListViewModel.getAccountId(), smartListViewModel.getContact().getPrimaryNumber()));
+                setResult(Activity.RESULT_OK, intent);
+                finish();
+            }
+
+            @Override
+            public void onItemLongClick(SmartListViewModel smartListViewModel) {
+            }
+        });
+        list.setLayoutManager(new LinearLayoutManager(this));
+        list.setAdapter(adapter);
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        Conference conference = null;
+        Intent intent = getIntent();
+        if (intent != null) {
+            String confId = intent.getStringExtra(CallFragment.KEY_CONF_ID);
+            if (!TextUtils.isEmpty(confId)) {
+                conference = mCallService.getConference(confId);
+            }
+        }
+
+        final Conference conf = conference;
+        mDisposable.add(mConversationFacade
+                .getCurrentAccountSubject()
+                .switchMap(Account::getConversationsViewModels)
+                .map(vm -> {
+                    if (conf == null)
+                        return vm;
+                    List<SmartListViewModel> filteredVms = new ArrayList<>(vm.size());
+                    models: for (SmartListViewModel v : vm) {
+                        for (SipCall call : conf.getParticipants()) {
+                            if (call.getContact() == v.getContact()) {
+                                continue models;
+                            }
+                        }
+                        filteredVms.add(v);
+                    }
+                    return filteredVms;
+                })
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(list -> {
+                    if (adapter != null)
+                        adapter.update(list);
+                }));
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+        mDisposable.clear();
+    }
+
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        adapter = null;
+    }
+}
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 99fecce..812dbb3 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
@@ -29,7 +29,6 @@
 import com.google.android.material.appbar.CollapsingToolbarLayout;
 import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 import com.google.android.material.floatingactionbutton.FloatingActionButton;
-import com.google.android.material.navigation.NavigationView;
 
 import androidx.annotation.NonNull;
 import androidx.coordinatorlayout.widget.CoordinatorLayout;
@@ -40,7 +39,6 @@
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.appcompat.widget.Toolbar;
 
-import android.text.TextUtils;
 import android.util.Log;
 import android.view.MenuItem;
 import android.view.View;
@@ -58,7 +56,7 @@
 import cx.ring.R;
 import cx.ring.about.AboutFragment;
 import cx.ring.account.AccountWizardActivity;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.contactrequests.ContactRequestsFragment;
 import cx.ring.fragments.AccountsManagementFragment;
 import cx.ring.fragments.ConversationFragment;
@@ -66,20 +64,19 @@
 import cx.ring.interfaces.Colorable;
 import cx.ring.model.Account;
 import cx.ring.model.AccountConfig;
-import cx.ring.navigation.RingNavigationFragment;
+import cx.ring.navigation.HomeNavigationFragment;
 import cx.ring.service.DRingService;
 import cx.ring.services.AccountService;
-import cx.ring.services.DeviceRuntimeService;
-import cx.ring.services.HardwareService;
 import cx.ring.services.NotificationService;
-import cx.ring.services.PreferencesService;
 import cx.ring.settings.SettingsFragment;
 import cx.ring.settings.VideoSettingsFragment;
+import cx.ring.utils.ConversationPath;
 import cx.ring.utils.DeviceUtils;
 import io.reactivex.android.schedulers.AndroidSchedulers;
 import io.reactivex.disposables.CompositeDisposable;
 
-public class HomeActivity extends AppCompatActivity implements RingNavigationFragment.OnNavigationSectionSelected, Colorable {
+public class HomeActivity extends AppCompatActivity implements HomeNavigationFragment.OnNavigationSectionSelected, Colorable {
+    static final String TAG = HomeActivity.class.getSimpleName();
 
     public static final int REQUEST_CODE_CALL = 3;
     public static final int REQUEST_CODE_CONVERSATION = 4;
@@ -88,34 +85,24 @@
     public static final int REQUEST_CODE_QR_CONVERSATION = 7;
     public static final int REQUEST_PERMISSION_CAMERA = 113;
     public static final int REQUEST_PERMISSION_READ_STORAGE = 114;
+
     public static final String HOME_TAG = "Home";
     public static final String CONTACT_REQUESTS_TAG = "Trust request";
     public static final String ACCOUNTS_TAG = "Accounts";
     public static final String ABOUT_TAG = "About";
     public static final String SETTINGS_TAG = "Prefs";
     public static final String VIDEO_SETTINGS_TAG = "VideoPrefs";
-    static public final String ACTION_PRESENT_TRUST_REQUEST_FRAGMENT = BuildConfig.APPLICATION_ID + "presentTrustRequestFragment";
-    static final String TAG = HomeActivity.class.getSimpleName();
+    public static final String ACTION_PRESENT_TRUST_REQUEST_FRAGMENT = BuildConfig.APPLICATION_ID + "presentTrustRequestFragment";
     private static final String NAVIGATION_TAG = "Navigation";
+
     protected Fragment fContent;
-    protected RingNavigationFragment fNavigation;
+    protected HomeNavigationFragment fNavigation;
     protected ConversationFragment fConversation;
 
     @Inject
-    DeviceRuntimeService mDeviceRuntimeService;
-
-    @Inject
-    PreferencesService mPreferencesService;
-
-    @Inject
-    HardwareService mHardwareService;
-
-    @Inject
     AccountService mAccountService;
     @Inject
     NotificationService mNotificationService;
-    @BindView(R.id.left_drawer)
-    NavigationView mNavigationView;
     @BindView(R.id.drawer_layout)
     DrawerLayout mNavigationDrawer;
 
@@ -150,20 +137,20 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        RingApplication.getInstance().startDaemon();
+        JamiApplication.getInstance().startDaemon();
         mToolbarSize = getResources().getDimension(R.dimen.abc_action_bar_default_height_material);
         mToolbarElevation = getResources().getDimension(R.dimen.toolbar_elevation);
         FragmentManager fragmentManager = getSupportFragmentManager();
 
         if (savedInstanceState != null) {
-            fNavigation = (RingNavigationFragment) fragmentManager.findFragmentByTag(NAVIGATION_TAG);
+            fNavigation = (HomeNavigationFragment) fragmentManager.findFragmentByTag(NAVIGATION_TAG);
         }
         setContentView(R.layout.activity_home);
 
         ButterKnife.bind(this);
 
         // dependency injection
-        RingApplication.getInstance().getRingInjectionComponent().inject(this);
+        JamiApplication.getInstance().getRingInjectionComponent().inject(this);
 
         setSupportActionBar(mToolbar);
 
@@ -203,7 +190,7 @@
         }
 
         if (fNavigation == null && savedInstanceState == null) {
-            fNavigation = new RingNavigationFragment();
+            fNavigation = new HomeNavigationFragment();
             fragmentManager.beginTransaction()
                     .replace(R.id.navigation_container, fNavigation, NAVIGATION_TAG)
                     .commit();
@@ -252,9 +239,7 @@
         if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
             Bundle extra = intent.getExtras();
             if (extra != null) {
-                String accountId = extra.getString(ConversationFragment.KEY_ACCOUNT_ID);
-                String uri = extra.getString(ConversationFragment.KEY_CONTACT_RING_ID);
-                if (!TextUtils.isEmpty(accountId) && !TextUtils.isEmpty(uri)) {
+                if (ConversationPath.fromBundle(extra) != null) {
                     intent.setClass(this, ConversationActivity.class);
                     startActivity(intent);
                 }
@@ -283,8 +268,8 @@
         }
 
         if (!getSupportFragmentManager().findFragmentByTag(HOME_TAG).isVisible()) {
-            fNavigation.selectSection(RingNavigationFragment.Section.HOME);
-            onNavigationSectionSelected(RingNavigationFragment.Section.HOME);
+            fNavigation.selectSection(HomeNavigationFragment.Section.HOME);
+            onNavigationSectionSelected(HomeNavigationFragment.Section.HOME);
         }
         if (fContent instanceof SmartListFragment) {
             Bundle bundle = new Bundle();
@@ -302,7 +287,7 @@
                 .setTitle(R.string.account_migration_title_dialog)
                 .setMessage(R.string.account_migration_message_dialog)
                 .setIcon(R.drawable.baseline_warning_24)
-                .setPositiveButton(android.R.string.ok, (dialog, which) -> fNavigation.selectSection(RingNavigationFragment.Section.MANAGE))
+                .setPositiveButton(android.R.string.ok, (dialog, which) -> fNavigation.selectSection(HomeNavigationFragment.Section.MANAGE))
                 .setNegativeButton(android.R.string.cancel, null)
                 .show();
     }
@@ -387,7 +372,7 @@
         }
         fContent = new ContactRequestsFragment();
         fContent.setArguments(bundle);
-        fNavigation.selectSection(RingNavigationFragment.Section.CONTACT_REQUESTS);
+        fNavigation.selectSection(HomeNavigationFragment.Section.CONTACT_REQUESTS);
         getSupportFragmentManager().beginTransaction()
                 .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
                 .replace(R.id.main_frame, fContent, CONTACT_REQUESTS_TAG)
@@ -413,7 +398,7 @@
             fContent = fragmentManager.findFragmentById(entry.getId());
             fragmentManager.popBackStack();
             if (fCount == 2)
-                fNavigation.selectSection(RingNavigationFragment.Section.HOME);
+                fNavigation.selectSection(HomeNavigationFragment.Section.HOME);
             return;
         }
         finish();
@@ -441,7 +426,7 @@
     }
 
     @Override
-    public void onNavigationSectionSelected(RingNavigationFragment.Section section) {
+    public void onNavigationSectionSelected(HomeNavigationFragment.Section section) {
         if (!isDrawerLocked) {
             mNavigationDrawer.closeDrawers();
         }
diff --git a/ring-android/app/src/main/java/cx/ring/client/RingtoneActivity.java b/ring-android/app/src/main/java/cx/ring/client/RingtoneActivity.java
index a62b595..173ea97 100644
--- a/ring-android/app/src/main/java/cx/ring/client/RingtoneActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/client/RingtoneActivity.java
@@ -54,7 +54,7 @@
 import cx.ring.R;
 import cx.ring.account.AccountEditionActivity;
 import cx.ring.adapters.RingtoneAdapter;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.model.Account;
 import cx.ring.model.ConfigKey;
 import cx.ring.model.Ringtone;
@@ -84,7 +84,7 @@
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
-        RingApplication.getInstance().getRingInjectionComponent().inject(this);
+        JamiApplication.getInstance().getRingInjectionComponent().inject(this);
         setContentView(R.layout.activity_ringtone);
         super.onCreate(savedInstanceState);
         mAccount = mAccountService.getAccount(getIntent().getExtras().getString(AccountEditionActivity.ACCOUNT_ID_KEY));
diff --git a/ring-android/app/src/main/java/cx/ring/contactrequests/BlackListFragment.java b/ring-android/app/src/main/java/cx/ring/contactrequests/BlackListFragment.java
index db43be6..e3c9abb 100644
--- a/ring-android/app/src/main/java/cx/ring/contactrequests/BlackListFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/contactrequests/BlackListFragment.java
@@ -36,7 +36,7 @@
 import butterknife.BindView;
 import cx.ring.R;
 import cx.ring.account.AccountEditionActivity;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.model.CallContact;
 import cx.ring.mvp.BaseSupportFragment;
 
@@ -59,7 +59,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/contactrequests/ContactRequestsFragment.java b/ring-android/app/src/main/java/cx/ring/contactrequests/ContactRequestsFragment.java
index f654684..7efc403 100644
--- a/ring-android/app/src/main/java/cx/ring/contactrequests/ContactRequestsFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/contactrequests/ContactRequestsFragment.java
@@ -40,10 +40,10 @@
 import cx.ring.adapters.SmartListAdapter;
 import cx.ring.client.ConversationActivity;
 import cx.ring.client.HomeActivity;
-import cx.ring.dependencyinjection.RingInjectionComponent;
-import cx.ring.fragments.ConversationFragment;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.mvp.BaseSupportFragment;
 import cx.ring.smartlist.SmartListViewModel;
+import cx.ring.utils.ConversationPath;
 import cx.ring.utils.DeviceUtils;
 import cx.ring.viewholders.SmartListViewHolder;
 
@@ -70,7 +70,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
@@ -148,19 +148,12 @@
     public void goToConversation(String accountId, String contactId) {
         Context context = requireContext();
         if (DeviceUtils.isTablet(context)) {
-            Bundle bundle = new Bundle();
-            bundle.putString(ConversationFragment.KEY_CONTACT_RING_ID, contactId);
-            bundle.putString(ConversationFragment.KEY_ACCOUNT_ID, accountId);
             Activity activity = getActivity();
-            if (activity instanceof HomeActivity)
-                ((HomeActivity) activity).startConversationTablet(bundle);
+            if (activity instanceof HomeActivity) {
+                ((HomeActivity) activity).startConversationTablet(ConversationPath.toBundle(accountId, contactId));
+            }
         } else {
-            Intent intent = new Intent()
-                    .setClass(context, ConversationActivity.class)
-                    .setAction(Intent.ACTION_VIEW)
-                    .putExtra(ConversationFragment.KEY_ACCOUNT_ID, accountId)
-                    .putExtra(ConversationFragment.KEY_CONTACT_RING_ID, contactId);
-            startActivity(intent);
+            startActivity(new Intent(Intent.ACTION_VIEW, ConversationPath.toUri(accountId, contactId), context, ConversationActivity.class));
         }
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/contacts/AvatarFactory.java b/ring-android/app/src/main/java/cx/ring/contacts/AvatarFactory.java
index bf6570d..f1be888 100644
--- a/ring-android/app/src/main/java/cx/ring/contacts/AvatarFactory.java
+++ b/ring-android/app/src/main/java/cx/ring/contacts/AvatarFactory.java
@@ -21,7 +21,6 @@
 
 package cx.ring.contacts;
 
-import android.app.Fragment;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -34,15 +33,11 @@
 import com.bumptech.glide.Glide;
 import com.bumptech.glide.RequestBuilder;
 import com.bumptech.glide.RequestManager;
-import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
 
 import cx.ring.model.Account;
 import cx.ring.model.CallContact;
 import cx.ring.views.AvatarDrawable;
-import ezvcard.VCard;
-import ezvcard.property.FormattedName;
 import io.reactivex.Single;
-import io.reactivex.schedulers.Schedulers;
 
 public class AvatarFactory {
 
diff --git a/ring-android/app/src/main/java/cx/ring/dependencyinjection/RingInjectionComponent.java b/ring-android/app/src/main/java/cx/ring/dependencyinjection/JamiInjectionComponent.java
similarity index 93%
rename from ring-android/app/src/main/java/cx/ring/dependencyinjection/RingInjectionComponent.java
rename to ring-android/app/src/main/java/cx/ring/dependencyinjection/JamiInjectionComponent.java
index 901978f..cc9ad93 100755
--- a/ring-android/app/src/main/java/cx/ring/dependencyinjection/RingInjectionComponent.java
+++ b/ring-android/app/src/main/java/cx/ring/dependencyinjection/JamiInjectionComponent.java
@@ -30,7 +30,7 @@
 import cx.ring.account.RingAccountCreationFragment;
 import cx.ring.account.RingAccountSummaryFragment;
 import cx.ring.account.RingLinkAccountFragment;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.client.ContactDetailsActivity;
 import cx.ring.client.HomeActivity;
 import cx.ring.client.RingtoneActivity;
@@ -42,6 +42,7 @@
 import cx.ring.fragments.AdvancedAccountFragment;
 import cx.ring.fragments.CallFragment;
 import cx.ring.fragments.ConversationFragment;
+import cx.ring.client.ConversationSelectionActivity;
 import cx.ring.fragments.GeneralAccountFragment;
 import cx.ring.fragments.MediaPreferenceFragment;
 import cx.ring.fragments.SIPAccountCreationFragment;
@@ -50,7 +51,7 @@
 import cx.ring.fragments.SmartListFragment;
 import cx.ring.history.DatabaseHelper;
 import cx.ring.launch.LaunchActivity;
-import cx.ring.navigation.RingNavigationFragment;
+import cx.ring.navigation.HomeNavigationFragment;
 import cx.ring.service.BootReceiver;
 import cx.ring.service.CallNotificationService;
 import cx.ring.service.DRingService;
@@ -65,7 +66,7 @@
 import cx.ring.services.HardwareService;
 import cx.ring.services.HistoryServiceImpl;
 import cx.ring.services.NotificationServiceImpl;
-import cx.ring.services.RingChooserTargetService;
+import cx.ring.services.JamiChooserTargetService;
 import cx.ring.services.SharedPreferencesServiceImpl;
 import cx.ring.settings.SettingsFragment;
 import cx.ring.share.ShareFragment;
@@ -88,11 +89,11 @@
 import dagger.Component;
 
 @Singleton
-@Component(modules = {RingInjectionModule.class, ServiceInjectionModule.class})
-public interface RingInjectionComponent {
-    void inject(RingApplication app);
+@Component(modules = {JamiInjectionModule.class, ServiceInjectionModule.class})
+public interface JamiInjectionComponent {
+    void inject(JamiApplication app);
 
-    void inject(RingNavigationFragment view);
+    void inject(HomeNavigationFragment view);
 
     void inject(HomeActivity activity);
 
@@ -116,6 +117,8 @@
 
     void inject(SmartListFragment fragment);
 
+    void inject(ConversationSelectionActivity fragment);
+
     void inject(RingAccountCreationFragment fragment);
 
     void inject(MediaPreferenceFragment fragment);
@@ -213,7 +216,7 @@
 
     void inject(TVSettingsFragment.PrefsFragment prefsFragment);
 
-    void inject(RingChooserTargetService service);
+    void inject(JamiChooserTargetService service);
 
     void inject(ShareWithFragment fragment);
 
diff --git a/ring-android/app/src/main/java/cx/ring/dependencyinjection/RingInjectionModule.java b/ring-android/app/src/main/java/cx/ring/dependencyinjection/JamiInjectionModule.java
similarity index 79%
rename from ring-android/app/src/main/java/cx/ring/dependencyinjection/RingInjectionModule.java
rename to ring-android/app/src/main/java/cx/ring/dependencyinjection/JamiInjectionModule.java
index 3d70bfa..125e7f9 100755
--- a/ring-android/app/src/main/java/cx/ring/dependencyinjection/RingInjectionModule.java
+++ b/ring-android/app/src/main/java/cx/ring/dependencyinjection/JamiInjectionModule.java
@@ -21,29 +21,29 @@
 
 import android.content.Context;
 
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import dagger.Module;
 import dagger.Provides;
 import io.reactivex.Scheduler;
 import io.reactivex.android.schedulers.AndroidSchedulers;
 
 @Module
-public class RingInjectionModule {
+public class JamiInjectionModule {
 
-    private final RingApplication mRingApplication;
+    private final JamiApplication mJamiApplication;
 
-    public RingInjectionModule(RingApplication app) {
-        mRingApplication = app;
+    public JamiInjectionModule(JamiApplication app) {
+        mJamiApplication = app;
     }
 
     @Provides
-    RingApplication provideRingApplication() {
-        return mRingApplication;
+    JamiApplication provideRingApplication() {
+        return mJamiApplication;
     }
 
     @Provides
     Context provideContext() {
-        return mRingApplication;
+        return mJamiApplication;
     }
 
     @Provides
diff --git a/ring-android/app/src/main/java/cx/ring/dependencyinjection/ServiceInjectionModule.java b/ring-android/app/src/main/java/cx/ring/dependencyinjection/ServiceInjectionModule.java
index 1ffd3af..c2194ed 100755
--- a/ring-android/app/src/main/java/cx/ring/dependencyinjection/ServiceInjectionModule.java
+++ b/ring-android/app/src/main/java/cx/ring/dependencyinjection/ServiceInjectionModule.java
@@ -27,11 +27,10 @@
 import javax.inject.Named;
 import javax.inject.Singleton;
 
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.facades.ConversationFacade;
 import cx.ring.services.AccountService;
 import cx.ring.services.CallService;
-import cx.ring.services.ConferenceService;
 import cx.ring.services.ContactService;
 import cx.ring.services.ContactServiceImpl;
 import cx.ring.services.DaemonService;
@@ -58,17 +57,17 @@
 @Module
 public class ServiceInjectionModule {
 
-    RingApplication mRingApplication;
+    private final JamiApplication mJamiApplication;
 
-    public ServiceInjectionModule(RingApplication app) {
-        mRingApplication = app;
+    public ServiceInjectionModule(JamiApplication app) {
+        mJamiApplication = app;
     }
 
     @Provides
     @Singleton
     PreferencesService provideSettingsService() {
         SharedPreferencesServiceImpl settingsService = new SharedPreferencesServiceImpl();
-        mRingApplication.getRingInjectionComponent().inject(settingsService);
+        mJamiApplication.getRingInjectionComponent().inject(settingsService);
         return settingsService;
     }
 
@@ -76,7 +75,7 @@
     @Singleton
     HistoryService provideHistoryService() {
         HistoryServiceImpl historyService = new HistoryServiceImpl();
-        mRingApplication.getRingInjectionComponent().inject(historyService);
+        mJamiApplication.getRingInjectionComponent().inject(historyService);
         return historyService;
     }
 
@@ -92,7 +91,7 @@
     @Singleton
     NotificationService provideNotificationService() {
         NotificationServiceImpl service = new NotificationServiceImpl();
-        mRingApplication.getRingInjectionComponent().inject(service);
+        mJamiApplication.getRingInjectionComponent().inject(service);
         service.initHelper();
         return service;
     }
@@ -101,7 +100,7 @@
     @Singleton
     DeviceRuntimeService provideDeviceRuntimeService(LogService logService) {
         DeviceRuntimeServiceImpl runtimeService = new DeviceRuntimeServiceImpl();
-        mRingApplication.getRingInjectionComponent().inject(runtimeService);
+        mJamiApplication.getRingInjectionComponent().inject(runtimeService);
         runtimeService.loadNativeLibrary();
         return runtimeService;
     }
@@ -110,7 +109,7 @@
     @Singleton
     DaemonService provideDaemonService(DeviceRuntimeService deviceRuntimeService) {
         DaemonService daemonService = new DaemonService(deviceRuntimeService);
-        mRingApplication.getRingInjectionComponent().inject(daemonService);
+        mJamiApplication.getRingInjectionComponent().inject(daemonService);
         return daemonService;
     }
 
@@ -118,23 +117,15 @@
     @Singleton
     CallService provideCallService() {
         CallService callService = new CallService();
-        mRingApplication.getRingInjectionComponent().inject(callService);
+        mJamiApplication.getRingInjectionComponent().inject(callService);
         return callService;
     }
 
     @Provides
     @Singleton
-    ConferenceService provideConferenceService() {
-        ConferenceService conferenceService = new ConferenceService();
-        mRingApplication.getRingInjectionComponent().inject(conferenceService);
-        return conferenceService;
-    }
-
-    @Provides
-    @Singleton
     AccountService provideAccountService() {
         AccountService accountService = new AccountService();
-        mRingApplication.getRingInjectionComponent().inject(accountService);
+        mJamiApplication.getRingInjectionComponent().inject(accountService);
         return accountService;
     }
 
@@ -142,7 +133,7 @@
     @Singleton
     HardwareService provideHardwareService(Context context) {
         HardwareServiceImpl hardwareService = new HardwareServiceImpl(context);
-        mRingApplication.getRingInjectionComponent().inject(hardwareService);
+        mJamiApplication.getRingInjectionComponent().inject(hardwareService);
         return hardwareService;
     }
 
@@ -150,7 +141,7 @@
     @Singleton
     ContactService provideContactService(PreferencesService sharedPreferencesService) {
         ContactServiceImpl contactService = new ContactServiceImpl();
-        mRingApplication.getRingInjectionComponent().inject(contactService);
+        mJamiApplication.getRingInjectionComponent().inject(contactService);
         return contactService;
     }
 
@@ -161,7 +152,7 @@
             CallService callService,
             AccountService accountService) {
         ConversationFacade conversationFacade = new ConversationFacade(historyService, callService, accountService);
-        mRingApplication.getRingInjectionComponent().inject(conversationFacade);
+        mJamiApplication.getRingInjectionComponent().inject(conversationFacade);
         return conversationFacade;
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/AccountMigrationFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/AccountMigrationFragment.java
index 345c0e2..c6a11cd 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/AccountMigrationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/AccountMigrationFragment.java
@@ -50,7 +50,7 @@
 import butterknife.OnEditorAction;
 import butterknife.OnFocusChange;
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.model.Account;
 import cx.ring.model.AccountConfig;
 import cx.ring.model.ConfigKey;
@@ -85,7 +85,7 @@
         ButterKnife.bind(this, inflatedView);
 
         // dependency injection
-        ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
 
         return inflatedView;
     }
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/AccountsManagementFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/AccountsManagementFragment.java
index b2eeb87..6149d30 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/AccountsManagementFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/AccountsManagementFragment.java
@@ -34,7 +34,6 @@
 import android.view.MenuInflater;
 import android.view.View;
 
-import java.util.HashMap;
 import java.util.List;
 
 import butterknife.BindView;
@@ -45,9 +44,9 @@
 import cx.ring.account.AccountsManagementPresenter;
 import cx.ring.account.AccountsManagementView;
 import cx.ring.adapters.AccountView;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.client.HomeActivity;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.model.Account;
 import cx.ring.mvp.BaseSupportFragment;
 import cx.ring.utils.ContentUriHandler;
@@ -72,7 +71,7 @@
         Log.d(TAG, "onCreate: Create Account Management Fragment");
 
         // dependency injection
-        ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
 
         mAccountsAdapter = new AccountsAdapter(this);
     }
@@ -83,7 +82,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/AdvancedAccountFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/AdvancedAccountFragment.java
index 2e59bd8..fe40fc5 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/AdvancedAccountFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/AdvancedAccountFragment.java
@@ -31,7 +31,7 @@
 
 import cx.ring.R;
 import cx.ring.account.AccountEditionActivity;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.model.AccountConfig;
 import cx.ring.model.ConfigKey;
 import cx.ring.mvp.BasePreferenceFragment;
@@ -45,7 +45,7 @@
 
     @Override
     public void onCreatePreferences(Bundle bundle, String s) {
-        ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
         super.onCreatePreferences(bundle, s);
 
         // Load the preferences from an XML resource
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 6cc63e6..8320fb3 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
@@ -21,6 +21,7 @@
 package cx.ring.fragments;
 
 import android.Manifest;
+import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.app.PictureInPictureParams;
@@ -59,25 +60,36 @@
 import androidx.annotation.Nullable;
 import androidx.appcompat.app.ActionBar;
 import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.view.menu.MenuBuilder;
+import androidx.appcompat.view.menu.MenuPopupHelper;
+import androidx.appcompat.widget.PopupMenu;
 import androidx.databinding.DataBindingUtil;
+import androidx.fragment.app.FragmentActivity;
+import androidx.recyclerview.widget.DiffUtil;
+import androidx.recyclerview.widget.RecyclerView;
 
 import com.rodolfonavalon.shaperipplelibrary.model.Circle;
 
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Locale;
 import java.util.Random;
 
 import javax.inject.Inject;
 
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.call.CallPresenter;
 import cx.ring.call.CallView;
 import cx.ring.client.CallActivity;
+import cx.ring.client.ContactDetailsActivity;
 import cx.ring.client.ConversationActivity;
+import cx.ring.client.ConversationSelectionActivity;
 import cx.ring.client.HomeActivity;
+import cx.ring.contacts.AvatarFactory;
 import cx.ring.databinding.FragCallBinding;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.databinding.ItemConferenceParticipantBinding;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.model.CallContact;
 import cx.ring.model.SipCall;
 import cx.ring.mvp.BaseSupportFragment;
@@ -86,12 +98,15 @@
 import cx.ring.services.HardwareService;
 import cx.ring.services.NotificationService;
 import cx.ring.utils.ActionHelper;
+import cx.ring.utils.ContentUriHandler;
+import cx.ring.utils.ConversationPath;
 import cx.ring.utils.DeviceUtils;
 import cx.ring.utils.KeyboardVisibilityManager;
 import cx.ring.utils.Log;
 import cx.ring.utils.MediaButtonsHelper;
 import cx.ring.views.AvatarDrawable;
 import io.reactivex.disposables.CompositeDisposable;
+import io.reactivex.disposables.Disposable;
 
 public class CallFragment extends BaseSupportFragment<CallPresenter> implements CallView, MediaButtonsHelper.MediaButtonsHelperCallback {
 
@@ -105,8 +120,10 @@
     public static final String KEY_CONF_ID = "confId";
     public static final String KEY_AUDIO_ONLY = "AUDIO_ONLY";
 
+    private static final int REQUEST_CODE_ADD_PARTICIPANT = 6;
     private static final int REQUEST_PERMISSION_INCOMING = 1003;
     private static final int REQUEST_PERMISSION_OUTGOING = 1004;
+
     private FragCallBinding binding;
     private OrientationEventListener mOrientationListener;
 
@@ -123,6 +140,91 @@
 
     private boolean mBackstackLost = false;
 
+    private ConfParticipantAdapter confAdapter = null;
+    private boolean mConferenceMode = false;
+
+    static class ParticipantView extends RecyclerView.ViewHolder {
+        final ItemConferenceParticipantBinding binding;
+        Disposable disposable = null;
+        ParticipantView(@NonNull ItemConferenceParticipantBinding b) {
+            super(b.getRoot());
+            binding = b;
+        }
+    }
+
+    public static class ConfParticipantAdapter extends RecyclerView.Adapter<ParticipantView> {
+        private List<SipCall> calls = null;
+        public interface ConfParticipantSelected {
+            void onParticipantSelected(View view, SipCall contact);
+        }
+        private final ConfParticipantSelected onSelectedCallback;
+
+        ConfParticipantAdapter(@NonNull ConfParticipantSelected cb) {
+            onSelectedCallback = cb;
+        }
+
+        @NonNull
+        @Override
+        public ParticipantView onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+            return new ParticipantView(ItemConferenceParticipantBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false));
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull ParticipantView holder, int position) {
+            final SipCall call = calls.get(position);
+            final CallContact contact = call.getContact();
+            final Context context = holder.itemView.getContext();
+            SipCall.CallStatus status = call.getCallStatus();
+            if (status == SipCall.CallStatus.CURRENT)  {
+                holder.binding.displayName.setText(contact.getDisplayName());
+                holder.binding.photo.setAlpha(1f);
+            } else {
+                holder.binding.displayName.setText(String.format("%s\n%s", contact.getDisplayName(), context.getText(callStateToHumanState(status))));
+                holder.binding.photo.setAlpha(.5f);
+            }
+            if (holder.disposable != null)
+                holder.disposable.dispose();
+            holder.disposable = AvatarFactory.getAvatar(context, contact)
+                    .subscribe(holder.binding.photo::setImageDrawable);
+            holder.itemView.setOnClickListener(view -> onSelectedCallback.onParticipantSelected(view, call));
+        }
+
+        @Override
+        public int getItemCount() {
+            return calls == null ? 0 : calls.size();
+        }
+
+        void updateFromCalls(@NonNull final List<SipCall> contacts) {
+            final List<SipCall> oldCalls = calls;
+            calls = contacts;
+            if (oldCalls != null) {
+                DiffUtil.calculateDiff(new DiffUtil.Callback() {
+                    @Override
+                    public int getOldListSize() {
+                        return oldCalls.size();
+                    }
+
+                    @Override
+                    public int getNewListSize() {
+                        return contacts.size();
+                    }
+
+                    @Override
+                    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
+                        return oldCalls.get(oldItemPosition) == contacts.get(newItemPosition);
+                    }
+
+                    @Override
+                    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
+                        return false;
+                    }
+                }).dispatchUpdatesTo(this);
+            } else {
+                notifyDataSetChanged();
+            }
+        }
+    }
+
     @Inject
     DeviceRuntimeService mDeviceRuntimeService;
 
@@ -172,7 +274,7 @@
                 return R.string.call_human_state_over;
             case NONE:
             default:
-                return 0;
+                return R.string.call_human_state_none;
         }
     }
 
@@ -198,7 +300,7 @@
     }
 
     @Override
-    public void enterPipMode(SipCall sipCall) {
+    public void enterPipMode(String callId) {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
             return;
         }
@@ -224,7 +326,7 @@
                     PendingIntent.getService(context, new Random().nextInt(),
                             new Intent(DRingService.ACTION_CALL_END)
                                     .setClass(context, DRingService.class)
-                                    .putExtra(NotificationService.KEY_CALL_ID, sipCall.getDaemonIdString()), PendingIntent.FLAG_ONE_SHOT)));
+                                    .putExtra(NotificationService.KEY_CALL_ID, callId), PendingIntent.FLAG_ONE_SHOT)));
             paramBuilder.setActions(actions);
             requireActivity().enterPictureInPictureMode(paramBuilder.build());
         } else if (DeviceUtils.isTv(context)) {
@@ -238,7 +340,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
@@ -269,7 +371,7 @@
     @Nullable
     @Override
     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
-        injectFragment(((RingApplication) requireActivity().getApplication()).getRingInjectionComponent());
+        injectFragment(((JamiApplication) requireActivity().getApplication()).getRingInjectionComponent());
         binding = DataBindingUtil.inflate(inflater, R.layout.frag_call, container, false);
         binding.setPresenter(this);
         return binding.getRoot();
@@ -305,13 +407,27 @@
         setHasOptionsMenu(true);
         super.onViewCreated(view, savedInstanceState);
         mCurrentOrientation = getResources().getConfiguration().orientation;
-        requireActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-        PowerManager powerManager = (PowerManager) requireContext().getSystemService(Context.POWER_SERVICE);
-        mScreenWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "ring:callLock");
-        mScreenWakeLock.setReferenceCounted(false);
 
-        if (mScreenWakeLock != null && !mScreenWakeLock.isHeld()) {
-            mScreenWakeLock.acquire();
+        FragmentActivity activity = getActivity();
+        if (activity != null) {
+            activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+            if (activity instanceof AppCompatActivity) {
+                AppCompatActivity ac_activity = (AppCompatActivity) activity;
+                ActionBar ab = ac_activity.getSupportActionBar();
+                if (ab != null) {
+                    ab.setHomeAsUpIndicator(R.drawable.baseline_chat_24);
+                    ab.setDisplayHomeAsUpEnabled(true);
+                }
+            }
+        }
+
+        PowerManager powerManager = (PowerManager) requireContext().getSystemService(Context.POWER_SERVICE);
+        if (powerManager != null) {
+            mScreenWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "ring:callLock");
+            mScreenWakeLock.setReferenceCounted(false);
+            if (mScreenWakeLock != null && !mScreenWakeLock.isHeld()) {
+                mScreenWakeLock.acquire();
+            }
         }
 
         binding.videoSurface.getHolder().setFormat(PixelFormat.RGBA_8888);
@@ -339,18 +455,20 @@
                 resetVideoSize(mVideoWidth, mVideoHeight));
 
         WindowManager windowManager = (WindowManager) requireContext().getSystemService(Context.WINDOW_SERVICE);
-        mOrientationListener = new OrientationEventListener(getContext()) {
-            @Override
-            public void onOrientationChanged(int orientation) {
-                int rot = windowManager.getDefaultDisplay().getRotation();
-                if (mCurrentOrientation != rot) {
-                    mCurrentOrientation = rot;
-                    presenter.configurationChanged(rot);
+        if (windowManager != null) {
+            mOrientationListener = new OrientationEventListener(getContext()) {
+                @Override
+                public void onOrientationChanged(int orientation) {
+                    int rot = windowManager.getDefaultDisplay().getRotation();
+                    if (mCurrentOrientation != rot) {
+                        mCurrentOrientation = rot;
+                        presenter.configurationChanged(rot);
+                    }
                 }
+            };
+            if (mOrientationListener.canDetectOrientation()) {
+                mOrientationListener.enable();
             }
-        };
-        if (mOrientationListener.canDetectOrientation()) {
-            mOrientationListener.enable();
         }
 
         binding.shapeRipple.setRippleShape(new Circle());
@@ -387,11 +505,13 @@
                 mScreenWakeLock.release();
             }
             PowerManager powerManager = (PowerManager) requireContext().getSystemService(Context.POWER_SERVICE);
-            mScreenWakeLock = powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "ring:callLock");
-            mScreenWakeLock.setReferenceCounted(false);
+            if (powerManager != null) {
+                mScreenWakeLock = powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "ring:callLock");
+                mScreenWakeLock.setReferenceCounted(false);
 
-            if (mScreenWakeLock != null && !mScreenWakeLock.isHeld()) {
-                mScreenWakeLock.acquire();
+                if (mScreenWakeLock != null && !mScreenWakeLock.isHeld()) {
+                    mScreenWakeLock.acquire();
+                }
             }
         }
     }
@@ -434,24 +554,35 @@
     }
 
     @Override
-    public void onCreateOptionsMenu(Menu m, MenuInflater inf) {
+    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+        if (requestCode == REQUEST_CODE_ADD_PARTICIPANT) {
+            if (resultCode == Activity.RESULT_OK && data != null) {
+                ConversationPath path = ConversationPath.fromUri(data.getData());
+                if (path != null) {
+                    presenter.addConferenceParticipant(path.getAccountId(), path.getContactId());
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onCreateOptionsMenu(@NonNull Menu m, @NonNull MenuInflater inf) {
         super.onCreateOptionsMenu(m, inf);
         inf.inflate(R.menu.ac_call, m);
         dialPadBtn = m.findItem(R.id.menuitem_dialpad);
     }
 
     @Override
-    public void onPrepareOptionsMenu(Menu menu) {
+    public void onPrepareOptionsMenu(@NonNull Menu menu) {
         super.onPrepareOptionsMenu(menu);
         presenter.prepareOptionMenu();
     }
 
     @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
+    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
         super.onOptionsItemSelected(item);
         switch (item.getItemId()) {
             case android.R.id.home:
-            case R.id.menuitem_chat:
                 presenter.chatClick();
                 break;
             case R.id.menuitem_dialpad:
@@ -501,8 +632,10 @@
 
     @Override
     public void displayHangupButton(boolean display) {
+        Log.w(TAG, "displayHangupButton " + display);
         binding.callControlGroup.setVisibility(display ? View.VISIBLE : View.GONE);
         binding.callHangupBtn.setVisibility(display ? View.VISIBLE : View.GONE);
+        binding.confControlGroup.setVisibility((mConferenceMode && display) ? View.VISIBLE : View.GONE);
     }
 
     @Override
@@ -527,17 +660,22 @@
 
     @Override
     public void updateTime(final long duration) {
-        if (binding.callStatusTxt != null)
-            binding.callStatusTxt.setText(String.format(Locale.getDefault(), "%d:%02d:%02d", duration / 3600, duration % 3600 / 60, duration % 60));
+        if (binding.callStatusTxt != null) {
+            if (duration == 0)
+                binding.callStatusTxt.setText(null);
+            else
+                binding.callStatusTxt.setText(String.format(Locale.getDefault(), "%d:%02d:%02d", duration / 3600, duration % 3600 / 60, duration % 60));
+        }
     }
 
     @Override
-    public void updateContactBubble(@NonNull final CallContact contact) {
-        String username = contact.getRingUsername();
-        String displayName = contact.getDisplayName();
+    @SuppressLint("RestrictedApi")
+    public void updateContactBubble(@NonNull final List<SipCall> contacts) {
+        Log.w(TAG, "updateContactBubble " + contacts.size());
 
-        String ringId = contact.getIds().get(0);
-        Log.d(TAG, "updateContactBubble: contact=" + contact + " username=" + username + ", ringId=" + ringId);
+        mConferenceMode = contacts.size() > 1;
+        String username = mConferenceMode ? "Conference with " + contacts.size() + " people" : contacts.get(0).getContact().getRingUsername();
+        String displayName = mConferenceMode ? null : contacts.get(0).getContact().getDisplayName();
 
         boolean hasProfileName = displayName != null && !displayName.contentEquals(username);
 
@@ -565,23 +703,48 @@
             binding.contactBubbleTxt.setText(username);
         }
 
-        binding.contactBubble.setImageDrawable(new AvatarDrawable(getActivity(), contact));
-    }
+        binding.contactBubble.setImageDrawable(new AvatarDrawable(getActivity(), contacts.get(0).getContact()));
 
-    @Override
-    public void updateCallStatus(final SipCall.CallStatus callStatus) {
-        switch (callStatus) {
-            case NONE:
-                binding.callStatusTxt.setText("");
-                break;
-            default:
-                binding.callStatusTxt.setText(callStateToHumanState(callStatus));
-                break;
+        if (!mConferenceMode) {
+            binding.confControlGroup.setVisibility(View.GONE);
+        } else {
+            binding.confControlGroup.setVisibility(View.VISIBLE);
+            if (confAdapter  == null) {
+                confAdapter = new ConfParticipantAdapter((view, call) -> {
+                    Context context = requireContext();
+                    PopupMenu popup = new PopupMenu(context, view);
+                    popup.inflate(R.menu.conference_participant_actions);
+                    popup.setOnMenuItemClickListener(item -> {
+                        switch (item.getItemId()) {
+                            case R.id.conv_contact_details:
+                                presenter.openParticipantContact(call);
+                                break;
+                            case R.id.conv_contact_hangup:
+                                presenter.hangupParticipant(call);
+                                break;
+                            default:
+                                return false;
+                        }
+                        return true;
+                    });
+                    MenuPopupHelper menuHelper = new MenuPopupHelper(context, (MenuBuilder) popup.getMenu(), view);
+                    menuHelper.setForceShowIcon(true);
+                    menuHelper.show();
+                });
+            }
+            confAdapter.updateFromCalls(contacts);
+            if (binding.confControlGroup.getAdapter() == null)
+                binding.confControlGroup.setAdapter(confAdapter);
         }
     }
 
     @Override
-    public void initMenu(boolean isSpeakerOn, boolean hasContact, boolean displayFlip, boolean canDial, boolean onGoingCall) {
+    public void updateCallStatus(final SipCall.CallStatus callStatus) {
+        binding.callStatusTxt.setText(callStateToHumanState(callStatus));
+    }
+
+    @Override
+    public void initMenu(boolean isSpeakerOn, boolean displayFlip, boolean canDial, boolean onGoingCall) {
         if (binding.callCameraFlipBtn != null) {
             binding.callCameraFlipBtn.setVisibility(displayFlip ? View.VISIBLE : View.GONE);
         }
@@ -592,6 +755,7 @@
 
     @Override
     public void initNormalStateDisplay(final boolean audioOnly, boolean isMuted) {
+        Log.w(TAG, "initNormalStateDisplay");
         binding.shapeRipple.stopRipple();
 
         binding.callAcceptBtn.setVisibility(View.GONE);
@@ -607,6 +771,8 @@
 
     @Override
     public void initIncomingCallDisplay() {
+        Log.w(TAG, "initIncomingCallDisplay");
+
         binding.callAcceptBtn.setVisibility(View.VISIBLE);
         binding.callRefuseBtn.setVisibility(View.VISIBLE);
         binding.callControlGroup.setVisibility(View.GONE);
@@ -618,6 +784,8 @@
 
     @Override
     public void initOutGoingCallDisplay() {
+        Log.w(TAG, "initOutGoingCallDisplay");
+
         binding.callAcceptBtn.setVisibility(View.GONE);
         binding.callRefuseBtn.setVisibility(View.VISIBLE);
         binding.callControlGroup.setVisibility(View.GONE);
@@ -691,19 +859,14 @@
 
     @Override
     public void goToConversation(String accountId, String conversationId) {
-        Intent intent = new Intent();
-        if (DeviceUtils.isTablet(requireActivity())) {
-            intent.setClass(requireActivity(), HomeActivity.class)
+        Context context = requireContext();
+        if (DeviceUtils.isTablet(context)) {
+            startActivity(new Intent(context, HomeActivity.class)
                     .setAction(DRingService.ACTION_CONV_ACCEPT)
-                    .putExtra(ConversationFragment.KEY_CONTACT_RING_ID, conversationId);
-            startActivity(intent);
+                    .putExtra(ConversationFragment.KEY_CONTACT_RING_ID, conversationId));
         } else {
-            intent.setClass(requireActivity(), ConversationActivity.class)
-                    .setAction(Intent.ACTION_VIEW)
-                    .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP)
-                    .putExtra(ConversationFragment.KEY_ACCOUNT_ID, accountId)
-                    .putExtra(ConversationFragment.KEY_CONTACT_RING_ID, conversationId);
-            startActivityForResult(intent, HomeActivity.REQUEST_CODE_CONVERSATION);
+            startActivityForResult(new Intent(Intent.ACTION_VIEW, ConversationPath.toUri(accountId, conversationId), context, ConversationActivity.class)
+                    .setFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT), HomeActivity.REQUEST_CODE_CONVERSATION);
         }
     }
 
@@ -713,6 +876,12 @@
                 ConversationFragment.REQ_ADD_CONTACT);
     }
 
+    @Override
+    public void goToContact(String accountId, CallContact contact) {
+        startActivity(new Intent(Intent.ACTION_VIEW, android.net.Uri.withAppendedPath(android.net.Uri.withAppendedPath(ContentUriHandler.CONTACT_CONTENT_URI, accountId), contact.getPrimaryNumber()))
+                .setClass(requireContext(), ContactDetailsActivity.class));
+    }
+
     /**
      * Checks if permissions are accepted for camera and microphone. Takes into account whether call is incoming and outgoing, and requests permissions if not available.
      * Initializes the call if permissions are accepted.
@@ -722,7 +891,6 @@
      */
     @Override
     public void prepareCall(boolean isIncoming) {
-        Bundle args = getArguments();
         boolean audioGranted = mDeviceRuntimeService.hasAudioPermission();
         boolean audioOnly;
         int permissionType;
@@ -730,9 +898,9 @@
         if (isIncoming) {
             audioOnly = presenter.isAudioOnly();
             permissionType = REQUEST_PERMISSION_INCOMING;
-
         } else {
-            audioOnly = args.getBoolean(KEY_AUDIO_ONLY);
+            Bundle args = getArguments();
+            audioOnly = args != null && args.getBoolean(KEY_AUDIO_ONLY);
             permissionType = REQUEST_PERMISSION_OUTGOING;
         }
         if (!audioOnly) {
@@ -764,7 +932,7 @@
      *
      * @param isIncoming true if call is incoming, false for outgoing
      */
-    public void initializeCall(boolean isIncoming) {
+    private void initializeCall(boolean isIncoming) {
         if (isIncoming) {
             presenter.acceptCall();
         } else {
@@ -818,6 +986,19 @@
         presenter.switchVideoInputClick();
     }
 
+    public void addParticipant() {
+        presenter.startAddParticipant();
+    }
+
+    @Override
+    public void startAddParticipant(String conferenceId) {
+        startActivityForResult(
+                new Intent(Intent.ACTION_PICK)
+                        .setClass(requireActivity(), ConversationSelectionActivity.class)
+                        .putExtra(KEY_CONF_ID, conferenceId),
+                CallFragment.REQUEST_CODE_ADD_PARTICIPANT);
+    }
+
     @Override
     public void positiveMediaButtonClicked() {
         presenter.positiveButtonClicked();
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.java
index 3edaea2..576ae97 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.java
@@ -66,7 +66,7 @@
 import cx.ring.R;
 import cx.ring.adapters.ConversationAdapter;
 import cx.ring.adapters.NumberAdapter;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.client.CallActivity;
 import cx.ring.client.ContactDetailsActivity;
 import cx.ring.client.ConversationActivity;
@@ -75,7 +75,7 @@
 import cx.ring.conversation.ConversationPresenter;
 import cx.ring.conversation.ConversationView;
 import cx.ring.databinding.FragConversationBinding;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.interfaces.Colorable;
 import cx.ring.model.CallContact;
 import cx.ring.model.Conversation;
@@ -170,7 +170,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
@@ -190,7 +190,7 @@
     @Nullable
     @Override
     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
-        injectFragment(((RingApplication) getActivity().getApplication()).getRingInjectionComponent());
+        injectFragment(((JamiApplication) getActivity().getApplication()).getRingInjectionComponent());
         marginPx = getResources().getDimensionPixelSize(R.dimen.conversation_message_input_margin);
         marginPxTotal = marginPx;
         animation.setDuration(150);
@@ -392,7 +392,7 @@
 
     public void takePicture() {
         if (!presenter.getDeviceRuntimeService().hasVideoPermission()) {
-            requestPermissions(new String[]{Manifest.permission.CAMERA}, RingApplication.PERMISSIONS_REQUEST);
+            requestPermissions(new String[]{Manifest.permission.CAMERA}, JamiApplication.PERMISSIONS_REQUEST);
         } else {
             Context c = getContext();
             if (c == null)
@@ -418,7 +418,7 @@
 
     @Override
     public void askWriteExternalStoragePermission() {
-        requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RingApplication.PERMISSIONS_REQUEST);
+        requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, JamiApplication.PERMISSIONS_REQUEST);
     }
 
     @Override
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/GeneralAccountFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/GeneralAccountFragment.java
index e730cad..0cca8e7 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/GeneralAccountFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/GeneralAccountFragment.java
@@ -29,7 +29,7 @@
 
 import cx.ring.R;
 import cx.ring.account.AccountEditionActivity;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.model.Account;
 import cx.ring.model.AccountConfig;
 import cx.ring.model.ConfigKey;
@@ -119,7 +119,7 @@
 
     @Override
     public void onCreatePreferences(Bundle bundle, String rootKey) {
-        ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
         super.onCreatePreferences(bundle, rootKey);
 
         presenter.init(getArguments().getString(AccountEditionActivity.ACCOUNT_ID_KEY));
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/MediaPreferenceFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/MediaPreferenceFragment.java
index 444f6a3..dda5db8 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/MediaPreferenceFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/MediaPreferenceFragment.java
@@ -26,18 +26,16 @@
 import android.os.Bundle;
 
 import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
 import androidx.preference.Preference;
 import androidx.preference.TwoStatePreference;
 
 import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 
-import java.io.File;
 import java.util.ArrayList;
 
 import cx.ring.R;
 import cx.ring.account.AccountEditionActivity;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.client.RingtoneActivity;
 import cx.ring.model.Account;
 import cx.ring.model.AccountConfig;
@@ -76,7 +74,7 @@
 
     @Override
     public void onCreatePreferences(Bundle bundle, String rootKey) {
-        ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
         super.onCreatePreferences(bundle, rootKey);
 
         String accountId = getArguments().getString(AccountEditionActivity.ACCOUNT_ID_KEY);
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/SIPAccountCreationFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/SIPAccountCreationFragment.java
index d59e55a..1b3e61a 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/SIPAccountCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/SIPAccountCreationFragment.java
@@ -25,8 +25,6 @@
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 
-import androidx.appcompat.app.AlertDialog;
-
 import android.view.KeyEvent;
 import android.view.inputmethod.EditorInfo;
 import android.widget.Button;
@@ -39,7 +37,7 @@
 import butterknife.OnClick;
 import butterknife.OnEditorAction;
 import cx.ring.R;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.mvp.BaseSupportFragment;
 import cx.ring.mvp.SIPCreationView;
 import cx.ring.wizard.SIPCreationPresenter;
@@ -71,7 +69,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/SecurityAccountFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/SecurityAccountFragment.java
index abdbd54..9c7cc01 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/SecurityAccountFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/SecurityAccountFragment.java
@@ -26,7 +26,6 @@
 import android.net.Uri;
 import android.os.Bundle;
 
-import androidx.core.content.ContextCompat;
 import androidx.preference.EditTextPreference;
 import androidx.preference.ListPreference;
 import androidx.preference.Preference;
@@ -39,7 +38,7 @@
 
 import cx.ring.R;
 import cx.ring.account.AccountEditionActivity;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.model.AccountConfig;
 import cx.ring.model.AccountCredentials;
 import cx.ring.model.ConfigKey;
@@ -101,7 +100,7 @@
     @Override
     public void onCreatePreferences(Bundle bundle, String s) {
         // dependency injection
-        ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
         super.onCreatePreferences(bundle, s);
 
         addPreferencesFromResource(R.xml.account_security_prefs);
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/ShareWithFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/ShareWithFragment.java
index 95deae3..77047de 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/ShareWithFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/ShareWithFragment.java
@@ -47,12 +47,13 @@
 
 import cx.ring.R;
 import cx.ring.adapters.SmartListAdapter;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.client.ConversationActivity;
 import cx.ring.facades.ConversationFacade;
 import cx.ring.model.Account;
 import cx.ring.services.ContactService;
 import cx.ring.smartlist.SmartListViewModel;
+import cx.ring.utils.ConversationPath;
 import cx.ring.viewholders.SmartListViewHolder;
 import io.reactivex.android.schedulers.AndroidSchedulers;
 import io.reactivex.disposables.CompositeDisposable;
@@ -82,7 +83,7 @@
      * fragment (e.g. upon screen orientation changes).
      */
     public ShareWithFragment() {
-        RingApplication.getInstance().getRingInjectionComponent().inject(this);
+        JamiApplication.getInstance().getRingInjectionComponent().inject(this);
     }
 
     public static ShareWithFragment newInstance() {
@@ -142,12 +143,12 @@
                     Intent intent = mPendingIntent;
                     mPendingIntent = null;
                     String type = intent.getType();
-                    if (type.startsWith("text/")) {
+                    if (type != null && type.startsWith("text/")) {
                         intent.putExtra(Intent.EXTRA_TEXT, previewText.getText().toString());
                     }
                     intent.putExtra(ConversationFragment.KEY_ACCOUNT_ID, smartListViewModel.getAccountId());
                     intent.putExtra(ConversationFragment.KEY_CONTACT_RING_ID, smartListViewModel.getContact().getPrimaryNumber());
-                    intent.setClass(getActivity(), ConversationActivity.class);
+                    intent.setClass(requireActivity(), ConversationActivity.class);
                     startActivity(intent);
                 }
             }
@@ -192,9 +193,7 @@
         Intent intent = getActivity().getIntent();
         Bundle extra = intent.getExtras();
         if (extra != null) {
-            String accountId = extra.getString(ConversationFragment.KEY_ACCOUNT_ID);
-            String uri = extra.getString(ConversationFragment.KEY_CONTACT_RING_ID);
-            if (!TextUtils.isEmpty(accountId) && !TextUtils.isEmpty(uri)) {
+            if (ConversationPath.fromBundle(extra) != null) {
                 intent.setClass(getActivity(), ConversationActivity.class);
                 startActivity(intent);
                 return;
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.java b/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.java
index 35bf670..25543ed 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.java
@@ -30,8 +30,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import com.google.android.material.badge.BadgeDrawable;
-import com.google.android.material.bottomnavigation.BottomNavigationView;
 import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;
 import com.google.android.material.snackbar.Snackbar;
@@ -65,16 +63,16 @@
 import cx.ring.client.HomeActivity;
 import cx.ring.client.QRCodeActivity;
 import cx.ring.contacts.AvatarFactory;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.model.CallContact;
 import cx.ring.model.Conversation;
 import cx.ring.mvp.BaseSupportFragment;
-import cx.ring.navigation.RingNavigationFragment;
 import cx.ring.smartlist.SmartListPresenter;
 import cx.ring.smartlist.SmartListView;
 import cx.ring.smartlist.SmartListViewModel;
 import cx.ring.utils.ActionHelper;
 import cx.ring.utils.ClipboardHelper;
+import cx.ring.utils.ConversationPath;
 import cx.ring.utils.DeviceUtils;
 import cx.ring.viewholders.SmartListViewHolder;
 
@@ -235,7 +233,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
@@ -528,17 +526,9 @@
         }
 
         if (!isTabletMode) {
-            Intent intent = new Intent()
-                    .setClass(requireActivity(), ConversationActivity.class)
-                    .setAction(Intent.ACTION_VIEW)
-                    .putExtra(ConversationFragment.KEY_ACCOUNT_ID, accountId)
-                    .putExtra(ConversationFragment.KEY_CONTACT_RING_ID, contactId.toString());
-            startActivity(intent);
+            startActivity(new Intent(Intent.ACTION_VIEW, ConversationPath.toUri(accountId, contactId.toString()), requireContext(), ConversationActivity.class));
         } else {
-            Bundle bundle = new Bundle();
-            bundle.putString(ConversationFragment.KEY_CONTACT_RING_ID, contactId.toString());
-            bundle.putString(ConversationFragment.KEY_ACCOUNT_ID, accountId);
-            ((HomeActivity) requireActivity()).startConversationTablet(bundle);
+            ((HomeActivity) requireActivity()).startConversationTablet(ConversationPath.toBundle(accountId, contactId.toString()));
         }
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/history/DatabaseHelper.java b/ring-android/app/src/main/java/cx/ring/history/DatabaseHelper.java
index 9d81ae0..555ac63 100644
--- a/ring-android/app/src/main/java/cx/ring/history/DatabaseHelper.java
+++ b/ring-android/app/src/main/java/cx/ring/history/DatabaseHelper.java
@@ -35,7 +35,7 @@
 
 import javax.inject.Inject;
 
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.model.ConversationHistory;
 import cx.ring.model.DataTransfer;
 import cx.ring.model.Interaction;
@@ -65,7 +65,7 @@
     public DatabaseHelper(Context context, String dbDirectory) {
         super(context, dbDirectory, null, DATABASE_VERSION);
         Log.d(TAG, "Helper initialized for " + dbDirectory);
-        ((RingApplication) context.getApplicationContext()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) context.getApplicationContext()).getRingInjectionComponent().inject(this);
     }
 
     /**
diff --git a/ring-android/app/src/main/java/cx/ring/launch/LaunchActivity.java b/ring-android/app/src/main/java/cx/ring/launch/LaunchActivity.java
index d7e3cba..c70976d 100644
--- a/ring-android/app/src/main/java/cx/ring/launch/LaunchActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/launch/LaunchActivity.java
@@ -26,13 +26,10 @@
 
 import androidx.annotation.NonNull;
 import androidx.core.app.ActivityCompat;
-import androidx.appcompat.app.AlertDialog;
-
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 
 import cx.ring.R;
 import cx.ring.account.AccountWizardActivity;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.client.HomeActivity;
 import cx.ring.mvp.BaseActivity;
 import cx.ring.tv.account.TVAccountWizard;
@@ -43,9 +40,9 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         // dependency injection
-        RingApplication.getInstance().getRingInjectionComponent().inject(this);
+        JamiApplication.getInstance().getRingInjectionComponent().inject(this);
         super.onCreate(savedInstanceState);
-        RingApplication.getInstance().startDaemon();
+        JamiApplication.getInstance().startDaemon();
 
         setContentView(R.layout.activity_launch);
 
@@ -54,7 +51,7 @@
 
     @Override
     public void askPermissions(String[] permissionsWeCanAsk) {
-        ActivityCompat.requestPermissions(this, permissionsWeCanAsk, RingApplication.PERMISSIONS_REQUEST);
+        ActivityCompat.requestPermissions(this, permissionsWeCanAsk, JamiApplication.PERMISSIONS_REQUEST);
     }
 
     @Override
@@ -72,13 +69,13 @@
     @Override
     public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
         switch (requestCode) {
-            case RingApplication.PERMISSIONS_REQUEST: {
+            case JamiApplication.PERMISSIONS_REQUEST: {
                 if (grantResults.length == 0) {
                     return;
                 }
                 for (int i = 0, n = permissions.length; i < n; i++) {
                     String permission = permissions[i];
-                    RingApplication.getInstance().permissionHasBeenAsked(permission);
+                    JamiApplication.getInstance().permissionHasBeenAsked(permission);
                     switch (permission) {
                         case Manifest.permission.READ_CONTACTS:
                             presenter.contactPermissionChanged(grantResults[i] == PackageManager.PERMISSION_GRANTED);
diff --git a/ring-android/app/src/main/java/cx/ring/mvp/BaseFragment.java b/ring-android/app/src/main/java/cx/ring/mvp/BaseFragment.java
index 3755144..e100d0a 100644
--- a/ring-android/app/src/main/java/cx/ring/mvp/BaseFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/mvp/BaseFragment.java
@@ -21,7 +21,7 @@
 
 import android.app.Fragment;
 import android.os.Bundle;
-import androidx.annotation.IdRes;
+
 import androidx.annotation.LayoutRes;
 import androidx.annotation.Nullable;
 import android.view.LayoutInflater;
@@ -34,9 +34,8 @@
 import butterknife.ButterKnife;
 import butterknife.Unbinder;
 import cx.ring.R;
-import cx.ring.account.RingAccountCreationFragment;
-import cx.ring.application.RingApplication;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.application.JamiApplication;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.model.RingError;
 
 public abstract class BaseFragment<T extends RootPresenter> extends Fragment implements BaseView {
@@ -51,14 +50,14 @@
     @LayoutRes
     public abstract int getLayout();
 
-    public abstract void injectFragment(RingInjectionComponent component);
+    public abstract void injectFragment(JamiInjectionComponent component);
 
     @Nullable
     @Override
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
         final View inflatedView = inflater.inflate(getLayout(), container, false);
         // dependency injection
-        injectFragment(((RingApplication) getActivity().getApplication()).getRingInjectionComponent());
+        injectFragment(((JamiApplication) getActivity().getApplication()).getRingInjectionComponent());
         //Butterknife
         mUnbinder = ButterKnife.bind(this, inflatedView);
         return inflatedView;
diff --git a/ring-android/app/src/main/java/cx/ring/mvp/BaseSupportFragment.java b/ring-android/app/src/main/java/cx/ring/mvp/BaseSupportFragment.java
index cce358b..4bfdce3 100644
--- a/ring-android/app/src/main/java/cx/ring/mvp/BaseSupportFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/mvp/BaseSupportFragment.java
@@ -36,8 +36,8 @@
 import butterknife.Unbinder;
 import cx.ring.R;
 import cx.ring.account.RingAccountCreationFragment;
-import cx.ring.application.RingApplication;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.application.JamiApplication;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.model.RingError;
 
 public abstract class BaseSupportFragment<T extends RootPresenter> extends Fragment implements BaseView {
@@ -52,14 +52,14 @@
     @LayoutRes
     public abstract int getLayout();
 
-    public abstract void injectFragment(RingInjectionComponent component);
+    public abstract void injectFragment(JamiInjectionComponent component);
 
     @Nullable
     @Override
     public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
         final View inflatedView = inflater.inflate(getLayout(), container, false);
         // dependency injection
-        injectFragment(((RingApplication) getActivity().getApplication()).getRingInjectionComponent());
+        injectFragment(((JamiApplication) getActivity().getApplication()).getRingInjectionComponent());
         //Butterknife
         mUnbinder = ButterKnife.bind(this, inflatedView);
         return inflatedView;
diff --git a/ring-android/app/src/main/java/cx/ring/navigation/RingNavigationFragment.java b/ring-android/app/src/main/java/cx/ring/navigation/HomeNavigationFragment.java
similarity index 95%
rename from ring-android/app/src/main/java/cx/ring/navigation/RingNavigationFragment.java
rename to ring-android/app/src/main/java/cx/ring/navigation/HomeNavigationFragment.java
index 40932fa..8de5ee0 100644
--- a/ring-android/app/src/main/java/cx/ring/navigation/RingNavigationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/navigation/HomeNavigationFragment.java
@@ -21,6 +21,7 @@
 
 import android.Manifest;
 import android.app.Activity;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
@@ -59,7 +60,7 @@
 import cx.ring.account.AccountWizardActivity;
 import cx.ring.client.CallActivity;
 import cx.ring.client.HomeActivity;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.model.Account;
 import cx.ring.mvp.BaseSupportFragment;
 import cx.ring.services.VCardServiceImpl;
@@ -72,10 +73,10 @@
 import io.reactivex.disposables.CompositeDisposable;
 import io.reactivex.schedulers.Schedulers;
 
-public class RingNavigationFragment extends BaseSupportFragment<RingNavigationPresenter> implements NavigationAdapter.OnNavigationItemClicked,
-        AccountAdapter.OnAccountActionClicked, RingNavigationView {
+public class HomeNavigationFragment extends BaseSupportFragment<HomeNavigationPresenter> implements NavigationAdapter.OnNavigationItemClicked,
+        AccountAdapter.OnAccountActionClicked, HomeNavigationView {
 
-    public static final String TAG = RingNavigationFragment.class.getSimpleName();
+    public static final String TAG = HomeNavigationFragment.class.getSimpleName();
 
     /***************
      * Header views
@@ -160,7 +161,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
@@ -177,15 +178,15 @@
                 selectSection(Section.CONTACT_REQUESTS);
             } else if (fm.findFragmentByTag(HomeActivity.ACCOUNTS_TAG) != null &&
                     fm.findFragmentByTag(HomeActivity.ACCOUNTS_TAG).isAdded()) {
-                selectSection(RingNavigationFragment.Section.MANAGE);
+                selectSection(HomeNavigationFragment.Section.MANAGE);
             } else if (fm.findFragmentByTag(HomeActivity.SETTINGS_TAG) != null &&
                     fm.findFragmentByTag(HomeActivity.SETTINGS_TAG).isAdded()) {
-                selectSection(RingNavigationFragment.Section.SETTINGS);
+                selectSection(HomeNavigationFragment.Section.SETTINGS);
             } else if (fm.findFragmentByTag(HomeActivity.ABOUT_TAG) != null &&
                     fm.findFragmentByTag(HomeActivity.ABOUT_TAG).isAdded()) {
-                selectSection(RingNavigationFragment.Section.ABOUT);
+                selectSection(HomeNavigationFragment.Section.ABOUT);
             } else {
-                selectSection(RingNavigationFragment.Section.HOME);
+                selectSection(HomeNavigationFragment.Section.HOME);
             }
         }
     }
@@ -415,7 +416,7 @@
     }
 
     @Override
-    public void showViewModel(final RingNavigationViewModel viewModel) {
+    public void showViewModel(final HomeNavigationViewModel viewModel) {
         mAccountAdapter.replaceAll(viewModel.getAccounts());
         updateUserView(viewModel.getAccount());
         updateSelectedAccountView(viewModel.getAccount());
@@ -439,12 +440,13 @@
     public void gotToImageCapture() {
         Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
         try {
-            File file = AndroidFileUtils.createImageFile(getContext());
-            Uri uri = FileProvider.getUriForFile(getContext(), ContentUriHandler.AUTHORITY_FILES, file);
+            Context context = requireContext();
+            File file = AndroidFileUtils.createImageFile(context);
+            Uri uri = FileProvider.getUriForFile(context, ContentUriHandler.AUTHORITY_FILES, file);
             intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
             intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
             tmpProfilePhotoUri = uri;
-        } catch (IOException e) {
+        } catch (Exception e) {
             Log.e(TAG, "Can't create temp file", e);
         }
         startActivityForResult(intent, HomeActivity.REQUEST_CODE_PHOTO);
diff --git a/ring-android/app/src/main/java/cx/ring/navigation/NavigationAdapter.java b/ring-android/app/src/main/java/cx/ring/navigation/NavigationAdapter.java
index ec5a81e..eddf30f 100644
--- a/ring-android/app/src/main/java/cx/ring/navigation/NavigationAdapter.java
+++ b/ring-android/app/src/main/java/cx/ring/navigation/NavigationAdapter.java
@@ -40,11 +40,11 @@
 import cx.ring.R;
 
 class NavigationAdapter extends RecyclerView.Adapter<NavigationAdapter.NavigationItemView> {
-    private List<RingNavigationFragment.NavigationItem> mDataset;
+    private List<HomeNavigationFragment.NavigationItem> mDataset;
     private OnNavigationItemClicked mListener;
     private int mItemSelected;
 
-    NavigationAdapter(@NonNull ArrayList<RingNavigationFragment.NavigationItem> menu) {
+    NavigationAdapter(@NonNull ArrayList<HomeNavigationFragment.NavigationItem> menu) {
         mDataset = menu;
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/service/BootReceiver.java b/ring-android/app/src/main/java/cx/ring/service/BootReceiver.java
index 43aa11d..34a9cdd 100644
--- a/ring-android/app/src/main/java/cx/ring/service/BootReceiver.java
+++ b/ring-android/app/src/main/java/cx/ring/service/BootReceiver.java
@@ -24,7 +24,7 @@
 
 import javax.inject.Inject;
 
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.services.PreferencesService;
 
 public class BootReceiver extends BroadcastReceiver {
@@ -42,7 +42,7 @@
         final String action = intent.getAction();
         if (Intent.ACTION_BOOT_COMPLETED.equals(action) || Intent.ACTION_REBOOT.equals(action)) {
             try {
-                ((RingApplication) context.getApplicationContext()).getRingInjectionComponent().inject(this);
+                ((JamiApplication) context.getApplicationContext()).getRingInjectionComponent().inject(this);
                 boolean isAllowRingOnStartup = mPreferencesService.getSettings().isAllowRingOnStartup();
 
                 if (isAllowRingOnStartup) {
diff --git a/ring-android/app/src/main/java/cx/ring/service/CallNotificationService.java b/ring-android/app/src/main/java/cx/ring/service/CallNotificationService.java
index 6c57dfb..d45e72c 100644
--- a/ring-android/app/src/main/java/cx/ring/service/CallNotificationService.java
+++ b/ring-android/app/src/main/java/cx/ring/service/CallNotificationService.java
@@ -30,7 +30,7 @@
 
 import javax.inject.Inject;
 
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.services.NotificationService;
 
 public class CallNotificationService extends Service {
@@ -67,7 +67,7 @@
 
     @Override
     public void onCreate() {
-        ((RingApplication) getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getApplication()).getRingInjectionComponent().inject(this);
         super.onCreate();
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/service/DRingService.java b/ring-android/app/src/main/java/cx/ring/service/DRingService.java
index b8efb3a..ec78ea5 100644
--- a/ring-android/app/src/main/java/cx/ring/service/DRingService.java
+++ b/ring-android/app/src/main/java/cx/ring/service/DRingService.java
@@ -59,18 +59,16 @@
 import javax.inject.Singleton;
 
 import cx.ring.BuildConfig;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.client.CallActivity;
 import cx.ring.client.ConversationActivity;
 import cx.ring.facades.ConversationFacade;
 import cx.ring.fragments.ConversationFragment;
-import cx.ring.model.Account;
 import cx.ring.model.Codec;
 import cx.ring.model.Settings;
 import cx.ring.model.Uri;
 import cx.ring.services.AccountService;
 import cx.ring.services.CallService;
-import cx.ring.services.ConferenceService;
 import cx.ring.services.ContactService;
 import cx.ring.services.DaemonService;
 import cx.ring.services.DeviceRuntimeService;
@@ -79,6 +77,7 @@
 import cx.ring.services.NotificationService;
 import cx.ring.services.PreferencesService;
 import cx.ring.tv.call.TVCallActivity;
+import cx.ring.utils.ConversationPath;
 import cx.ring.utils.DeviceUtils;
 import io.reactivex.disposables.CompositeDisposable;
 
@@ -121,9 +120,6 @@
     protected CallService mCallService;
     @Inject
     @Singleton
-    protected ConferenceService mConferenceService;
-    @Inject
-    @Singleton
     protected AccountService mAccountService;
     @Inject
     @Singleton
@@ -292,72 +288,72 @@
 
         @Override
         public void removeConference(final String confID) throws RemoteException {
-            mConferenceService.removeConference(confID);
+            mCallService.removeConference(confID);
         }
 
         @Override
         public void joinParticipant(final String selCallID, final String dragCallID) throws RemoteException {
-            mConferenceService.joinParticipant(selCallID, dragCallID);
+            mCallService.joinParticipant(selCallID, dragCallID);
         }
 
         @Override
         public void addParticipant(final String callID, final String confID) throws RemoteException {
-            mConferenceService.addParticipant(callID, confID);
+            mCallService.addParticipant(callID, confID);
         }
 
         @Override
         public void addMainParticipant(final String confID) throws RemoteException {
-            mConferenceService.addMainParticipant(confID);
+            mCallService.addMainParticipant(confID);
         }
 
         @Override
         public void detachParticipant(final String callID) throws RemoteException {
-            mConferenceService.detachParticipant(callID);
+            mCallService.detachParticipant(callID);
         }
 
         @Override
         public void joinConference(final String selConfID, final String dragConfID) throws RemoteException {
-            mConferenceService.joinConference(selConfID, dragConfID);
+            mCallService.joinConference(selConfID, dragConfID);
         }
 
         @Override
         public void hangUpConference(final String confID) throws RemoteException {
-            mConferenceService.hangUpConference(confID);
+            mCallService.hangUpConference(confID);
         }
 
         @Override
         public void holdConference(final String confID) throws RemoteException {
-            mConferenceService.holdConference(confID);
+            mCallService.holdConference(confID);
         }
 
         @Override
         public void unholdConference(final String confID) throws RemoteException {
-            mConferenceService.unholdConference(confID);
+            mCallService.unholdConference(confID);
         }
 
         @Override
         public boolean isConferenceParticipant(final String callID) throws RemoteException {
-            return mConferenceService.isConferenceParticipant(callID);
+            return mCallService.isConferenceParticipant(callID);
         }
 
         @Override
         public Map<String, ArrayList<String>> getConferenceList() throws RemoteException {
-            return mConferenceService.getConferenceList();
+            return mCallService.getConferenceList();
         }
 
         @Override
         public List<String> getParticipantList(final String confID) throws RemoteException {
-            return mConferenceService.getParticipantList(confID);
+            return mCallService.getParticipantList(confID);
         }
 
         @Override
         public String getConferenceId(String callID) throws RemoteException {
-            return mConferenceService.getConferenceId(callID);
+            return mCallService.getConferenceId(callID);
         }
 
         @Override
         public String getConferenceDetails(final String callID) throws RemoteException {
-            return mConferenceService.getConferenceDetails(callID);
+            return mCallService.getConferenceState(callID);
         }
 
         @Override
@@ -432,7 +428,7 @@
 
         @Override
         public Map<String, String> getConference(final String id) throws RemoteException {
-            return mConferenceService.getConference(id);
+            return mCallService.getConferenceDetails(id);
         }
 
         @Override
@@ -564,7 +560,7 @@
         super.onCreate();
 
         // dependency injection
-        RingApplication.getInstance().getRingInjectionComponent().inject(this);
+        JamiApplication.getInstance().getRingInjectionComponent().inject(this);
         isRunning = true;
 
         if (mDeviceRuntimeService.hasContactPermission()) {
@@ -585,8 +581,8 @@
             showSystemNotification(s);
         }));
 
-        RingApplication.getInstance().bindDaemon();
-        RingApplication.getInstance().bootstrapDaemon();
+        JamiApplication.getInstance().bindDaemon();
+        JamiApplication.getInstance().bootstrapDaemon();
     }
 
     @Override
@@ -816,9 +812,7 @@
                 break;
             }
             case ACTION_CONV_ACCEPT:
-                startActivity(new Intent(Intent.ACTION_VIEW)
-                        .putExtras(extras)
-                        .setClass(getApplicationContext(), ConversationActivity.class)
+                startActivity(new Intent(Intent.ACTION_VIEW, ConversationPath.toUri(accountId, ringId), getApplicationContext(), ConversationActivity.class)
                         .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
                 break;
             default:
diff --git a/ring-android/app/src/main/java/cx/ring/service/RingJobService.java b/ring-android/app/src/main/java/cx/ring/service/RingJobService.java
index 3992db0..2fa9c5a 100644
--- a/ring-android/app/src/main/java/cx/ring/service/RingJobService.java
+++ b/ring-android/app/src/main/java/cx/ring/service/RingJobService.java
@@ -23,7 +23,7 @@
 import android.os.Build;
 
 import androidx.annotation.RequiresApi;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.utils.Log;
 
 @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@@ -45,7 +45,7 @@
             return false;
         Log.w(TAG, "onStartJob() " + params);
         try {
-            RingApplication.getInstance().startDaemon();
+            JamiApplication.getInstance().startDaemon();
             new Thread(() -> {
                 synchronized (this) {
                     try {
diff --git a/ring-android/app/src/main/java/cx/ring/services/CameraService.java b/ring-android/app/src/main/java/cx/ring/services/CameraService.java
index 82b2430..8fa1a88 100644
--- a/ring-android/app/src/main/java/cx/ring/services/CameraService.java
+++ b/ring-android/app/src/main/java/cx/ring/services/CameraService.java
@@ -40,7 +40,7 @@
     private static final String TAG = CameraService.class.getSimpleName();
 
     private final HashMap<String, VideoParams> mParams = new HashMap<>();
-    final Map<String, DeviceParams> mNativeParams = new HashMap<>();
+    private final Map<String, DeviceParams> mNativeParams = new HashMap<>();
 
     static class VideoDevices {
         final List<String> cameras = new ArrayList<>();
@@ -228,7 +228,7 @@
 
         StringMap toMap() {
             StringMap map = new StringMap();
-            map.set("size", Integer.toString(size.x) + "x" + Integer.toString(size.y));
+            map.set("size", size.x + "x" + size.y);
             map.set("rate", Long.toString(rate));
             return map;
         }
diff --git a/ring-android/app/src/main/java/cx/ring/services/CameraServiceCamera2.java b/ring-android/app/src/main/java/cx/ring/services/CameraServiceCamera2.java
index 0666625..f29ffaa 100644
--- a/ring-android/app/src/main/java/cx/ring/services/CameraServiceCamera2.java
+++ b/ring-android/app/src/main/java/cx/ring/services/CameraServiceCamera2.java
@@ -71,7 +71,7 @@
 
 @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
 class CameraServiceCamera2 extends CameraService {
-    private static final String TAG = CameraServiceCamera2.class.getName();
+    private static final String TAG = CameraServiceCamera2.class.getSimpleName();
     private static final int FPS_MAX = 30;
     private static final int FPS_TARGET = 15;
 
@@ -399,7 +399,7 @@
             SurfaceTexture texture = view.getSurfaceTexture();
             Surface s = new Surface(texture);
 
-            final Pair<MediaCodec, Surface> codec = hw_accel ? openCameraWithEncoder(videoParams, videoParams.getCodec(), handler, resolution, bitrate) : null;
+            final Pair<MediaCodec, Surface> codec = (hw_accel && videoParams.getCodec() != null) ? openCameraWithEncoder(videoParams, videoParams.getCodec(), handler, resolution, bitrate) : null;
 
             final List<Surface> targets = new ArrayList<>(2);
             targets.add(s);
diff --git a/ring-android/app/src/main/java/cx/ring/services/DataTransferService.java b/ring-android/app/src/main/java/cx/ring/services/DataTransferService.java
index 8b9c41d..1e3188d 100644
--- a/ring-android/app/src/main/java/cx/ring/services/DataTransferService.java
+++ b/ring-android/app/src/main/java/cx/ring/services/DataTransferService.java
@@ -30,7 +30,7 @@
 
 import javax.inject.Inject;
 
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.utils.Log;
 
 public class DataTransferService extends Service {
@@ -84,7 +84,7 @@
     @Override
     public void onCreate() {
         Log.d(TAG, "OnCreate(), Service has been initialized");
-        ((RingApplication) getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getApplication()).getRingInjectionComponent().inject(this);
         super.onCreate();
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/services/DeviceRuntimeServiceImpl.java b/ring-android/app/src/main/java/cx/ring/services/DeviceRuntimeServiceImpl.java
index fc111c3..2b293bb 100644
--- a/ring-android/app/src/main/java/cx/ring/services/DeviceRuntimeServiceImpl.java
+++ b/ring-android/app/src/main/java/cx/ring/services/DeviceRuntimeServiceImpl.java
@@ -35,7 +35,7 @@
 import javax.inject.Inject;
 import javax.inject.Named;
 
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.daemon.IntVect;
 import cx.ring.daemon.StringVect;
 import cx.ring.service.OpenSlParams;
@@ -99,7 +99,7 @@
 
     @Override
     public String getPushToken() {
-        return RingApplication.getInstance().getPushToken();
+        return JamiApplication.getInstance().getPushToken();
     }
 
     private boolean isNetworkConnectedForType(int connectivityManagerType) {
diff --git a/ring-android/app/src/main/java/cx/ring/services/HardwareServiceImpl.java b/ring-android/app/src/main/java/cx/ring/services/HardwareServiceImpl.java
index a817bdd..0d13039 100644
--- a/ring-android/app/src/main/java/cx/ring/services/HardwareServiceImpl.java
+++ b/ring-android/app/src/main/java/cx/ring/services/HardwareServiceImpl.java
@@ -47,6 +47,7 @@
 import cx.ring.daemon.Ringservice;
 import cx.ring.daemon.StringMap;
 import cx.ring.daemon.UintVect;
+import cx.ring.model.Conference;
 import cx.ring.model.SipCall;
 import cx.ring.model.SipCall.CallStatus;
 import cx.ring.utils.BluetoothWrapper;
@@ -65,7 +66,7 @@
 
     private static final String TAG = HardwareServiceImpl.class.getSimpleName();
     private static WeakReference<TextureView> mCameraPreviewSurface = new WeakReference<>(null);
-    private static WeakReference<SipCall> mCameraPreviewCall = new WeakReference<>(null);
+    private static WeakReference<Conference> mCameraPreviewCall = new WeakReference<>(null);
 
     private static final Map<String, WeakReference<SurfaceHolder>> videoSurfaces = Collections.synchronizedMap(new HashMap<>());
     private final Map<String, Shm> videoInputs = new HashMap<>();
@@ -457,10 +458,15 @@
             videoEvents.onNext(event);
             return;
         }
-        final SipCall call = mCameraPreviewCall.get();
-        if (call != null) {
-            call.setDetails(Ringservice.getCallDetails(call.getDaemonIdString()).toNative());
-            videoParams.codec = call.getVideoCodec();
+        final Conference conf = mCameraPreviewCall.get();
+        if (conf != null) {
+            SipCall call = conf.getCall();
+            if (call != null) {
+                call.setDetails(Ringservice.getCallDetails(call.getDaemonIdString()).toNative());
+                videoParams.codec = call.getVideoCodec();
+            } else {
+                videoParams.codec = null;
+            }
         }
         Log.w(TAG, "startCapture: call " + camId + " " + videoParams.codec);
 
@@ -523,7 +529,7 @@
             return;
         }
 
-        Log.w(TAG, "addVideoSurface " + id + holder.hashCode());
+        Log.w(TAG, "addVideoSurface " + id);
 
         Shm shm = videoInputs.get(id);
         WeakReference<SurfaceHolder> surfaceHolder = new WeakReference<>((SurfaceHolder) holder);
@@ -547,11 +553,36 @@
         event.w = shm.w;
         event.h = shm.h;
         videoEvents.onNext(event);
-
     }
 
     @Override
-    public void addPreviewVideoSurface(Object oholder, SipCall call) {
+    public void updateVideoSurfaceId(String currentId, String newId)
+    {
+        Log.w(TAG, "updateVideoSurfaceId " + currentId + " " + newId);
+
+        WeakReference<SurfaceHolder> surfaceHolder = videoSurfaces.get(currentId);
+        if (surfaceHolder == null) {
+            return;
+        }
+        SurfaceHolder surface = surfaceHolder.get();
+
+        Shm shm = videoInputs.get(currentId);
+        if (shm != null && shm.window != 0) {
+            try {
+                stopVideo(shm.id, shm.window);
+            } catch (Exception e) {
+                Log.e(TAG, "removeVideoSurface error" + e);
+            }
+            shm.window = 0;
+        }
+        videoSurfaces.remove(currentId);
+        if (surface != null) {
+            addVideoSurface(newId, surface);
+        }
+    }
+
+    @Override
+    public void addPreviewVideoSurface(Object oholder, Conference conference) {
         if (!(oholder instanceof TextureView)) {
             return;
         }
@@ -560,7 +591,7 @@
         if (mCameraPreviewSurface.get() == oholder)
             return;
         mCameraPreviewSurface = new WeakReference<>(holder);
-        mCameraPreviewCall = new WeakReference<>(call);
+        mCameraPreviewCall = new WeakReference<>(conference);
         if (mShouldCapture && !mIsCapturing) {
             startCapture(mCapturingId);
         }
@@ -569,6 +600,7 @@
     @Override
     public void removeVideoSurface(String id) {
         Log.i(TAG, "removeVideoSurface " + id);
+        videoSurfaces.remove(id);
         Shm shm = videoInputs.get(id);
         if (shm == null) {
             return;
diff --git a/ring-android/app/src/main/java/cx/ring/services/RingChooserTargetService.java b/ring-android/app/src/main/java/cx/ring/services/JamiChooserTargetService.java
similarity index 94%
rename from ring-android/app/src/main/java/cx/ring/services/RingChooserTargetService.java
rename to ring-android/app/src/main/java/cx/ring/services/JamiChooserTargetService.java
index b65b9b4..337523c 100644
--- a/ring-android/app/src/main/java/cx/ring/services/RingChooserTargetService.java
+++ b/ring-android/app/src/main/java/cx/ring/services/JamiChooserTargetService.java
@@ -37,7 +37,7 @@
 import javax.inject.Inject;
 import javax.inject.Singleton;
 
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.contacts.AvatarFactory;
 import cx.ring.facades.ConversationFacade;
 import cx.ring.fragments.ConversationFragment;
@@ -46,7 +46,7 @@
 import io.reactivex.schedulers.Schedulers;
 
 @RequiresApi(api = Build.VERSION_CODES.M)
-public class RingChooserTargetService extends ChooserTargetService {
+public class JamiChooserTargetService extends ChooserTargetService {
 
     @Inject
     @Singleton
@@ -57,8 +57,8 @@
     @Override
     public void onCreate() {
         super.onCreate();
-        RingApplication.getInstance().startDaemon();
-        RingApplication.getInstance().getRingInjectionComponent().inject(this);
+        JamiApplication.getInstance().startDaemon();
+        JamiApplication.getInstance().getRingInjectionComponent().inject(this);
         targetSize = (int) (AvatarFactory.SIZE_NOTIF * getResources().getDisplayMetrics().density);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/services/SharedPreferencesServiceImpl.java b/ring-android/app/src/main/java/cx/ring/services/SharedPreferencesServiceImpl.java
index a26b514..d5dcca3 100644
--- a/ring-android/app/src/main/java/cx/ring/services/SharedPreferencesServiceImpl.java
+++ b/ring-android/app/src/main/java/cx/ring/services/SharedPreferencesServiceImpl.java
@@ -37,7 +37,7 @@
 import javax.inject.Inject;
 
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.model.Settings;
 import cx.ring.utils.DeviceUtils;
 import cx.ring.utils.NetworkUtils;
@@ -130,7 +130,7 @@
 
     @Override
     public boolean isPushAllowed() {
-        String token = RingApplication.getInstance().getPushToken();
+        String token = JamiApplication.getInstance().getPushToken();
         return getSettings().isAllowPushNotifications() && !TextUtils.isEmpty(token) /*&& NetworkUtils.isPushAllowed(mContext, getSettings().isAllowMobileData())*/;
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/settings/SettingsFragment.java b/ring-android/app/src/main/java/cx/ring/settings/SettingsFragment.java
index cdb0f05..f2465e5 100644
--- a/ring-android/app/src/main/java/cx/ring/settings/SettingsFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/settings/SettingsFragment.java
@@ -19,18 +19,13 @@
  */
 package cx.ring.settings;
 
-import android.Manifest;
 import android.app.Activity;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.os.Build;
 import android.os.Bundle;
 import androidx.annotation.NonNull;
 
 import com.google.android.material.dialog.MaterialAlertDialogBuilder;
 import com.google.android.material.snackbar.Snackbar;
-import androidx.core.content.ContextCompat;
+
 import android.text.TextUtils;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -44,13 +39,12 @@
 import butterknife.OnCheckedChanged;
 import butterknife.OnClick;
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.client.HomeActivity;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.model.Settings;
 import cx.ring.mvp.BaseSupportFragment;
 import cx.ring.mvp.GenericView;
-import cx.ring.services.SharedPreferencesServiceImpl;
 
 /**
  * TODO: improvements : handle multiples permissions for feature.
@@ -78,7 +72,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
@@ -87,7 +81,7 @@
         setHasOptionsMenu(true);
         super.onViewCreated(view, savedInstanceState);
         mDarkTheme.setChecked(presenter.getDarkMode());
-        if (TextUtils.isEmpty(RingApplication.getInstance().getPushToken())) {
+        if (TextUtils.isEmpty(JamiApplication.getInstance().getPushToken())) {
             mGroupPushNotifications.setVisibility(View.GONE);
         }
         // loading preferences
diff --git a/ring-android/app/src/main/java/cx/ring/share/ScanFragment.java b/ring-android/app/src/main/java/cx/ring/share/ScanFragment.java
index 9e896b5..f8ed56c 100644
--- a/ring-android/app/src/main/java/cx/ring/share/ScanFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/share/ScanFragment.java
@@ -51,8 +51,8 @@
 
 
 import cx.ring.R;
-import cx.ring.application.RingApplication;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.application.JamiApplication;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.fragments.ConversationFragment;
 import cx.ring.mvp.BaseSupportFragment;
 
@@ -69,7 +69,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
     }
 
     private boolean hasCameraPermission() {
@@ -97,7 +97,7 @@
         if (isVisibleToUser) {
             if (!hasCameraPermission()) {
                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
-                    requestPermissions(new String[]{Manifest.permission.CAMERA}, RingApplication.PERMISSIONS_REQUEST);
+                    requestPermissions(new String[]{Manifest.permission.CAMERA}, JamiApplication.PERMISSIONS_REQUEST);
                 } else {
                     displayNoPermissionsError();
                 }
diff --git a/ring-android/app/src/main/java/cx/ring/share/ShareFragment.java b/ring-android/app/src/main/java/cx/ring/share/ShareFragment.java
index 0905676..fcba458 100644
--- a/ring-android/app/src/main/java/cx/ring/share/ShareFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/share/ShareFragment.java
@@ -36,7 +36,7 @@
 import butterknife.BindView;
 import butterknife.OnClick;
 import cx.ring.R;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.mvp.BaseSupportFragment;
 import cx.ring.mvp.GenericView;
 import cx.ring.utils.QRCodeUtils;
@@ -73,7 +73,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountExport.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountExport.java
index bc4e252..51f570c 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountExport.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountExport.java
@@ -45,7 +45,7 @@
 import cx.ring.R;
 import cx.ring.account.RingAccountSummaryPresenter;
 import cx.ring.account.RingAccountSummaryView;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.model.Account;
 import cx.ring.utils.AndroidFileUtils;
 
@@ -65,7 +65,7 @@
 
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
-        ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
 
         super.onViewCreated(view, savedInstanceState);
         presenter.setAccountId(mIdAccount);
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountWizard.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountWizard.java
index c8d1e79..d220f54 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountWizard.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVAccountWizard.java
@@ -37,7 +37,7 @@
 import cx.ring.account.AccountCreationModelImpl;
 import cx.ring.account.AccountWizardPresenter;
 import cx.ring.account.AccountWizardView;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.model.Account;
 import cx.ring.model.AccountConfig;
 import cx.ring.mvp.AccountCreationModel;
@@ -61,10 +61,10 @@
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
-        RingApplication.getInstance().getRingInjectionComponent().inject(this);
+        JamiApplication.getInstance().getRingInjectionComponent().inject(this);
         super.onCreate(savedInstanceState);
         ButterKnife.bind(this);
-        RingApplication.getInstance().startDaemon();
+        JamiApplication.getInstance().startDaemon();
 
         Intent intent = getIntent();
         if (intent != null) {
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVHomeAccountCreationFragment.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVHomeAccountCreationFragment.java
index 088d8d4..56e79b2 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVHomeAccountCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVHomeAccountCreationFragment.java
@@ -31,7 +31,7 @@
 import cx.ring.account.AccountCreationModelImpl;
 import cx.ring.account.HomeAccountCreationPresenter;
 import cx.ring.account.HomeAccountCreationView;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 
 public class TVHomeAccountCreationFragment
         extends RingGuidedStepFragment<HomeAccountCreationPresenter>
@@ -42,7 +42,7 @@
 
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
-        ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
 
         super.onViewCreated(view, savedInstanceState);
     }
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileCreationFragment.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileCreationFragment.java
index 235cd28..03914bf 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileCreationFragment.java
@@ -25,7 +25,6 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
-import android.net.Uri;
 import android.os.Bundle;
 import android.provider.MediaStore;
 import androidx.annotation.NonNull;
@@ -34,7 +33,6 @@
 import androidx.leanback.widget.GuidedAction;
 import androidx.appcompat.app.AlertDialog;
 import android.text.TextUtils;
-import android.util.Log;
 import android.view.View;
 
 import java.util.List;
@@ -44,14 +42,13 @@
 import cx.ring.account.ProfileCreationFragment;
 import cx.ring.account.ProfileCreationPresenter;
 import cx.ring.account.ProfileCreationView;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.model.Account;
 import cx.ring.mvp.AccountCreationModel;
 import cx.ring.tv.camera.CustomCameraActivity;
 import cx.ring.utils.AndroidFileUtils;
 import cx.ring.views.AvatarDrawable;
 import io.reactivex.Single;
-import io.reactivex.android.schedulers.AndroidSchedulers;
 
 public class TVProfileCreationFragment extends RingGuidedStepFragment<ProfileCreationPresenter>
         implements ProfileCreationView {
@@ -108,7 +105,7 @@
 
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
-        ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
         super.onViewCreated(view, savedInstanceState);
 
         if (mModel == null) {
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileEditingFragment.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileEditingFragment.java
index c6bff18..44af925 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileEditingFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVProfileEditingFragment.java
@@ -27,7 +27,6 @@
 import android.os.Bundle;
 import android.provider.MediaStore;
 import androidx.annotation.NonNull;
-import androidx.leanback.app.GuidedStepSupportFragment;
 import androidx.leanback.widget.GuidanceStylist;
 import androidx.leanback.widget.GuidedAction;
 import androidx.appcompat.app.AlertDialog;
@@ -39,11 +38,11 @@
 
 import cx.ring.R;
 import cx.ring.account.ProfileCreationFragment;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.model.Account;
-import cx.ring.navigation.RingNavigationPresenter;
-import cx.ring.navigation.RingNavigationView;
-import cx.ring.navigation.RingNavigationViewModel;
+import cx.ring.navigation.HomeNavigationPresenter;
+import cx.ring.navigation.HomeNavigationView;
+import cx.ring.navigation.HomeNavigationViewModel;
 import cx.ring.tv.camera.CustomCameraActivity;
 import cx.ring.utils.AndroidFileUtils;
 import cx.ring.utils.BitmapUtils;
@@ -52,8 +51,8 @@
 import io.reactivex.android.schedulers.AndroidSchedulers;
 import io.reactivex.schedulers.Schedulers;
 
-public class TVProfileEditingFragment extends RingGuidedStepFragment<RingNavigationPresenter>
-        implements RingNavigationView {
+public class TVProfileEditingFragment extends RingGuidedStepFragment<HomeNavigationPresenter>
+        implements HomeNavigationView {
 
     private static final int USER_NAME = 1;
     private static final int GALLERY = 2;
@@ -107,7 +106,7 @@
 
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
-        ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
         super.onViewCreated(view, savedInstanceState);
         iconSize = (int) getResources().getDimension(R.dimen.tv_avatar_size);
     }
@@ -157,7 +156,7 @@
     }
 
     @Override
-    public void showViewModel(RingNavigationViewModel viewModel) {
+    public void showViewModel(HomeNavigationViewModel viewModel) {
         Account account = viewModel.getAccount();
         if (account == null) {
             Log.e(TAG, "Not able to get current account");
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVRingAccountCreationFragment.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVRingAccountCreationFragment.java
index a95df88..7c998db 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVRingAccountCreationFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVRingAccountCreationFragment.java
@@ -35,7 +35,7 @@
 import cx.ring.account.AccountCreationModelImpl;
 import cx.ring.account.RingAccountCreationPresenter;
 import cx.ring.account.RingAccountCreationView;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.mvp.AccountCreationModel;
 import cx.ring.utils.Log;
 import cx.ring.utils.StringUtils;
@@ -84,7 +84,7 @@
 
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
-        ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
 
         // Bind the presenter to the view
         super.onViewCreated(view, savedInstanceState);
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVRingLinkAccountFragment.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVRingLinkAccountFragment.java
index 28f3953..af91933 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVRingLinkAccountFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVRingLinkAccountFragment.java
@@ -31,7 +31,7 @@
 import cx.ring.account.AccountCreationModelImpl;
 import cx.ring.account.RingLinkAccountPresenter;
 import cx.ring.account.RingLinkAccountView;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.mvp.AccountCreationModel;
 import cx.ring.utils.StringUtils;
 
@@ -53,7 +53,7 @@
 
     @Override
     public void onViewCreated(View view, Bundle savedInstanceState) {
-        ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
         super.onViewCreated(view, savedInstanceState);
 
         presenter.init(model);
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVSettingsFragment.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVSettingsFragment.java
index fa4120f..b191ea5 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVSettingsFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVSettingsFragment.java
@@ -33,12 +33,11 @@
 import android.view.View;
 
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.fragments.GeneralAccountPresenter;
 import cx.ring.fragments.GeneralAccountView;
 import cx.ring.model.Account;
 import cx.ring.model.ConfigKey;
-import cx.ring.services.SharedPreferencesServiceImpl;
 
 public class TVSettingsFragment extends LeanbackSettingsFragmentCompat {
 
@@ -71,7 +70,7 @@
 
         @Override
         public void onViewCreated(View view, Bundle savedInstanceState) {
-            ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+            ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
             super.onViewCreated(view, savedInstanceState);
             presenter.init();
         }
diff --git a/ring-android/app/src/main/java/cx/ring/tv/account/TVShareFragment.java b/ring-android/app/src/main/java/cx/ring/tv/account/TVShareFragment.java
index 1d5cd78..2dafd65 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/account/TVShareFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/account/TVShareFragment.java
@@ -30,7 +30,7 @@
 import butterknife.BindString;
 import butterknife.BindView;
 import cx.ring.R;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.model.Account;
 import cx.ring.mvp.BaseFragment;
 import cx.ring.mvp.GenericView;
@@ -65,7 +65,7 @@
     }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/tv/call/TVCallActivity.java b/ring-android/app/src/main/java/cx/ring/tv/call/TVCallActivity.java
index cc34d9a..b293511 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/call/TVCallActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/call/TVCallActivity.java
@@ -18,10 +18,6 @@
  */
 package cx.ring.tv.call;
 
-import android.app.Activity;
-import android.app.Fragment;
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
 import android.media.AudioManager;
 import android.os.Build;
 import android.os.Bundle;
@@ -30,14 +26,19 @@
 import android.view.MotionEvent;
 import android.view.WindowManager;
 
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentTransaction;
+
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.call.CallView;
 import cx.ring.fragments.ConversationFragment;
 import cx.ring.services.NotificationService;
 import cx.ring.utils.Log;
 
-public class TVCallActivity extends Activity {
+public class TVCallActivity extends FragmentActivity {
 
     static final String TAG = TVCallActivity.class.getSimpleName();
     private static final String CALL_FRAGMENT_TAG = "CALL_FRAGMENT_TAG";
@@ -59,14 +60,14 @@
         setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);
 
         // dependency injection
-        RingApplication.getInstance().getRingInjectionComponent().inject(this);
-        RingApplication.getInstance().startDaemon();
+        JamiApplication.getInstance().getRingInjectionComponent().inject(this);
+        JamiApplication.getInstance().startDaemon();
 
         boolean audioOnly = false;
         String accountId = getIntent().getStringExtra(ConversationFragment.KEY_ACCOUNT_ID);
         String ringId = getIntent().getStringExtra(ConversationFragment.KEY_CONTACT_RING_ID);
 
-        FragmentManager fragmentManager = getFragmentManager();
+        FragmentManager fragmentManager = getSupportFragmentManager();
         FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
 
         if (!TextUtils.isEmpty(ringId)) {
@@ -91,7 +92,7 @@
 
     @Override
     public void onUserLeaveHint () {
-        Fragment fragment = getFragmentManager().findFragmentByTag(CALL_FRAGMENT_TAG);
+        Fragment fragment = getSupportFragmentManager().findFragmentByTag(CALL_FRAGMENT_TAG);
         if (fragment instanceof CallView) {
             CallView callFragment = (CallView) fragment;
             callFragment.onUserLeave();
diff --git a/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.java b/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.java
index f388338..7664473 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.java
@@ -27,7 +27,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.content.res.Configuration;
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
@@ -57,27 +56,32 @@
 import com.rodolfonavalon.shaperipplelibrary.model.Circle;
 
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Locale;
 
 import javax.inject.Inject;
 
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.call.CallPresenter;
 import cx.ring.call.CallView;
+import cx.ring.client.ContactDetailsActivity;
+import cx.ring.client.ConversationSelectionActivity;
 import cx.ring.databinding.TvFragCallBinding;
-import cx.ring.dependencyinjection.RingInjectionComponent;
+import cx.ring.dependencyinjection.JamiInjectionComponent;
 import cx.ring.fragments.CallFragment;
 import cx.ring.model.CallContact;
 import cx.ring.model.SipCall;
-import cx.ring.mvp.BaseFragment;
+import cx.ring.mvp.BaseSupportFragment;
 import cx.ring.services.DeviceRuntimeService;
 import cx.ring.services.HardwareService;
 import cx.ring.tv.main.HomeActivity;
+import cx.ring.utils.ContentUriHandler;
+import cx.ring.utils.ConversationPath;
 import cx.ring.views.AvatarDrawable;
 import io.reactivex.disposables.CompositeDisposable;
 
-public class TVCallFragment extends BaseFragment<CallPresenter> implements CallView {
+public class TVCallFragment extends BaseSupportFragment<CallPresenter> implements CallView {
 
     public static final String TAG = TVCallFragment.class.getSimpleName();
 
@@ -90,6 +94,7 @@
     public static final String KEY_CONTACT_RING_ID = "CONTACT_RING_ID";
     public static final String KEY_AUDIO_ONLY = "AUDIO_ONLY";
 
+    private static final int REQUEST_CODE_ADD_PARTICIPANT = 6;
     private static final int REQUEST_PERMISSION_INCOMING = 1003;
     private static final int REQUEST_PERMISSION_OUTGOING = 1004;
 
@@ -154,14 +159,14 @@
     public void handleCallWakelock(boolean isAudioOnly) { }
 
     @Override
-    public void injectFragment(RingInjectionComponent component) {
+    public void injectFragment(JamiInjectionComponent component) {
         component.inject(this);
     }
 
     @Nullable
     @Override
-    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
-        injectFragment(((RingApplication) getActivity().getApplication()).getRingInjectionComponent());
+    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
+        injectFragment(((JamiApplication) getActivity().getApplication()).getRingInjectionComponent());
         binding = TvFragCallBinding.inflate(inflater, container, false);
         binding.setPresenter(this);
         return binding.getRoot();
@@ -193,7 +198,7 @@
     };
 
     @Override
-    public void onViewCreated(View view, Bundle savedInstanceState) {
+    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
         PowerManager powerManager = (PowerManager) getActivity().getSystemService(Context.POWER_SERVICE);
         mScreenWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "ring:callLock");
@@ -286,7 +291,19 @@
     }
 
     @Override
-    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {
+    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+        if (requestCode == REQUEST_CODE_ADD_PARTICIPANT) {
+            if (resultCode == Activity.RESULT_OK && data != null) {
+                ConversationPath path = ConversationPath.fromUri(data.getData());
+                if (path != null) {
+                    presenter.addConferenceParticipant(path.getAccountId(), path.getContactId());
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
         if(!isInPictureInPictureMode) {
             mBackstackLost = true;
         }
@@ -359,7 +376,8 @@
     }
 
     @Override
-    public void updateContactBubble(@NonNull final CallContact contact) {
+    public void updateContactBubble(@NonNull final List<SipCall> calls) {
+        CallContact contact = calls.get(0).getContact();
         String username = contact.getRingUsername();
         String ringId = contact.getIds().get(0);
         Log.d(TAG, "updateContactBubble: username=" + username + ", ringId=" + ringId + " photo:" + contact.getPhoto());
@@ -391,7 +409,7 @@
     }
 
     @Override
-    public void initMenu(boolean isSpeakerOn, boolean hasContact, boolean displayFlip, boolean canDial, boolean onGoingCall) {
+    public void initMenu(boolean isSpeakerOn, boolean displayFlip, boolean canDial, boolean onGoingCall) {
 
     }
 
@@ -557,6 +575,12 @@
     }
 
     @Override
+    public void goToContact(String accountId, CallContact contact) {
+        startActivity(new Intent(Intent.ACTION_VIEW, android.net.Uri.withAppendedPath(android.net.Uri.withAppendedPath(ContentUriHandler.CONTACT_CONTENT_URI, accountId), contact.getPrimaryNumber()))
+                .setClass(requireContext(), ContactDetailsActivity.class));
+    }
+
+    @Override
     public void goToConversation(String accountId, String conversationId) {
 
     }
@@ -566,6 +590,15 @@
 
     }
 
+    @Override
+    public void startAddParticipant(String conferenceId) {
+        startActivityForResult(
+                new Intent(Intent.ACTION_PICK)
+                        .setClass(requireActivity(), ConversationSelectionActivity.class)
+                        .putExtra(KEY_CONF_ID, conferenceId),
+                REQUEST_CODE_ADD_PARTICIPANT);
+    }
+
     public void hangUpClicked() {
         presenter.hangupCall();
     }
@@ -599,7 +632,7 @@
     }
 
     @Override
-    public void enterPipMode(SipCall sipCall) {
+    public void enterPipMode(String callId) {
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
             return;
         }
@@ -616,9 +649,9 @@
                 paramBuilder.setAspectRatio(new Rational(w, h));
                 paramBuilder.setSourceRectHint(videoBounds);
             }
-            getActivity().enterPictureInPictureMode(paramBuilder.build());
+            requireActivity().enterPictureInPictureMode(paramBuilder.build());
         } else {
-            getActivity().enterPictureInPictureMode();
+            requireActivity().enterPictureInPictureMode();
         }
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/tv/cards/iconcards/IconCardPresenter.java b/ring-android/app/src/main/java/cx/ring/tv/cards/iconcards/IconCardPresenter.java
index 7470b29..ba0cbaf 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/cards/iconcards/IconCardPresenter.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/cards/iconcards/IconCardPresenter.java
@@ -23,13 +23,13 @@
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import androidx.leanback.widget.ImageCardView;
-import androidx.core.content.ContextCompat;
+
 import android.view.ContextThemeWrapper;
 import android.widget.ImageView;
 
 
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.tv.cards.AbstractCardPresenter;
 import cx.ring.tv.cards.Card;
 
@@ -43,7 +43,7 @@
 
     @Override
     protected ImageCardView onCreateView() {
-        RingApplication.getInstance().getRingInjectionComponent().inject(this);
+        JamiApplication.getInstance().getRingInjectionComponent().inject(this);
         ImageCardView imageCardView = new ImageCardView(getContext());
         final ImageView image = imageCardView.getMainImageView();
         image.setBackgroundResource(R.drawable.icon_focused);
diff --git a/ring-android/app/src/main/java/cx/ring/tv/contact/TVContactFragment.java b/ring-android/app/src/main/java/cx/ring/tv/contact/TVContactFragment.java
index eb7763d..9001032 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/contact/TVContactFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/contact/TVContactFragment.java
@@ -41,7 +41,7 @@
 import androidx.leanback.widget.ListRow;
 import androidx.leanback.widget.ListRowPresenter;
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.fragments.ConversationFragment;
 import cx.ring.model.Uri;
 import cx.ring.tv.call.TVCallActivity;
@@ -60,7 +60,7 @@
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
-        ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
         super.onCreate(savedInstanceState);
         mContactUri = (Uri) getActivity().getIntent().getSerializableExtra(TVContactActivity.CONTACT_REQUEST);
     }
diff --git a/ring-android/app/src/main/java/cx/ring/tv/contactrequest/TVContactRequestFragment.java b/ring-android/app/src/main/java/cx/ring/tv/contactrequest/TVContactRequestFragment.java
index e9921cb..2f53e70 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/contactrequest/TVContactRequestFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/contactrequest/TVContactRequestFragment.java
@@ -40,7 +40,7 @@
 import android.view.View;
 
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.model.Uri;
 import cx.ring.tv.main.BaseDetailFragment;
 import cx.ring.tv.model.TVListViewModel;
@@ -58,7 +58,7 @@
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
-        ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
         super.onCreate(savedInstanceState);
         mSelectedContactRequest = (Uri) getActivity().getIntent()
                 .getSerializableExtra(TVContactRequestActivity.CONTACT_REQUEST);
diff --git a/ring-android/app/src/main/java/cx/ring/tv/main/HomeActivity.java b/ring-android/app/src/main/java/cx/ring/tv/main/HomeActivity.java
index 7a48ebb..438377b 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/main/HomeActivity.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/main/HomeActivity.java
@@ -27,7 +27,7 @@
 import androidx.fragment.app.FragmentActivity;
 
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 
 public class HomeActivity extends FragmentActivity {
     private BackgroundManager mBackgroundManager;
@@ -35,7 +35,7 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        RingApplication.getInstance().startDaemon();
+        JamiApplication.getInstance().startDaemon();
         setContentView(R.layout.tv_activity_home);
         mBackgroundManager = BackgroundManager.getInstance(this);
         mBackgroundManager.attach(getWindow());
diff --git a/ring-android/app/src/main/java/cx/ring/tv/main/MainFragment.java b/ring-android/app/src/main/java/cx/ring/tv/main/MainFragment.java
index 2dea096..bfdde3f 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/main/MainFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/main/MainFragment.java
@@ -47,10 +47,10 @@
 import java.util.List;
 
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.fragments.ConversationFragment;
 import cx.ring.model.Account;
-import cx.ring.navigation.RingNavigationViewModel;
+import cx.ring.navigation.HomeNavigationViewModel;
 import cx.ring.services.VCardServiceImpl;
 import cx.ring.tv.about.AboutActivity;
 import cx.ring.tv.account.TVAccountExport;
@@ -94,7 +94,7 @@
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-        ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
         return super.onCreateView(inflater, container, savedInstanceState);
     }
 
@@ -258,7 +258,7 @@
     }
 
     @Override
-    public void displayAccountInfos(final RingNavigationViewModel viewModel) {
+    public void displayAccountInfos(final HomeNavigationViewModel viewModel) {
         Context context = getContext();
         if (context == null) {
             Log.e(TAG, "displayAccountInfos: Not able to get context");
diff --git a/ring-android/app/src/main/java/cx/ring/tv/main/MainPresenter.java b/ring-android/app/src/main/java/cx/ring/tv/main/MainPresenter.java
index e3795d5..606e152 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/main/MainPresenter.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/main/MainPresenter.java
@@ -32,11 +32,10 @@
 import cx.ring.model.Conversation;
 import cx.ring.model.RingError;
 import cx.ring.mvp.RootPresenter;
-import cx.ring.navigation.RingNavigationViewModel;
+import cx.ring.navigation.HomeNavigationViewModel;
 import cx.ring.services.AccountService;
 import cx.ring.services.ContactService;
 import cx.ring.services.HardwareService;
-import cx.ring.smartlist.SmartListViewModel;
 import cx.ring.tv.model.TVListViewModel;
 import cx.ring.utils.Log;
 import io.reactivex.Observable;
@@ -193,7 +192,7 @@
                 .observeOn(mUiScheduler)
                 .subscribe(accounts -> {
                     Account account = accounts.isEmpty() ? null : accounts.get(0);
-                    RingNavigationViewModel viewModel = new RingNavigationViewModel(account, accounts);
+                    HomeNavigationViewModel viewModel = new HomeNavigationViewModel(account, accounts);
                     getView().displayAccountInfos(viewModel);
                 }, e-> Log.d(TAG, "reloadAccountInfos getProfileAccountList onError", e)));
     }
diff --git a/ring-android/app/src/main/java/cx/ring/tv/main/MainView.java b/ring-android/app/src/main/java/cx/ring/tv/main/MainView.java
index d6d2f72..7e08306 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/main/MainView.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/main/MainView.java
@@ -19,11 +19,9 @@
  */
 package cx.ring.tv.main;
 
-import android.graphics.drawable.BitmapDrawable;
-
 import java.util.List;
 
-import cx.ring.navigation.RingNavigationViewModel;
+import cx.ring.navigation.HomeNavigationViewModel;
 import cx.ring.tv.model.TVListViewModel;
 
 public interface MainView {
@@ -40,7 +38,7 @@
 
     void displayErrorToast(int error);
 
-    void displayAccountInfos(RingNavigationViewModel viewModel);
+    void displayAccountInfos(HomeNavigationViewModel viewModel);
 
     void showExportDialog(String pAccountID);
 
diff --git a/ring-android/app/src/main/java/cx/ring/tv/search/RingSearchFragment.java b/ring-android/app/src/main/java/cx/ring/tv/search/RingSearchFragment.java
index e5fcff4..f7d289d 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/search/RingSearchFragment.java
+++ b/ring-android/app/src/main/java/cx/ring/tv/search/RingSearchFragment.java
@@ -36,14 +36,13 @@
 import butterknife.ButterKnife;
 import butterknife.Unbinder;
 import cx.ring.R;
-import cx.ring.application.RingApplication;
+import cx.ring.application.JamiApplication;
 import cx.ring.fragments.ConversationFragment;
 import cx.ring.model.CallContact;
 import cx.ring.tv.call.TVCallActivity;
 import cx.ring.tv.cards.Card;
 import cx.ring.tv.cards.CardPresenterSelector;
 import cx.ring.tv.cards.contacts.ContactCard;
-import cx.ring.utils.Log;
 
 public class RingSearchFragment extends BaseSearchFragment<RingSearchPresenter>
         implements SearchSupportFragment.SearchResultProvider, RingSearchView {
@@ -64,7 +63,7 @@
         setSearchResultProvider(this);
 
         // dependency injection
-        ((RingApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
+        ((JamiApplication) getActivity().getApplication()).getRingInjectionComponent().inject(this);
         setOnItemViewClickedListener((itemViewHolder, item, rowViewHolder, row) -> presenter.contactClicked(((ContactCard) item).getModel().getContact()));
         setBadgeDrawable(ContextCompat.getDrawable(getActivity(), R.mipmap.ic_launcher));
         setSearchQuery("", false);
diff --git a/ring-android/app/src/main/java/cx/ring/utils/ContentUriHandler.java b/ring-android/app/src/main/java/cx/ring/utils/ContentUriHandler.java
index 4a3bf1a..24c0b1c 100644
--- a/ring-android/app/src/main/java/cx/ring/utils/ContentUriHandler.java
+++ b/ring-android/app/src/main/java/cx/ring/utils/ContentUriHandler.java
@@ -19,9 +19,14 @@
  */
 package cx.ring.utils;
 
+import android.content.Intent;
 import android.net.Uri;
+import android.os.Bundle;
+
+import java.util.List;
 
 import cx.ring.BuildConfig;
+import cx.ring.fragments.ConversationFragment;
 
 /**
  * This class distributes content uri used to pass along data in the app
@@ -33,7 +38,7 @@
 
     private static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
 
-    public static final Uri CONVERSATION_CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "conversations");
+    public static final Uri CONVERSATION_CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "conversation");
     public static final Uri ACCOUNTS_CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "accounts");
     public static final Uri CONTACT_CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "contact");
 
diff --git a/ring-android/app/src/main/java/cx/ring/utils/ConversationPath.java b/ring-android/app/src/main/java/cx/ring/utils/ConversationPath.java
new file mode 100644
index 0000000..9b66085
--- /dev/null
+++ b/ring-android/app/src/main/java/cx/ring/utils/ConversationPath.java
@@ -0,0 +1,78 @@
+package cx.ring.utils;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+
+import java.util.List;
+
+import cx.ring.fragments.ConversationFragment;
+
+public class ConversationPath {
+    private final String accountId;
+    private final String contactId;
+    public ConversationPath(String account, String contact) {
+        accountId = account;
+        contactId = contact;
+    }
+    public String getAccountId() {
+        return accountId;
+    }
+    public String getContactId() {
+        return contactId;
+    }
+    public Uri toUri() {
+        return toUri(accountId, contactId);
+    }
+    public static Uri toUri(String accountId, String contactId) {
+        Uri.Builder builder = ContentUriHandler.CONVERSATION_CONTENT_URI.buildUpon();
+        builder = builder.appendEncodedPath(accountId);
+        builder = builder.appendEncodedPath(contactId);
+        return builder.build();
+    }
+
+    public Bundle toBundle() {
+        return toBundle(accountId, contactId);
+    }
+    public void toBundle(Bundle bundle) {
+        bundle.putString(ConversationFragment.KEY_CONTACT_RING_ID, contactId);
+        bundle.putString(ConversationFragment.KEY_ACCOUNT_ID, accountId);
+    }
+    public static Bundle toBundle(String accountId, String contactId) {
+        Bundle bundle = new Bundle();
+        bundle.putString(ConversationFragment.KEY_CONTACT_RING_ID, contactId);
+        bundle.putString(ConversationFragment.KEY_ACCOUNT_ID, accountId);
+        return bundle;
+    }
+
+    public static ConversationPath fromUri(Uri uri) {
+        if (uri != null && uri.toString().startsWith(ContentUriHandler.CONVERSATION_CONTENT_URI.toString())) {
+            List<String> pathSegments = uri.getPathSegments();
+            if (pathSegments.size() > 2) {
+                return new ConversationPath(pathSegments.get(pathSegments.size() - 2), pathSegments.get(pathSegments.size() - 1));
+            }
+        }
+        return null;
+    }
+    public static ConversationPath fromBundle(Bundle bundle) {
+        if (bundle != null) {
+            String accountId = bundle.getString(ConversationFragment.KEY_ACCOUNT_ID);
+            String contactId = bundle.getString(ConversationFragment.KEY_CONTACT_RING_ID);
+            if (accountId != null && contactId != null) {
+                return new ConversationPath(accountId, contactId);
+            }
+        }
+        return null;
+    }
+
+    public static ConversationPath fromIntent(Intent intent) {
+        if (intent != null) {
+            Uri uri = intent.getData();
+            ConversationPath conversationPath = fromUri(uri);
+            if (conversationPath != null)
+                return conversationPath;
+            return fromBundle(intent.getExtras());
+        }
+        return null;
+    }
+}
diff --git a/ring-android/app/src/main/res/drawable/background_conference_participant.xml b/ring-android/app/src/main/res/drawable/background_conference_participant.xml
new file mode 100644
index 0000000..60fe659
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable/background_conference_participant.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:shape="rectangle">
+            <solid android:color="#D8FFFFFF" />
+            <corners
+                android:radius="6dp" />
+        </shape>
+    </item>
+</selector>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout-land/frag_call.xml b/ring-android/app/src/main/res/layout-land/frag_call.xml
deleted file mode 100644
index a39c927..0000000
--- a/ring-android/app/src/main/res/layout-land/frag_call.xml
+++ /dev/null
@@ -1,282 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
-Copyright (C) 2004-2016 Savoir-faire Linux Inc.
-
-Author: Adrien Beraud <adrien.beraud@savoirfairelinux.com>
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program.  If not, see <http://www.gnu.org/licenses/>.
--->
-<layout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    xmlns:tools="http://schemas.android.com/tools">
-
-    <data>
-
-        <variable
-            name="presenter"
-            type="cx.ring.fragments.CallFragment" />
-    </data>
-
-    <FrameLayout
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:keepScreenOn="true"
-        tools:context=".client.CallActivity">
-
-        <RelativeLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent">
-
-            <SurfaceView
-                android:id="@+id/video_surface"
-                android:layout_width="match_parent"
-                android:layout_height="32dp"
-                android:layout_centerInParent="true"
-                android:layout_gravity="center"
-                android:visibility="gone"
-                tools:visibility="visible" />
-
-            <androidx.cardview.widget.CardView
-                android:id="@+id/preview_container"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_alignParentEnd="true"
-                android:layout_alignParentBottom="true"
-                android:layout_margin="12dp"
-                android:visibility="gone"
-                app:cardCornerRadius="16dp"
-                app:cardPreventCornerOverlap="false">
-
-                <cx.ring.views.AutoFitTextureView
-                    android:id="@+id/preview_surface"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:visibility="visible"
-                    tools:visibility="visible" />
-            </androidx.cardview.widget.CardView>
-
-        </RelativeLayout>
-
-        <RelativeLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:animateLayoutChanges="true"
-            android:clipToPadding="false"
-            android:fitsSystemWindows="true">
-
-            <LinearLayout
-                android:id="@+id/contact_bubble_layout"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_centerInParent="true"
-                android:gravity="center"
-                android:orientation="horizontal"
-                android:visibility="visible"
-                android:weightSum="100">
-
-                <RelativeLayout
-                    android:layout_width="230dp"
-                    android:layout_height="230dp"
-                    android:layout_weight="50">
-
-                    <com.rodolfonavalon.shaperipplelibrary.ShapeRipple
-                        android:id="@+id/shape_ripple"
-                        android:layout_width="match_parent"
-                        android:layout_height="match_parent"
-                        app:enable_color_transition="true"
-                        app:ripple_color="@color/white"
-                        app:ripple_count="3"
-                        app:ripple_duration="5000"
-                        app:ripple_stroke_width="15dp" />
-
-                    <ImageView
-                        android:id="@+id/contact_bubble"
-                        android:layout_width="160dp"
-                        android:layout_height="160dp"
-                        android:layout_centerInParent="true"
-                        android:layout_margin="35dp"
-                        tools:src="@drawable/ic_contact_picture_fallback" />
-                </RelativeLayout>
-
-                <LinearLayout
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="50"
-                    android:gravity="center"
-                    android:orientation="vertical">
-
-                    <TextView
-                        android:id="@+id/contact_bubble_txt"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:ellipsize="middle"
-                        android:gravity="center_horizontal"
-                        android:paddingStart="32dp"
-                        android:paddingEnd="32dp"
-                        android:singleLine="true"
-                        android:textAppearance="?android:attr/textAppearanceLarge"
-                        android:textColor="@color/text_color_primary_dark"
-                        tools:text="Contact Name" />
-
-                    <TextView
-                        android:id="@+id/contact_bubble_num_txt"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:ellipsize="middle"
-                        android:gravity="center_horizontal"
-                        android:paddingStart="32dp"
-                        android:paddingEnd="32dp"
-                        android:singleLine="true"
-                        android:textAppearance="?android:attr/textAppearanceMedium"
-                        android:textColor="@color/text_color_secondary_dark"
-                        android:visibility="gone"
-                        tools:text="ring:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
-                        tools:visibility="visible" />
-
-                    <TextView
-                        android:id="@+id/call_status_txt"
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:gravity="center_horizontal"
-                        android:paddingStart="32dp"
-                        android:paddingEnd="32dp"
-                        android:textColor="@color/text_color_primary_dark"
-                        android:textSize="16sp"
-                        tools:text="Connecting" />
-
-                    <LinearLayout
-                        android:layout_width="wrap_content"
-                        android:layout_height="wrap_content"
-                        android:orientation="horizontal"
-                        tools:visibility="visible">
-
-                        <com.google.android.material.floatingactionbutton.FloatingActionButton
-                            android:id="@+id/call_refuse_btn"
-                            android:layout_width="wrap_content"
-                            android:layout_height="wrap_content"
-                            android:layout_margin="16dp"
-                            android:contentDescription="@string/action_call_decline"
-                            android:onClick="@{() -> presenter.refuseClicked()}"
-                            android:tint="@color/white"
-                            android:visibility="gone"
-                            app:backgroundTint="@color/error_red"
-                            app:elevation="6dp"
-                            app:fabSize="normal"
-                            app:pressedTranslationZ="12dp"
-                            app:rippleColor="@android:color/white"
-                            app:srcCompat="@drawable/baseline_call_end_24"
-                            app:useCompatPadding="true" />
-
-                        <com.google.android.material.floatingactionbutton.FloatingActionButton
-                            android:id="@+id/call_accept_btn"
-                            android:layout_width="wrap_content"
-                            android:layout_height="wrap_content"
-                            android:layout_margin="16dp"
-                            android:contentDescription="@string/action_call_accept"
-                            android:onClick="@{() -> presenter.acceptClicked()}"
-                            android:visibility="gone"
-                            app:backgroundTint="#4caf50"
-                            app:elevation="6dp"
-                            app:fabSize="normal"
-                            app:pressedTranslationZ="12dp"
-                            app:rippleColor="@android:color/white"
-                            app:srcCompat="@drawable/baseline_call_24"
-                            app:useCompatPadding="true" />
-
-                    </LinearLayout>
-                </LinearLayout>
-
-            </LinearLayout>
-
-            <LinearLayout
-                android:id="@+id/call_control_group"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_alignParentStart="true"
-                android:layout_alignParentBottom="true"
-                android:layout_marginStart="16dp"
-                android:layout_marginBottom="16dp"
-                android:gravity="center"
-                android:orientation="vertical"
-                android:visibility="gone"
-                tools:visibility="visible">
-
-                <ImageButton
-                    android:id="@+id/call_camera_flip_btn"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_margin="12dp"
-                    android:background="@drawable/call_button_background"
-                    android:contentDescription="@string/ab_action_flipcamera"
-                    android:onClick="@{() -> presenter.cameraFlip()}"
-                    android:padding="16dp"
-                    android:tint="@color/white"
-                    app:srcCompat="@drawable/baseline_camera_front_24" />
-
-                <cx.ring.views.CheckableImageButton
-                    android:id="@+id/call_mic_btn"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_margin="12dp"
-                    android:background="@drawable/call_button_background"
-                    android:contentDescription="@string/action_call_mic_mute"
-                    android:onClick="@{() -> presenter.micClicked()}"
-                    android:padding="16dp"
-                    android:tint="@color/white"
-                    app:srcCompat="@drawable/baseline_mic_off_24"
-                    tools:visibility="visible" />
-
-                <cx.ring.views.CheckableImageButton
-                    android:id="@+id/call_speaker_btn"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_margin="12dp"
-                    android:background="@drawable/call_button_background"
-                    android:contentDescription="@string/ab_action_speakerphone"
-                    android:onClick="@{() -> presenter.speakerClicked()}"
-                    android:padding="16dp"
-                    android:tint="@color/white"
-                    app:srcCompat="@drawable/baseline_volume_up_24" />
-
-            </LinearLayout>
-
-            <EditText
-                android:id="@+id/dialpad_edit_text"
-                android:layout_width="1dp"
-                android:layout_height="1dp"
-                android:ems="10"
-                android:inputType="phone"
-                android:visibility="visible" />
-
-            <com.google.android.material.floatingactionbutton.FloatingActionButton
-                android:id="@+id/call_hangup_btn"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_alignParentBottom="true"
-                android:layout_centerHorizontal="true"
-                android:layout_marginBottom="4dp"
-                android:contentDescription="@string/action_call_hangup"
-                android:onClick="@{() -> presenter.hangUpClicked()}"
-                android:tint="@color/white"
-                android:visibility="gone"
-                app:backgroundTint="@color/error_red"
-                app:elevation="6dp"
-                app:fabSize="normal"
-                app:pressedTranslationZ="12dp"
-                app:rippleColor="@android:color/white"
-                app:srcCompat="@drawable/baseline_call_end_24"
-                app:useCompatPadding="true" />
-
-        </RelativeLayout>
-    </FrameLayout>
-</layout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/activity_ringtone.xml b/ring-android/app/src/main/res/layout/activity_ringtone.xml
index 6723e4b..0e5dbc9 100644
--- a/ring-android/app/src/main/res/layout/activity_ringtone.xml
+++ b/ring-android/app/src/main/res/layout/activity_ringtone.xml
@@ -6,16 +6,15 @@
     android:layout_height="match_parent"
     android:orientation="vertical">
 
-    <androidx.appcompat.widget.Toolbar
+    <!--<com.google.android.material.appbar.MaterialToolbar
         android:id="@+id/ringtoneToolbar"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:background="?attr/colorPrimary"
         android:minHeight="?attr/actionBarSize"
         android:elevation="@dimen/toolbar_elevation"
-        android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar"
+        style="@style/Widget.MaterialComponents.Toolbar.Surface"
         app:navigationIcon="?attr/homeAsUpIndicator"
-        app:title="@string/account_ringtone_title" />
+        app:title="@string/account_ringtone_title" />-->
 
     <androidx.core.widget.NestedScrollView
         android:layout_width="match_parent"
diff --git a/ring-android/app/src/main/res/layout/frag_call.xml b/ring-android/app/src/main/res/layout/frag_call.xml
index 3f65cd1..1df29bd 100644
--- a/ring-android/app/src/main/res/layout/frag_call.xml
+++ b/ring-android/app/src/main/res/layout/frag_call.xml
@@ -53,10 +53,14 @@
                 android:layout_height="wrap_content"
                 android:layout_alignParentEnd="true"
                 android:layout_alignParentBottom="true"
-                android:layout_margin="12dp"
+                android:layout_marginStart="12dp"
+                android:layout_marginTop="12dp"
+                android:layout_marginEnd="12dp"
+                android:layout_marginBottom="12dp"
                 android:visibility="gone"
                 app:cardCornerRadius="16dp"
-                app:cardPreventCornerOverlap="false">
+                app:cardPreventCornerOverlap="false"
+                tools:visibility="visible">
 
                 <cx.ring.views.AutoFitTextureView
                     android:id="@+id/preview_surface"
@@ -75,23 +79,26 @@
             android:clipToPadding="false"
             android:fitsSystemWindows="true">
 
-            <LinearLayout
+            <com.google.android.flexbox.FlexboxLayout
                 android:id="@+id/contact_bubble_layout"
-                android:layout_width="match_parent"
+                android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_centerInParent="true"
-                android:gravity="center"
                 android:orientation="vertical"
-                android:visibility="invisible">
+                android:visibility="visible"
+                app:flexDirection="column"
+                app:flexWrap="wrap"
+                tools:visibility="gone">
 
                 <RelativeLayout
-                    android:layout_width="match_parent"
+                    android:layout_width="230dp"
                     android:layout_height="230dp">
 
                     <com.rodolfonavalon.shaperipplelibrary.ShapeRipple
                         android:id="@+id/shape_ripple"
-                        android:layout_width="match_parent"
+                        android:layout_width="wrap_content"
                         android:layout_height="match_parent"
+                        android:layout_centerInParent="true"
                         app:enable_color_transition="true"
                         app:ripple_color="@color/white"
                         app:ripple_count="3"
@@ -106,90 +113,95 @@
                         tools:src="@drawable/ic_contact_picture_fallback" />
                 </RelativeLayout>
 
-                <TextView
-                    android:id="@+id/contact_bubble_txt"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:ellipsize="middle"
-                    android:gravity="center_horizontal"
-                    android:paddingStart="32dp"
-                    android:paddingEnd="32dp"
-                    android:singleLine="true"
-                    android:textAppearance="?android:attr/textAppearanceLarge"
-                    android:textColor="@color/text_color_primary_dark"
-                    tools:text="Contact Name" />
-
-                <TextView
-                    android:id="@+id/contact_bubble_num_txt"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:ellipsize="middle"
-                    android:gravity="center_horizontal"
-                    android:paddingStart="32dp"
-                    android:paddingEnd="32dp"
-                    android:singleLine="true"
-                    android:textAppearance="?android:attr/textAppearanceMedium"
-                    android:textColor="@color/text_color_secondary_dark"
-                    android:visibility="gone"
-                    tools:text="ring:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
-                    tools:visibility="visible" />
-
-                <TextView
-                    android:id="@+id/call_status_txt"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:gravity="center_horizontal"
-                    android:paddingStart="32dp"
-                    android:paddingEnd="32dp"
-                    android:textColor="@color/text_color_primary_dark"
-                    android:textSize="16sp"
-                    tools:text="Connecting" />
-            </LinearLayout>
-
-            <LinearLayout
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_below="@+id/contact_bubble_layout"
-                android:layout_centerHorizontal="true"
-                android:orientation="horizontal"
-                tools:visibility="gone">
-
-                <com.google.android.material.floatingactionbutton.FloatingActionButton
-                    android:id="@+id/call_refuse_btn"
+                <LinearLayout
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_margin="16dp"
-                    android:contentDescription="@string/action_call_decline"
-                    android:onClick="@{() -> presenter.refuseClicked()}"
-                    android:tint="@color/white"
-                    android:visibility="gone"
-                    app:backgroundTint="@color/error_red"
-                    app:elevation="6dp"
-                    app:fabSize="normal"
-                    app:pressedTranslationZ="12dp"
-                    app:rippleColor="@android:color/white"
-                    app:srcCompat="@drawable/baseline_call_end_24"
-                    app:useCompatPadding="true" />
+                    android:gravity="center_horizontal"
+                    android:orientation="vertical">
 
-                <com.google.android.material.floatingactionbutton.FloatingActionButton
-                    android:id="@+id/call_accept_btn"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_margin="16dp"
-                    android:contentDescription="@string/action_call_accept"
-                    android:onClick="@{() -> presenter.acceptClicked()}"
-                    android:visibility="gone"
-                    app:backgroundTint="@color/green_500"
-                    app:elevation="6dp"
-                    app:fabSize="normal"
-                    app:pressedTranslationZ="12dp"
-                    app:rippleColor="@android:color/white"
-                    app:srcCompat="@drawable/baseline_call_24"
-                    app:useCompatPadding="true" />
+                    <TextView
+                        android:id="@+id/contact_bubble_txt"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:ellipsize="middle"
+                        android:gravity="center_horizontal"
+                        android:paddingStart="32dp"
+                        android:paddingEnd="32dp"
+                        android:singleLine="true"
+                        android:textAppearance="?android:attr/textAppearanceLarge"
+                        android:textColor="@color/text_color_primary_dark"
+                        tools:text="Contact Name" />
 
-            </LinearLayout>
+                    <TextView
+                        android:id="@+id/contact_bubble_num_txt"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:ellipsize="middle"
+                        android:gravity="center_horizontal"
+                        android:paddingStart="32dp"
+                        android:paddingEnd="32dp"
+                        android:singleLine="true"
+                        android:textAppearance="?android:attr/textAppearanceMedium"
+                        android:textColor="@color/text_color_secondary_dark"
+                        android:visibility="gone"
+                        tools:text="ring:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+                        tools:visibility="visible" />
 
-            <LinearLayout
+                    <TextView
+                        android:id="@+id/call_status_txt"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:gravity="center_horizontal"
+                        android:paddingStart="32dp"
+                        android:paddingEnd="32dp"
+                        android:textColor="@color/text_color_primary_dark"
+                        android:textSize="16sp"
+                        tools:text="Connecting" />
+
+                    <LinearLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:orientation="horizontal"
+                        tools:visibility="visible">
+
+                        <com.google.android.material.floatingactionbutton.FloatingActionButton
+                            android:id="@+id/call_refuse_btn"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_margin="16dp"
+                            android:contentDescription="@string/action_call_decline"
+                            android:onClick="@{() -> presenter.refuseClicked()}"
+                            android:tint="@color/white"
+                            android:visibility="visible"
+                            app:backgroundTint="@color/error_red"
+                            app:elevation="6dp"
+                            app:fabSize="normal"
+                            app:pressedTranslationZ="12dp"
+                            app:rippleColor="@android:color/white"
+                            app:srcCompat="@drawable/baseline_call_end_24"
+                            app:useCompatPadding="true" />
+
+                        <com.google.android.material.floatingactionbutton.FloatingActionButton
+                            android:id="@+id/call_accept_btn"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_margin="16dp"
+                            android:contentDescription="@string/action_call_accept"
+                            android:onClick="@{() -> presenter.acceptClicked()}"
+                            android:visibility="visible"
+                            app:backgroundTint="@color/green_500"
+                            app:elevation="6dp"
+                            app:fabSize="normal"
+                            app:pressedTranslationZ="12dp"
+                            app:rippleColor="@android:color/white"
+                            app:srcCompat="@drawable/baseline_call_24"
+                            app:useCompatPadding="true" />
+                    </LinearLayout>
+
+                </LinearLayout>
+            </com.google.android.flexbox.FlexboxLayout>
+
+            <com.google.android.flexbox.FlexboxLayout
                 android:id="@+id/call_control_group"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
@@ -200,6 +212,8 @@
                 android:gravity="center"
                 android:orientation="vertical"
                 android:visibility="gone"
+                app:flexDirection="column_reverse"
+                app:flexWrap="wrap"
                 tools:visibility="visible">
 
                 <ImageButton
@@ -214,6 +228,17 @@
                     android:tint="@color/white"
                     app:srcCompat="@drawable/baseline_camera_front_24" />
 
+                <ImageButton
+                    android:id="@+id/call_conference_add"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_margin="12dp"
+                    android:background="@drawable/call_button_background"
+                    android:onClick="@{() -> presenter.addParticipant()}"
+                    android:padding="16dp"
+                    android:tint="@color/white"
+                    app:srcCompat="@drawable/baseline_person_add_24" />
+
                 <cx.ring.views.CheckableImageButton
                     android:id="@+id/call_mic_btn"
                     android:layout_width="wrap_content"
@@ -239,7 +264,17 @@
                     android:tint="@color/white"
                     app:srcCompat="@drawable/baseline_volume_up_24" />
 
-            </LinearLayout>
+            </com.google.android.flexbox.FlexboxLayout>
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/conf_control_group"
+                android:layout_alignParentEnd="true"
+                android:layout_alignParentTop="true"
+                app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+                tools:listitem="@layout/item_conference_participant"
+                tools:itemCount="4" />
 
             <EditText
                 android:id="@+id/dialpad_edit_text"
diff --git a/ring-android/app/src/main/res/layout/frag_conversation.xml b/ring-android/app/src/main/res/layout/frag_conversation.xml
index 522f391..67de715 100644
--- a/ring-android/app/src/main/res/layout/frag_conversation.xml
+++ b/ring-android/app/src/main/res/layout/frag_conversation.xml
@@ -201,18 +201,18 @@
                     android:layout_height="match_parent"
                     android:gravity="center"
                     android:orientation="horizontal"
-                    android:paddingStart="4dp">
+                    android:paddingStart="8dp">
 
-	                <ImageButton
-	                    android:id="@+id/btn_menu"
-	                    android:layout_width="wrap_content"
-	                    android:layout_height="match_parent"
-	                    android:background="?selectableItemBackgroundBorderless"
-	                    android:contentDescription="@string/share_label"
-	                    android:onClick="@{v -> presenter.expandMenu(v)}"
-	                    android:padding="8dp"
-	                    android:tint="@android:color/darker_gray"
-	                    app:srcCompat="@drawable/baseline_expand_less_24" />
+                    <ImageButton
+                        android:id="@+id/btn_menu"
+                        android:layout_width="28dp"
+                        android:layout_height="match_parent"
+                        android:background="?selectableItemBackgroundBorderless"
+                        android:contentDescription="@string/share_label"
+                        android:onClick="@{v -> presenter.expandMenu(v)}"
+                        android:padding="8dp"
+                        android:tint="@android:color/darker_gray"
+                        app:srcCompat="@drawable/baseline_expand_less_24" />
 
                     <ImageButton
                         android:id="@+id/btn_take_picture"
diff --git a/ring-android/app/src/main/res/layout/frag_selectconv.xml b/ring-android/app/src/main/res/layout/frag_selectconv.xml
new file mode 100644
index 0000000..ddfc620
--- /dev/null
+++ b/ring-android/app/src/main/res/layout/frag_selectconv.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <!--<com.google.android.material.appbar.MaterialToolbar
+        android:id="@+id/toolbar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        style="@style/Widget.MaterialComponents.Toolbar.Surface"/>-->
+
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/conversationList"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:clipToPadding="false"
+        android:paddingTop="8dp"
+        app:layoutManager="LinearLayoutManager"
+        tools:context=".client.ConversationSelectionActivity"
+        tools:listitem="@layout/item_smartlist" />
+</LinearLayout>
diff --git a/ring-android/app/src/main/res/layout/item_conference_participant.xml b/ring-android/app/src/main/res/layout/item_conference_participant.xml
new file mode 100644
index 0000000..8b67837
--- /dev/null
+++ b/ring-android/app/src/main/res/layout/item_conference_participant.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+Copyright (C) 2004-2016 Savoir-faire Linux Inc.
+
+Author: Alexandre Lision <alexandre.lision@savoirfairelinux.com>
+        Adrien Beraud <adrien.beraud@savoirfairelinux.com>
+        Romain Bertozzi <romain.bertozzi@savoirfairelinux.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-->
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <data />
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:descendantFocusability="blocksDescendants"
+        android:gravity="center_vertical|end"
+        android:minHeight="72dp"
+        android:paddingLeft="16dp"
+        android:paddingTop="8dp"
+        android:paddingRight="16dp"
+        android:paddingBottom="8dp">
+
+        <TextView
+            android:id="@+id/display_name"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_margin="@dimen/padding_large"
+            android:background="@drawable/background_conference_participant"
+            android:elevation="4dp"
+            android:ellipsize="end"
+            android:maxLines="2"
+            android:paddingStart="16dp"
+            android:paddingTop="8dp"
+            android:paddingEnd="16dp"
+            android:paddingBottom="8dp"
+            android:textColor="@color/grey_800"
+            android:textIsSelectable="false"
+            android:textSize="16sp"
+            android:textAlignment="center"
+            tools:text="Thomas\nConnecting..." />
+
+        <com.google.android.material.floatingactionbutton.FloatingActionButton
+            android:id="@+id/photo"
+            android:layout_width="60dp"
+            android:layout_height="60dp"
+            android:contentDescription="@string/contact_picture_description"
+            android:tintMode="multiply"
+            app:maxImageSize="56dp"
+            tools:src="@drawable/ic_contact_picture_fallback"/>
+
+    </LinearLayout>
+</layout>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/menu/ac_call.xml b/ring-android/app/src/main/res/menu/ac_call.xml
index 828aef5..0181a83 100644
--- a/ring-android/app/src/main/res/menu/ac_call.xml
+++ b/ring-android/app/src/main/res/menu/ac_call.xml
@@ -3,12 +3,6 @@
     xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <item
-        android:id="@+id/menuitem_chat"
-        app:showAsAction="ifRoom"
-        android:icon="@drawable/baseline_chat_24"
-        android:title="@string/ab_action_chat"/>
-
-    <item
         android:id="@+id/menuitem_dialpad"
         app:showAsAction="ifRoom"
         android:icon="@drawable/baseline_dialpad_24"
diff --git a/ring-android/app/src/main/res/menu/conference_participant_actions.xml b/ring-android/app/src/main/res/menu/conference_participant_actions.xml
new file mode 100644
index 0000000..061f850
--- /dev/null
+++ b/ring-android/app/src/main/res/menu/conference_participant_actions.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
+    <item
+        android:id="@+id/conv_contact_details"
+        android:icon="@drawable/baseline_person_24"
+        android:title="@string/conversation_details"
+        app:showAsAction="always"
+        tools:ignore="AlwaysShowAction" />
+    <item
+        android:id="@+id/conv_contact_hangup"
+        android:icon="@drawable/baseline_call_end_24"
+        android:title="@string/action_call_hangup"
+        app:showAsAction="always"
+        android:iconTint="@color/red_500" />
+</menu>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/values/strings_call.xml b/ring-android/app/src/main/res/values/strings_call.xml
index ddfa479..e865eb3 100644
--- a/ring-android/app/src/main/res/values/strings_call.xml
+++ b/ring-android/app/src/main/res/values/strings_call.xml
@@ -36,6 +36,6 @@
     <string name="call_human_state_hold">Hold</string>
     <string name="call_human_state_unhold">Unhold</string>
     <string name="call_human_state_over">Over</string>
-    <string name="call_human_state_none">None</string>
+    <string name="call_human_state_none" translatable="false" />
     <!-- Conferences -->
 </resources>
\ No newline at end of file
diff --git a/ring-android/app/src/noPush/AndroidManifest.xml b/ring-android/app/src/noPush/AndroidManifest.xml
index cac453e..5bac656 100644
--- a/ring-android/app/src/noPush/AndroidManifest.xml
+++ b/ring-android/app/src/noPush/AndroidManifest.xml
@@ -22,7 +22,7 @@
     tools:ignore="ImpliedTouchscreenHardware,MissingLeanbackLauncher,MissingLeanbackSupport">
 
     <application
-        android:name=".application.RingApplicationNoPush"
+        android:name=".application.JamiApplicationNoPush"
         tools:ignore="GoogleAppIndexingWarning,UnusedAttribute" />
 
 </manifest>
diff --git a/ring-android/app/src/noPush/java/cx/ring/application/RingApplicationNoPush.java b/ring-android/app/src/noPush/java/cx/ring/application/JamiApplicationNoPush.java
similarity index 93%
rename from ring-android/app/src/noPush/java/cx/ring/application/RingApplicationNoPush.java
rename to ring-android/app/src/noPush/java/cx/ring/application/JamiApplicationNoPush.java
index 2cc7113..24b8f39 100644
--- a/ring-android/app/src/noPush/java/cx/ring/application/RingApplicationNoPush.java
+++ b/ring-android/app/src/noPush/java/cx/ring/application/JamiApplicationNoPush.java
@@ -18,7 +18,7 @@
  */
 package cx.ring.application;
 
-public class RingApplicationNoPush extends RingApplication {
+public class JamiApplicationNoPush extends JamiApplication {
 
     @Override
     public String getPushToken() {
diff --git a/ring-android/app/src/withFirebase/AndroidManifest.xml b/ring-android/app/src/withFirebase/AndroidManifest.xml
index 1107813..e3ac4a3 100644
--- a/ring-android/app/src/withFirebase/AndroidManifest.xml
+++ b/ring-android/app/src/withFirebase/AndroidManifest.xml
@@ -21,11 +21,11 @@
     package="cx.ring">
 
     <application
-        android:name=".application.RingApplicationFirebase"
+        android:name=".application.JamiApplicationFirebase"
         tools:ignore="UnusedAttribute">
 
         <service
-            android:name=".services.RingFirebaseMessagingService"
+            android:name=".services.JamiFirebaseMessagingService"
             android:stopWithTask="false">
             <intent-filter>
                 <action android:name="com.google.firebase.MESSAGING_EVENT" />
diff --git a/ring-android/app/src/withFirebase/java/cx/ring/application/RingApplicationFirebase.java b/ring-android/app/src/withFirebase/java/cx/ring/application/JamiApplicationFirebase.java
similarity index 94%
rename from ring-android/app/src/withFirebase/java/cx/ring/application/RingApplicationFirebase.java
rename to ring-android/app/src/withFirebase/java/cx/ring/application/JamiApplicationFirebase.java
index 388f4f3..3097904 100644
--- a/ring-android/app/src/withFirebase/java/cx/ring/application/RingApplicationFirebase.java
+++ b/ring-android/app/src/withFirebase/java/cx/ring/application/JamiApplicationFirebase.java
@@ -26,8 +26,8 @@
 
 import cx.ring.service.DRingService;
 
-public class RingApplicationFirebase extends RingApplication {
-    static private String TAG = RingApplicationFirebase.class.getSimpleName();
+public class JamiApplicationFirebase extends JamiApplication {
+    static private String TAG = JamiApplicationFirebase.class.getSimpleName();
 
     static private String pushToken = "";
 
diff --git a/ring-android/app/src/withFirebase/java/cx/ring/services/RingFirebaseMessagingService.java b/ring-android/app/src/withFirebase/java/cx/ring/services/JamiFirebaseMessagingService.java
similarity index 85%
rename from ring-android/app/src/withFirebase/java/cx/ring/services/RingFirebaseMessagingService.java
rename to ring-android/app/src/withFirebase/java/cx/ring/services/JamiFirebaseMessagingService.java
index 9701b5e..cc446bc 100644
--- a/ring-android/app/src/withFirebase/java/cx/ring/services/RingFirebaseMessagingService.java
+++ b/ring-android/app/src/withFirebase/java/cx/ring/services/JamiFirebaseMessagingService.java
@@ -20,6 +20,8 @@
 
 import android.content.Intent;
 import android.os.Bundle;
+
+import androidx.annotation.NonNull;
 import androidx.legacy.content.WakefulBroadcastReceiver;
 import android.util.Log;
 
@@ -28,14 +30,14 @@
 
 import java.util.Map;
 
-import cx.ring.application.RingApplicationFirebase;
+import cx.ring.application.JamiApplicationFirebase;
 import cx.ring.service.DRingService;
 
-public class RingFirebaseMessagingService extends FirebaseMessagingService {
-    private static final String TAG = RingFirebaseMessagingService.class.getSimpleName();
+public class JamiFirebaseMessagingService extends FirebaseMessagingService {
+    private static final String TAG = JamiFirebaseMessagingService.class.getSimpleName();
 
     @Override
-    public void onMessageReceived(RemoteMessage remoteMessage) {
+    public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
         try {
             // Log.d(TAG, "onMessageReceived: " + remoteMessage.getFrom());
             Map<String, String> data = remoteMessage.getData();
@@ -54,10 +56,10 @@
     }
 
     @Override
-    public void onNewToken(String refreshedToken) {
+    public void onNewToken(@NonNull String refreshedToken) {
         try {
             Log.d(TAG, "onTokenRefresh: refreshed token: " + refreshedToken);
-            RingApplicationFirebase.setPushToken(refreshedToken);
+            JamiApplicationFirebase.setPushToken(refreshedToken);
             startService(new Intent(DRingService.ACTION_PUSH_TOKEN_CHANGED)
                     .setClass(this, DRingService.class)
                     .putExtra(DRingService.PUSH_TOKEN_FIELD_TOKEN, refreshedToken));
diff --git a/ring-android/build.gradle b/ring-android/build.gradle
index f1b4895..b68ffa5 100644
--- a/ring-android/build.gradle
+++ b/ring-android/build.gradle
@@ -4,7 +4,7 @@
         jcenter()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:3.5.0'
+        classpath 'com.android.tools.build:gradle:3.5.1'
         classpath 'com.google.gms:google-services:4.3.1'
     }
 }
diff --git a/ring-android/libringclient/src/main/java/cx/ring/call/CallPresenter.java b/ring-android/libringclient/src/main/java/cx/ring/call/CallPresenter.java
index b54564a..b9ba40a 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/call/CallPresenter.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/call/CallPresenter.java
@@ -20,24 +20,34 @@
  */
 package cx.ring.call;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 
+import cx.ring.facades.ConversationFacade;
+import cx.ring.model.Conference;
+import cx.ring.model.Conversation;
 import cx.ring.model.SipCall;
+import cx.ring.model.Uri;
 import cx.ring.mvp.RootPresenter;
 import cx.ring.services.AccountService;
 import cx.ring.services.CallService;
 import cx.ring.services.ContactService;
 import cx.ring.services.DeviceRuntimeService;
 import cx.ring.services.HardwareService;
-import cx.ring.services.NotificationService;
 import cx.ring.utils.Log;
 import cx.ring.utils.StringUtils;
+import io.reactivex.Maybe;
 import io.reactivex.Observable;
+import io.reactivex.Observer;
 import io.reactivex.Scheduler;
 import io.reactivex.disposables.Disposable;
+import io.reactivex.subjects.BehaviorSubject;
+import io.reactivex.subjects.Subject;
 
 public class CallPresenter extends RootPresenter<CallView> {
 
@@ -48,8 +58,12 @@
     private HardwareService mHardwareService;
     private CallService mCallService;
     private DeviceRuntimeService mDeviceRuntimeService;
+    private ConversationFacade mConversationFacade;
 
-    private SipCall mSipCall;
+    private Conference mSipCall;
+    private final List<SipCall> mPendingCalls = new ArrayList<>();
+    private final Subject<List<SipCall>> mPendingSubject = BehaviorSubject.createDefault(mPendingCalls);
+
     private boolean mOnGoingCall = false;
     private boolean mAudioOnly = true;
     private boolean permissionChanged = false;
@@ -61,6 +75,7 @@
     private int videoHeight = -1;
     private int previewWidth = -1;
     private int previewHeight = -1;
+    private String currentSurfaceId = null;
 
     private Disposable timeUpdateTask = null;
 
@@ -72,12 +87,15 @@
     public CallPresenter(AccountService accountService,
                          ContactService contactService,
                          HardwareService hardwareService,
-                         CallService callService, DeviceRuntimeService deviceRuntimeService) {
+                         CallService callService,
+                         DeviceRuntimeService deviceRuntimeService,
+                         ConversationFacade conversationFacade) {
         mAccountService = accountService;
         mContactService = contactService;
         mHardwareService = hardwareService;
         mCallService = callService;
         mDeviceRuntimeService = deviceRuntimeService;
+        mConversationFacade = conversationFacade;
     }
 
     public void cameraPermissionChanged(boolean isGranted) {
@@ -105,13 +123,13 @@
     @Override
     public void bindView(CallView view) {
         super.bindView(view);
-        mCompositeDisposable.add(mAccountService.getRegisteredNames()
+        /*mCompositeDisposable.add(mAccountService.getRegisteredNames()
                 .observeOn(mUiScheduler)
                 .subscribe(r -> {
                     if (mSipCall != null && mSipCall.getContact() != null) {
                         getView().updateContactBubble(mSipCall.getContact());
                     }
-                }));
+                }));*/
         mCompositeDisposable.add(mHardwareService.getVideoEvents()
                 .observeOn(mUiScheduler)
                 .subscribe(this::onVideoEvent));
@@ -140,18 +158,19 @@
         //getView().blockScreenRotation();
 
         mCompositeDisposable.add(mCallService
-                .placeCallObservable(accountId, StringUtils.toNumber(contactRingId), audioOnly)
+                .placeCall(accountId, StringUtils.toNumber(contactRingId), audioOnly)
+                //.map(mCallService::getConference)
+                .flatMapObservable(call -> mCallService.getConfUpdates(call))
                 .observeOn(mUiScheduler)
-                .subscribe(call -> {
-                    contactUpdate(call);
-                    confUpdate(call);
+                .subscribe(conference -> {
+                    contactUpdate(conference);
+                    confUpdate(conference);
                 }, e -> {
                     hangupCall();
                     Log.e(TAG, "Error with initOutgoing: " + e.getMessage());
                 }));
     }
 
-
     /**
      * Returns to or starts an incoming call
      *
@@ -164,49 +183,58 @@
         // if the call is incoming through a full intent, this allows the incoming call to display
         incomingIsFullIntent = actionViewOnly;
 
-        Observable<SipCall> callObservable = mCallService.getCallUpdates(confId).observeOn(mUiScheduler).share();
+        Observable<Conference> callObservable = mCallService.getConfUpdates(confId)
+                .observeOn(mUiScheduler)
+                .share();
 
         // Handles the case where the call has been accepted, emits a single so as to only check for permissions and start the call once
-        mCompositeDisposable.add(callObservable.firstOrError().subscribe(call -> {
-            if (!actionViewOnly) {
-                contactUpdate(call);
-                confUpdate(call);
-                callInitialized = true;
-                getView().prepareCall(true);
-            }
-        }, e -> {
-            hangupCall();
-            Log.e(TAG, "Error with initIncoming, preparing call flow :" , e);
-        }));
+        mCompositeDisposable.add(callObservable
+                .firstOrError()
+                .subscribe(call -> {
+                    if (!actionViewOnly) {
+                        contactUpdate(call);
+                        confUpdate(call);
+                        callInitialized = true;
+                        getView().prepareCall(true);
+                    }
+                }, e -> {
+                    hangupCall();
+                    Log.e(TAG, "Error with initIncoming, preparing call flow :" , e);
+                }));
 
         // Handles retrieving call updates. Items emitted are only used if call is already in process or if user is returning to a call.
-        mCompositeDisposable.add(callObservable.subscribe(call -> {
-            if (callInitialized || actionViewOnly) {
-                contactUpdate(call);
-                confUpdate(call);
-            }
-        }, e -> {
-            hangupCall();
-            Log.e(TAG, "Error with initIncoming, action view flow: ", e);
-        }));
+        mCompositeDisposable.add(callObservable
+                .subscribe(call -> {
+                    if (callInitialized || actionViewOnly) {
+                        contactUpdate(call);
+                        confUpdate(call);
+                    }
+                }, e -> {
+                    hangupCall();
+                    Log.e(TAG, "Error with initIncoming, action view flow: ", e);
+                }));
     }
 
     public void prepareOptionMenu() {
         boolean isSpeakerOn = mHardwareService.isSpeakerPhoneOn();
-        boolean hasContact = mSipCall != null && null != mSipCall.getContact() && mSipCall.getContact().isUnknown();
+        //boolean hasContact = mSipCall != null && null != mSipCall.getContact() && mSipCall.getContact().isUnknown();
         boolean canDial = mOnGoingCall && mSipCall != null && !mSipCall.isIncoming();
         boolean hasMultipleCamera = mHardwareService.getCameraCount() > 1 && mOnGoingCall && !mAudioOnly;
-        getView().initMenu(isSpeakerOn, hasContact, hasMultipleCamera, canDial, mOnGoingCall);
+        getView().initMenu(isSpeakerOn, hasMultipleCamera, canDial, mOnGoingCall);
     }
 
     public void chatClick() {
-        if (mSipCall == null
-                || mSipCall.getContact() == null
-                || mSipCall.getContact().getIds() == null
-                || mSipCall.getContact().getIds().isEmpty()) {
+        if (mSipCall == null || mSipCall.getParticipants().isEmpty()) {
             return;
         }
-        getView().goToConversation(mSipCall.getAccount(), mSipCall.getContact().getIds().get(0));
+        SipCall firstCall = mSipCall.getParticipants().get(0);
+        if (firstCall == null
+                || firstCall.getContact() == null
+                || firstCall.getContact().getIds() == null
+                || firstCall.getContact().getIds().isEmpty()) {
+            return;
+        }
+        getView().goToConversation(firstCall.getAccount(), firstCall.getContact().getIds().get(0));
     }
 
     public void speakerClick(boolean checked) {
@@ -226,10 +254,17 @@
         if(mSipCall == null)
             return;
 
-        mHardwareService.switchInput(mSipCall.getDaemonIdString(), false);
+        mHardwareService.switchInput(mSipCall.getId(), false);
         getView().switchCameraIcon(mHardwareService.isPreviewFromFrontCamera());
     }
 
+    /*public void addParticipantClick() {
+        if(mSipCall == null)
+            return;
+
+        getView().launchAddParti
+    }*/
+
     public void configurationChanged(int rotation) {
         mHardwareService.setDeviceOrientation(rotation);
     }
@@ -242,20 +277,26 @@
         if (mSipCall == null) {
             return;
         }
-        mCallService.accept(mSipCall.getDaemonIdString());
+        mCallService.accept(mSipCall.getId());
     }
 
     public void hangupCall() {
         if (mSipCall != null) {
-            mCallService.hangUp(mSipCall.getDaemonIdString());
+            if (mSipCall.isConference())
+                mCallService.hangUpConference(mSipCall.getId());
+            else
+                mCallService.hangUp(mSipCall.getId());
+        }
+        for (SipCall call : mPendingCalls) {
+            mCallService.hangUp(call.getDaemonIdString());
         }
         finish();
     }
 
     public void refuseCall() {
-        final SipCall call = mSipCall;
+        final Conference call = mSipCall;
         if (call != null) {
-            mCallService.refuse(call.getDaemonIdString());
+            mCallService.refuse(call.getId());
         }
         finish();
     }
@@ -264,20 +305,32 @@
         if (mSipCall == null) {
             return;
         }
-        mHardwareService.addVideoSurface(mSipCall.getDaemonIdString(), holder);
+        String newId = mSipCall.getId();
+        if (!newId.equals(currentSurfaceId)) {
+            mHardwareService.removeVideoSurface(currentSurfaceId);
+            currentSurfaceId = newId;
+        }
+        mHardwareService.addVideoSurface(mSipCall.getId(), holder);
         getView().displayContactBubble(false);
     }
 
+    public void videoSurfaceUpdateId(String newId) {
+        if (!Objects.equals(newId, currentSurfaceId)) {
+            mHardwareService.updateVideoSurfaceId(currentSurfaceId, newId);
+            currentSurfaceId = newId;
+        }
+    }
+
     public void previewVideoSurfaceCreated(Object holder) {
         mHardwareService.addPreviewVideoSurface(holder, mSipCall);
         //mHardwareService.startCapture(null);
     }
 
     public void videoSurfaceDestroyed() {
-        if (mSipCall == null) {
-            return;
+        if (currentSurfaceId != null) {
+            mHardwareService.removeVideoSurface(currentSurfaceId);
+            currentSurfaceId = null;
         }
-        mHardwareService.removeVideoSurface(mSipCall.getDaemonIdString());
     }
 
     public void previewVideoSurfaceDestroyed() {
@@ -286,7 +339,7 @@
     }
 
     public void displayChanged() {
-        mHardwareService.switchInput(mSipCall.getDaemonIdString(), false);
+        mHardwareService.switchInput(mSipCall.getId(), false);
     }
 
     public void layoutChanged() {
@@ -311,30 +364,77 @@
             view.finish();
     }
 
-    private void contactUpdate(final SipCall call) {
-        if (mSipCall != call) {
-            mSipCall = call;
-            mCompositeDisposable.add(mContactService.observeContact(call.getAccount(), call.getContact())
+    private Disposable contactDisposable = null;
+
+    private void contactUpdate(final Conference conference) {
+        if (mSipCall != conference) {
+            mSipCall = conference;
+            if (contactDisposable != null && !contactDisposable.isDisposed()) {
+                contactDisposable.dispose();
+            }
+            if (conference.getParticipants().isEmpty())
+                return;
+
+            // Updates of participant (and  pending participant) list
+            Observable<List<SipCall>> callsObservable = mPendingSubject
+                    .map(pendingList -> {
+                        Log.w(TAG, "mPendingSubject onNext " + pendingList.size() + " " + conference.getParticipants().size());
+                        if (pendingList.isEmpty())
+                            return conference.getParticipants();
+                        List<SipCall> newList = new ArrayList<>(conference.getParticipants().size() + pendingList.size());
+                        newList.addAll(conference.getParticipants());
+                        newList.addAll(pendingList);
+                        return newList;
+                    });
+
+            // Updates of individual contacts
+            Observable<List<Observable<SipCall>>> contactsObservable = callsObservable
+                    .flatMapSingle(calls -> Observable
+                            .fromIterable(calls)
+                            .map(call -> mContactService.observeContact(call.getAccount(), call.getContact())
+                                    .map(contact -> call))
+                            .toList(calls.size()));
+
+            // Combined updates of contacts as participant list updates
+            Observable<List<SipCall>> contactUpdates = contactsObservable
+                    .switchMap(list -> Observable
+                            .combineLatest(list, objects -> {
+                                Log.w(TAG, "flatMapObservable " + objects.length);
+                                ArrayList<SipCall> calls = new ArrayList<>(objects.length);
+                                for (Object call : objects)
+                                    calls.add((SipCall)call);
+                                return (List<SipCall>)calls;
+                            }))
+                    .filter(list -> !list.isEmpty());
+
+            contactDisposable = contactUpdates
                     .observeOn(mUiScheduler)
-                    .subscribe(c -> getView().updateContactBubble(c), e -> Log.e(TAG, e.getMessage())));
+                    .subscribe(cs -> getView().updateContactBubble(cs), e -> Log.e(TAG, "Error updating contact data", e));
+            mCompositeDisposable.add(contactDisposable);
         }
     }
 
-    private void confUpdate(SipCall call) {
-        mAudioOnly = call.isAudioOnly();
+    private void confUpdate(Conference call) {
+        Log.w(TAG, "confUpdate " + call.getId());
+
+        mSipCall = call;
+        mAudioOnly = !call.hasVideo();
         CallView view = getView();
         if (view == null)
             return;
         view.updateMenu();
         if (call.isOnGoing()) {
+            Log.w(TAG, "confUpdate call.isOnGoing");
+
             mOnGoingCall = true;
             view.initNormalStateDisplay(mAudioOnly, isMicrophoneMuted());
             view.updateMenu();
             if (!mAudioOnly) {
                 mHardwareService.setPreviewSettings();
+                videoSurfaceUpdateId(call.getId());
                 view.displayVideoSurface(true, mDeviceRuntimeService.hasVideoPermission());
                 if (permissionChanged) {
-                    mHardwareService.switchInput(mSipCall.getDaemonIdString(), permissionChanged);
+                    mHardwareService.switchInput(mSipCall.getId(), permissionChanged);
                     permissionChanged = false;
                 }
             }
@@ -342,17 +442,20 @@
                 timeUpdateTask.dispose();
             timeUpdateTask = mUiScheduler.schedulePeriodicallyDirect(this::updateTime, 0, 1, TimeUnit.SECONDS);
         } else if (call.isRinging()) {
+            Log.w(TAG, "confUpdate call.isRinging");
+            SipCall scall = call.getCall();
+
             view.handleCallWakelock(mAudioOnly);
-            if (call.isIncoming()) {
-                if (mAccountService.getAccount(call.getAccount()).isAutoanswerEnabled()) {
-                    mCallService.accept(call.getDaemonIdString());
+            if (scall.isIncoming()) {
+                if (mAccountService.getAccount(scall.getAccount()).isAutoanswerEnabled()) {
+                    mCallService.accept(scall.getDaemonIdString());
                     // only display the incoming call screen if the notification is a full screen intent
                 } else if (incomingIsFullIntent) {
                     view.initIncomingCallDisplay();
                 }
             } else {
                 mOnGoingCall = false;
-                view.updateCallStatus(call.getCallStatus());
+                view.updateCallStatus(scall.getCallStatus());
                 view.initOutGoingCallDisplay();
             }
         } else {
@@ -363,10 +466,13 @@
     private void updateTime() {
         CallView view = getView();
         if (view != null && mSipCall != null) {
-            long duration = System.currentTimeMillis() - mSipCall.getTimestamp();
-            duration = duration / 1000;
             if (mSipCall.isOnGoing()) {
-                view.updateTime(duration);
+                long start = mSipCall.getTimestampStart();
+                if (start != Long.MAX_VALUE) {
+                    view.updateTime((System.currentTimeMillis() - start) / 1000);
+                } else {
+                    view.updateTime(-1);
+                }
             }
         }
     }
@@ -376,7 +482,7 @@
 
         if (event.start) {
             getView().displayVideoSurface(true, !isPipMode() && mDeviceRuntimeService.hasVideoPermission());
-        } else if (mSipCall != null && mSipCall.getDaemonIdString().equals(event.callId)) {
+        } else if (mSipCall != null && mSipCall.getId().equals(event.callId)) {
             getView().displayVideoSurface(event.started, event.started && !isPipMode() && mDeviceRuntimeService.hasVideoPermission());
             if (event.started) {
                 videoWidth = event.w;
@@ -422,8 +528,8 @@
     }
 
     public void requestPipMode() {
-        if (mSipCall != null && mSipCall.isOnGoing() && !mSipCall.isAudioOnly()) {
-            getView().enterPipMode(mSipCall);
+        if (mSipCall != null && mSipCall.isOnGoing() && mSipCall.hasVideo()) {
+            getView().enterPipMode(mSipCall.getId());
         }
     }
 
@@ -450,4 +556,79 @@
     public void sendDtmf(CharSequence s) {
         mCallService.playDtmf(s.toString());
     }
+
+    public void addConferenceParticipant(String accountId, String contactId) {
+        String destCallId = mSipCall.getId();
+
+        mCompositeDisposable.add(mConversationFacade.startConversation(accountId, new Uri(contactId))
+                .map(Conversation::getCurrentCalls)
+                .subscribe(calls -> {
+                    if (calls.isEmpty()) {
+                        final Observer<SipCall>  pendingObserver = new Observer<SipCall>() {
+                            private SipCall call = null;
+                            @Override
+                            public void onSubscribe(Disposable d) {}
+
+                            @Override
+                            public void onNext(SipCall sipCall) {
+                                Log.w(TAG, "placeCallObservable onNext " + sipCall.getCallStatus());
+                                if (call == null) {
+                                    call = sipCall;
+                                    mPendingCalls.add(sipCall);
+                                }
+                                mPendingSubject.onNext(mPendingCalls);
+                            }
+
+                            @Override
+                            public void onError(Throwable e) {}
+
+                            @Override
+                            public void onComplete() {
+                                Log.w(TAG, "placeCallObservable onComplete " + call);
+                                if (call != null) {
+                                    mPendingCalls.remove(call);
+                                    mPendingSubject.onNext(mPendingCalls);
+                                    call = null;
+                                }
+                            }
+                        };
+
+                        // Place new call, join to conference when answered
+                        Maybe<SipCall> newCall = mCallService.placeCallObservable(accountId, contactId, mAudioOnly)
+                                .doOnEach(pendingObserver)
+                                .filter(SipCall::isOnGoing)
+                                .firstElement()
+                                .delay(1, TimeUnit.SECONDS)
+                                .doOnEvent((v, e) -> pendingObserver.onComplete());
+                        if (mSipCall.getParticipants().size() > 1) {
+                            mCompositeDisposable.add(newCall.subscribe(call -> mCallService.joinConference(destCallId, call.getDaemonIdString())));
+                        } else {
+                            mCompositeDisposable.add(newCall.subscribe(call -> mCallService.joinParticipant(destCallId, call.getDaemonIdString())));
+                        }
+
+                    } else {
+                        // Selected contact already in call or conference, join it to current conference
+                        Conference call = calls.get(0);
+                        if (call != mSipCall) {
+                            if (mSipCall.getParticipants().size() > 1) {
+                                mCallService.joinConference(destCallId, call.getId());
+                            } else {
+                                mCallService.joinParticipant(destCallId, call.getId());
+                            }
+                        }
+                    }
+                }));
+    }
+
+    public void startAddParticipant() {
+        getView().startAddParticipant(mSipCall.getId());
+    }
+
+    public void hangupParticipant(SipCall call) {
+        mCallService.hangUp(call.getDaemonIdString());
+    }
+
+    public void openParticipantContact(SipCall call) {
+        getView().goToContact(call.getAccount(), call.getContact());
+    }
 }
diff --git a/ring-android/libringclient/src/main/java/cx/ring/call/CallView.java b/ring-android/libringclient/src/main/java/cx/ring/call/CallView.java
index 2c028bf..12bb537 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/call/CallView.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/call/CallView.java
@@ -19,6 +19,8 @@
  */
 package cx.ring.call;
 
+import java.util.List;
+
 import cx.ring.model.CallContact;
 import cx.ring.model.SipCall.CallStatus;
 import cx.ring.model.SipCall;
@@ -44,11 +46,11 @@
 
     void updateTime(long duration);
 
-    void updateContactBubble(CallContact contact);
+    void updateContactBubble(List<SipCall> contact);
 
     void updateCallStatus(CallStatus callState);
 
-    void initMenu(boolean isSpeakerOn, boolean hasContact, boolean displayFlip, boolean canDial, boolean onGoingCall);
+    void initMenu(boolean isSpeakerOn, boolean displayFlip, boolean canDial, boolean onGoingCall);
 
     void initNormalStateDisplay(boolean audioOnly, boolean muted);
 
@@ -63,13 +65,17 @@
 
     void goToAddContact(CallContact callContact);
 
+    void startAddParticipant(String conferenceId);
+
     void finish();
 
     void onUserLeave();
 
-    void enterPipMode(SipCall sipCall);
+    void enterPipMode(String callId);
 
     void prepareCall(boolean isIncoming);
 
     void handleCallWakelock(boolean isAudioOnly);
+
+    void goToContact(String accountId, CallContact contact);
 }
diff --git a/ring-android/libringclient/src/main/java/cx/ring/facades/ConversationFacade.java b/ring-android/libringclient/src/main/java/cx/ring/facades/ConversationFacade.java
index 646a897..c8216e8 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/facades/ConversationFacade.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/facades/ConversationFacade.java
@@ -92,10 +92,14 @@
                 .getCurrentAccountSubject()
                 .switchMapSingle(this::loadSmartlist);
 
-        mDisposableBag.add(mCallService.getCallSubject()
+        mDisposableBag.add(mCallService.getCallsUpdates()
                 .observeOn(Schedulers.io())
                 .subscribe(this::onCallStateChange));
 
+        mDisposableBag.add(mCallService.getConfsUpdates()
+                .observeOn(Schedulers.io())
+                .subscribe(this::onConfStateChange));
+
         mDisposableBag.add(currentAccountSubject
                 .switchMap(a -> a.getPendingSubject()
                         .doOnNext(p -> mNotificationService.showIncomingTrustRequestNotification(a)))
@@ -391,7 +395,6 @@
                 .subscribe(c -> updateTextNotifications(txt.getAccount(), c), e -> Log.e(TAG, e.getMessage()));
     }
 
-
     public void acceptRequest(String accountId, Uri contactUri) {
         if (accountId == null || contactUri == null)
             return;
@@ -415,8 +418,12 @@
         mNotificationService.handleDataTransferNotification(transfer, conversation.getContact(), conversation.isVisible());
     }
 
+    private void onConfStateChange(Conference conference) {
+        Log.d(TAG, "onConfStateChange Thread id: " + Thread.currentThread().getId());
+    }
+
     private void onCallStateChange(SipCall call) {
-        Log.d(TAG, "Thread id: " + Thread.currentThread().getId());
+        Log.d(TAG, "onCallStateChange Thread id: " + Thread.currentThread().getId());
         SipCall.CallStatus newState = call.getCallStatus();
         boolean incomingCall = newState == SipCall.CallStatus.RINGING && call.isIncoming();
         mHardwareService.updateAudioState(newState, incomingCall, !call.isAudioOnly());
@@ -440,6 +447,7 @@
         if ((call.isRinging() || newState == SipCall.CallStatus.CURRENT) && call.getTimestamp() == 0) {
             call.setTimestamp(System.currentTimeMillis());
         }
+
         if (incomingCall) {
             mNotificationService.handleCallNotification(conference, false);
             mHardwareService.setPreviewSettings();
diff --git a/ring-android/libringclient/src/main/java/cx/ring/model/Conference.java b/ring-android/libringclient/src/main/java/cx/ring/model/Conference.java
index 4768434..44e95f2 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/model/Conference.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/model/Conference.java
@@ -22,29 +22,24 @@
 package cx.ring.model;
 
 import java.util.ArrayList;
-import java.util.Random;
+import java.util.List;
 
 public class Conference {
 
     private String mId;
     private SipCall.CallStatus mConfState;
-    private ArrayList<SipCall> mParticipants;
+    private final ArrayList<SipCall> mParticipants;
     private boolean mRecording;
-    private int uuid;
-
-    private static String DEFAULT_ID = "-1";
 
     public Conference(SipCall call) {
-        this(DEFAULT_ID);
+        this(call.getDaemonIdString());
         mParticipants.add(call);
-        uuid = new Random().nextInt();
     }
 
     public Conference(String cID) {
         mId = cID;
         mParticipants = new ArrayList<>();
         mRecording = false;
-        uuid = new Random().nextInt();
     }
 
     public Conference(Conference c) {
@@ -52,15 +47,21 @@
         mConfState = c.mConfState;
         mParticipants = new ArrayList<>(c.mParticipants);
         mRecording = c.mRecording;
-        uuid = c.getUuid();
     }
 
     public boolean isRinging() {
         return !mParticipants.isEmpty() && mParticipants.get(0).isRinging();
     }
 
-    public int getUuid() {
-        return uuid;
+    public boolean isConference() {
+        return mParticipants.size() > 1;
+    }
+
+    public SipCall getCall() {
+        if (!isConference() && !mParticipants.isEmpty()) {
+            return mParticipants.get(0);
+        }
+        return null;
     }
 
     public String getId() {
@@ -71,13 +72,17 @@
         }
     }
 
+    public String getConfId() {
+        return mId;
+    }
+
     public SipCall.CallStatus getState() {
         if (mParticipants.size() == 1) {
             return mParticipants.get(0).getCallStatus();
         }
         return mConfState;
     }
-    public ArrayList<SipCall> getParticipants() {
+    public List<SipCall> getParticipants() {
         return mParticipants;
     }
 
@@ -89,7 +94,7 @@
         return mParticipants.remove(toRemove);
     }
 
-    boolean contains(String callID) {
+    public boolean contains(String callID) {
         for (SipCall participant : mParticipants) {
             if (participant.getDaemonIdString().contentEquals(callID))
                 return true;
@@ -105,28 +110,6 @@
         return null;
     }
 
-    /**
-     * Compare conferences based on confID/participants
-     */
-    @Override
-    public boolean equals(Object c) {
-        if (c instanceof Conference) {
-            if (((Conference) c).mId.contentEquals(mId) && !mId.contentEquals("-1")) {
-                return true;
-            } else {
-                if (((Conference) c).mId.contentEquals(mId)) {
-                    for (SipCall participant : mParticipants) {
-                        if (!((Conference) c).contains(participant.getDaemonIdString())) {
-                            return false;
-                        }
-                    }
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     public boolean isIncoming() {
         return mParticipants.size() == 1 && mParticipants.get(0).isIncoming();
     }
@@ -135,4 +118,21 @@
         return mParticipants.size() == 1 && mParticipants.get(0).isOnGoing() || mParticipants.size() > 1;
     }
 
+    public boolean hasVideo() {
+        for (SipCall call : mParticipants)
+            if (!call.isAudioOnly())
+                return true;
+        return false;
+    }
+
+    public long getTimestampStart() {
+        long t = Long.MAX_VALUE;
+        for (SipCall call : mParticipants)
+            t = Math.min(call.getTimestamp(), t);
+        return t;
+    }
+
+    public void removeParticipants() {
+        mParticipants.clear();
+    }
 }
diff --git a/ring-android/libringclient/src/main/java/cx/ring/model/SipCall.java b/ring-android/libringclient/src/main/java/cx/ring/model/SipCall.java
index b3f599a..2fcbc9f 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/model/SipCall.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/model/SipCall.java
@@ -14,9 +14,8 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 package cx.ring.model;
 
@@ -28,6 +27,7 @@
 import java.util.Map;
 
 import cx.ring.utils.ProfileChunk;
+import cx.ring.utils.StringUtils;
 import cx.ring.utils.VCardUtils;
 import ezvcard.Ezvcard;
 import ezvcard.VCard;
@@ -45,6 +45,7 @@
     public final static String KEY_AUDIO_CODEC = "AUDIO_CODEC";
     public final static String KEY_VIDEO_CODEC = "VIDEO_CODEC";
     public final static String KEY_DURATION = "duration";
+    public final static String KEY_CONF_ID = "CONF_ID";
 
     private boolean isPeerHolding = false;
     private boolean isAudioMuted = false;
@@ -52,7 +53,6 @@
     private boolean isRecording = false;
     private boolean isAudioOnly = false;
 
-
     private CallStatus mCallStatus = CallStatus.NONE;
 
     private long timestampEnd = 0;
@@ -60,10 +60,11 @@
     private String mAudioCodec;
     private String mVideoCodec;
     private String mContactNumber;
+    private String mConfId;
 
     private ProfileChunk mProfileChunk = null;
 
-    public SipCall(String daemonId, String author, String account, ConversationHistory conversation, CallContact contact, int direction) {
+    public SipCall(String daemonId, String author, String account, ConversationHistory conversation, CallContact contact, Direction direction) {
         mDaemonId = daemonId == null ? null : Long.parseLong(daemonId);
         mAuthor = direction == Direction.INCOMING ? author : null;
         mAccount = account;
@@ -92,7 +93,7 @@
         mContact = interaction.getContact();
     }
 
-    public SipCall(String daemonId, String account, String contactNumber, int direction) {
+    public SipCall(String daemonId, String account, String contactNumber, Direction direction) {
         mDaemonId = daemonId == null ? null : Long.parseLong(daemonId);
         mIsIncoming = direction == Direction.INCOMING;
         mAccount = account;
@@ -104,42 +105,11 @@
     }
 
     public SipCall(String daemonId, Map<String, String> call_details) {
-        this(daemonId, call_details.get(KEY_ACCOUNT_ID), call_details.get(KEY_PEER_NUMBER), Integer.parseInt(call_details.get(KEY_CALL_TYPE)));
+        this(daemonId, call_details.get(KEY_ACCOUNT_ID), call_details.get(KEY_PEER_NUMBER), Direction.fromInt(Integer.parseInt(call_details.get(KEY_CALL_TYPE))));
         setCallState(CallStatus.fromString(call_details.get(KEY_CALL_STATE)));
         setDetails(call_details);
     }
 
-    public static CallStatus stateFromString(String state) {
-        switch (state) {
-            case "SEARCHING":
-                return CallStatus.SEARCHING;
-            case "CONNECTING":
-                return CallStatus.CONNECTING;
-            case "INCOMING":
-            case "RINGING":
-                return CallStatus.RINGING;
-            case "CURRENT":
-                return CallStatus.CURRENT;
-            case "HUNGUP":
-                return CallStatus.HUNGUP;
-            case "BUSY":
-                return CallStatus.BUSY;
-            case "FAILURE":
-                return CallStatus.FAILURE;
-            case "HOLD":
-                return CallStatus.HOLD;
-            case "UNHOLD":
-                return CallStatus.UNHOLD;
-            case "INACTIVE":
-                return CallStatus.INACTIVE;
-            case "OVER":
-                return CallStatus.OVER;
-            case "NONE":
-            default:
-                return CallStatus.NONE;
-        }
-    }
-
     public void setDetails(Map<String, String> details) {
         isPeerHolding = "true".equals(details.get(KEY_PEER_HOLDING));
         isAudioMuted = "true".equals(details.get(KEY_AUDIO_MUTED));
@@ -147,6 +117,12 @@
         isAudioOnly = "true".equals(details.get(KEY_AUDIO_ONLY));
         mAudioCodec = details.get(KEY_AUDIO_CODEC);
         mVideoCodec = details.get(KEY_VIDEO_CODEC);
+        String confId = details.get(KEY_CONF_ID);
+        mConfId = StringUtils.isEmpty(confId) ? null : confId;
+    }
+
+    public boolean isConferenceParticipant() {
+        return mConfId != null;
     }
 
     public String getContactNumber() {
@@ -207,6 +183,14 @@
         return mAudioCodec;
     }
 
+    public String getConfId() {
+        return mConfId;
+    }
+
+    public void setConfId(String confId) {
+        mConfId = confId;
+    }
+
     public void setCallState(CallStatus callStatus) {
         mCallStatus = callStatus;
         if (callStatus == CallStatus.CURRENT) {
@@ -235,7 +219,7 @@
         return mCallStatus == CallStatus.CURRENT || mCallStatus == CallStatus.HOLD || mCallStatus == CallStatus.UNHOLD;
     }
 
-    public void setIsIncoming(int direction) {
+    public void setIsIncoming(Direction direction) {
         mIsIncoming = (direction == Direction.INCOMING);
     }
 
@@ -275,20 +259,51 @@
         INACTIVE,
         OVER;
 
-        static CallStatus fromString(String str) {
-            for (CallStatus status : values()) {
-                if (status.name().equals(str)) {
-                    return status;
-                }
+        public static CallStatus fromString(String state) {
+            switch (state) {
+                case "SEARCHING":
+                    return SEARCHING;
+                case "CONNECTING":
+                    return CONNECTING;
+                case "INCOMING":
+                case "RINGING":
+                    return RINGING;
+                case "CURRENT":
+                    return CURRENT;
+                case "HUNGUP":
+                    return HUNGUP;
+                case "BUSY":
+                    return BUSY;
+                case "FAILURE":
+                    return FAILURE;
+                case "HOLD":
+                    return HOLD;
+                case "UNHOLD":
+                    return UNHOLD;
+                case "INACTIVE":
+                    return INACTIVE;
+                case "OVER":
+                    return OVER;
+                case "NONE":
+                default:
+                    return NONE;
             }
-            return NONE;
         }
     }
 
-    public interface Direction {
-        int INCOMING = 0;
-        int OUTGOING = 1;
+    public enum  Direction {
+        INCOMING(0),
+        OUTGOING(1);
+
+        private final int value;
+        Direction(int v) {
+            value = v;
+        }
+        int getValue() {
+            return value;
+        }
+        static Direction fromInt(int value) {
+            return value == INCOMING.value ? INCOMING : OUTGOING;
+        }
     }
-
-
 }
diff --git a/ring-android/libringclient/src/main/java/cx/ring/navigation/RingNavigationPresenter.java b/ring-android/libringclient/src/main/java/cx/ring/navigation/HomeNavigationPresenter.java
similarity index 95%
rename from ring-android/libringclient/src/main/java/cx/ring/navigation/RingNavigationPresenter.java
rename to ring-android/libringclient/src/main/java/cx/ring/navigation/HomeNavigationPresenter.java
index c7078dc..a049eff 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/navigation/RingNavigationPresenter.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/navigation/HomeNavigationPresenter.java
@@ -43,9 +43,9 @@
 import io.reactivex.Single;
 import io.reactivex.schedulers.Schedulers;
 
-public class RingNavigationPresenter extends RootPresenter<RingNavigationView> {
+public class HomeNavigationPresenter extends RootPresenter<HomeNavigationView> {
 
-    private static final String TAG = RingNavigationPresenter.class.getSimpleName();
+    private static final String TAG = HomeNavigationPresenter.class.getSimpleName();
 
     private final AccountService mAccountService;
     private final DeviceRuntimeService mDeviceRuntimeService;
@@ -56,7 +56,7 @@
     protected Scheduler mUiScheduler;
 
     @Inject
-    public RingNavigationPresenter(AccountService accountService,
+    public HomeNavigationPresenter(AccountService accountService,
                                    HardwareService hardwareService,
                                    DeviceRuntimeService deviceRuntimeService) {
         mAccountService = accountService;
@@ -65,19 +65,19 @@
     }
 
     @Override
-    public void bindView(RingNavigationView view) {
+    public void bindView(HomeNavigationView view) {
         super.bindView(view);
         mCompositeDisposable.add(mAccountService.getProfileAccountList()
                 .observeOn(mUiScheduler)
                 .subscribe(accounts -> {
-                    RingNavigationView v = getView();
+                    HomeNavigationView v = getView();
                     if (v != null)
-                        v.showViewModel(new RingNavigationViewModel(accounts.isEmpty() ? null : accounts.get(0), accounts));
+                        v.showViewModel(new HomeNavigationViewModel(accounts.isEmpty() ? null : accounts.get(0), accounts));
                 }, e ->  Log.e(TAG, "Error loading account list !", e)));
         mCompositeDisposable.add(mAccountService.getObservableAccounts()
                 .observeOn(mUiScheduler)
                 .subscribe(account -> {
-                    RingNavigationView v = getView();
+                    HomeNavigationView v = getView();
                     if (v != null)
                         v.updateModel(account);
                 }, e ->  Log.e(TAG, "Error loading account list !", e)));
diff --git a/ring-android/libringclient/src/main/java/cx/ring/navigation/RingNavigationView.java b/ring-android/libringclient/src/main/java/cx/ring/navigation/HomeNavigationView.java
similarity index 91%
rename from ring-android/libringclient/src/main/java/cx/ring/navigation/RingNavigationView.java
rename to ring-android/libringclient/src/main/java/cx/ring/navigation/HomeNavigationView.java
index 3961400..e14df02 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/navigation/RingNavigationView.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/navigation/HomeNavigationView.java
@@ -21,9 +21,9 @@
 
 import cx.ring.model.Account;
 
-public interface RingNavigationView {
+public interface HomeNavigationView {
 
-    void showViewModel(RingNavigationViewModel viewModel);
+    void showViewModel(HomeNavigationViewModel viewModel);
 
     void updateModel(Account account);
 
diff --git a/ring-android/libringclient/src/main/java/cx/ring/navigation/RingNavigationViewModel.java b/ring-android/libringclient/src/main/java/cx/ring/navigation/HomeNavigationViewModel.java
similarity index 92%
rename from ring-android/libringclient/src/main/java/cx/ring/navigation/RingNavigationViewModel.java
rename to ring-android/libringclient/src/main/java/cx/ring/navigation/HomeNavigationViewModel.java
index 1098bd1..30a7c44 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/navigation/RingNavigationViewModel.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/navigation/HomeNavigationViewModel.java
@@ -24,11 +24,11 @@
 
 import cx.ring.model.Account;
 
-public class RingNavigationViewModel {
+public class HomeNavigationViewModel {
     final private Account mAccount;
     final private List<Account> mAccounts;
 
-    public RingNavigationViewModel(Account account, List<Account> accounts) {
+    public HomeNavigationViewModel(Account account, List<Account> accounts) {
         mAccount = account;
         mAccounts = accounts;
     }
diff --git a/ring-android/libringclient/src/main/java/cx/ring/services/CallService.java b/ring-android/libringclient/src/main/java/cx/ring/services/CallService.java
index d06d43e..76d0da8 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/services/CallService.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/services/CallService.java
@@ -20,19 +20,25 @@
  */
 package cx.ring.services;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ScheduledExecutorService;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 
 import cx.ring.daemon.Blob;
-import cx.ring.daemon.IntegerMap;
 import cx.ring.daemon.Ringservice;
 import cx.ring.daemon.StringMap;
+import cx.ring.daemon.StringVect;
 import cx.ring.model.Account;
 import cx.ring.model.CallContact;
+import cx.ring.model.Conference;
 import cx.ring.model.Conversation;
 import cx.ring.model.SipCall;
 import cx.ring.model.Uri;
@@ -43,7 +49,6 @@
 import io.reactivex.Single;
 import io.reactivex.schedulers.Schedulers;
 import io.reactivex.subjects.PublishSubject;
-import io.reactivex.subjects.Subject;
 
 public class CallService {
 
@@ -66,20 +71,89 @@
     @Inject
     DeviceRuntimeService mDeviceRuntimeService;
 
-    private Map<String, SipCall> currentCalls = new HashMap<>();
-    private final PublishSubject<SipCall> callSubject = PublishSubject.create();
+    private final Map<String, SipCall> currentCalls = new HashMap<>();
+    private final Map<String, Conference> currentConferences = new HashMap<>();
 
-    public Subject<SipCall> getCallSubject() {
+    private final PublishSubject<SipCall> callSubject = PublishSubject.create();
+    private final PublishSubject<Conference> conferenceSubject = PublishSubject.create();
+
+
+    public Observable<Conference> getConfsUpdates() {
+        return conferenceSubject;
+    }
+
+    private Observable<Conference> getConfCallUpdates(final Conference conf) {
+        Log.w(TAG, "getConfCallUpdates " + conf.getConfId());
+
+        return conferenceSubject
+                .filter(c -> c == conf)
+                .startWith(conf)
+                .map(Conference::getParticipants)
+                .switchMap(list -> Observable.fromIterable(list)
+                        .flatMap(call -> callSubject.filter(c -> c == call)))
+                .map(call -> conf)
+                .startWith(conf);
+    }
+
+    public Observable<Conference> getConfUpdates(final String confId) {
+        SipCall call = getCurrentCallForId(confId);
+        return call == null ? Observable.error(new IllegalArgumentException()) : getConfUpdates(call);
+        /*Conference call = currentConferences.get(confId);
+        return call == null ? Observable.error(new IllegalArgumentException()) : conferenceSubject
+                .filter(c -> c.getId().equals(confId));//getConfUpdates(call);*/
+    }
+
+    private static class ConferenceEntity {
+        Conference conference;
+        ConferenceEntity(Conference conf) {
+            conference = conf;
+        }
+    }
+
+    public Observable<Conference> getConfUpdates(final SipCall call) {
+        return getConfUpdates(getConference(call));
+    }
+    private Observable<Conference> getConfUpdates(final Conference conference) {
+        Log.w(TAG, "getConfUpdates " + conference.getId());
+
+        ConferenceEntity conferenceEntity = new ConferenceEntity(conference);
+        return conferenceSubject
+                .startWith(conference)
+                .filter(conf -> {
+                    Log.w(TAG, "getConfUpdates filter " + conf.getConfId() + " " + conf.getParticipants().size() + " (tracked " + conferenceEntity.conference.getConfId() + " " + conferenceEntity.conference.getParticipants().size() + ")");
+                    if (conf == conferenceEntity.conference) {
+                        return true;
+                    }
+                    if (conf.contains(conferenceEntity.conference.getId())) {
+                        Log.w(TAG, "Switching tracked conference (up) to " + conf.getId());
+                        conferenceEntity.conference = conf;
+                        return true;
+                    }
+                    if (conferenceEntity.conference.getParticipants().size() == 1
+                            && conf.getParticipants().size() == 1
+                            && conferenceEntity.conference.getCall() == conf.getCall()
+                            && conf.getCall().getDaemonIdString().equals(conf.getConfId())) {
+                        Log.w(TAG, "Switching tracked conference (down) to " + conf.getId());
+                        conferenceEntity.conference = conf;
+                        return true;
+                    }
+                    return false;
+                })
+                .switchMap(this::getConfCallUpdates);
+    }
+
+    public Observable<SipCall> getCallsUpdates() {
         return callSubject;
     }
-
-    public Observable<SipCall> getCallUpdates(final SipCall call) {
-        return callSubject.filter(c -> c == call).startWith(call);
+    private Observable<SipCall> getCallUpdates(final SipCall call) {
+        return callSubject.filter(c -> c == call)
+                .startWith(call)
+                .takeWhile(c -> c.getCallStatus() != SipCall.CallStatus.OVER);
     }
-    public Observable<SipCall> getCallUpdates(final String callId) {
+    /*public Observable<SipCall> getCallUpdates(final String callId) {
         SipCall call = getCurrentCallForId(callId);
         return call == null ? Observable.error(new IllegalArgumentException()) : getCallUpdates(call);
-    }
+    }*/
 
     public Observable<SipCall> placeCallObservable(final String accountId, final String number, final boolean audioOnly) {
         return placeCall(accountId, number, audioOnly)
@@ -234,7 +308,6 @@
         return null;
     }
 
-    @SuppressWarnings("ConstantConditions")
     public boolean toggleRecordingCall(final String id) {
         mExecutor.execute(() -> Ringservice.toggleRecording(id));
         return false;
@@ -280,7 +353,7 @@
                 .subscribeOn(Schedulers.from(mExecutor));
     }
 
-    public SipCall getCurrentCallForId(String callId) {
+    private SipCall getCurrentCallForId(String callId) {
         return currentCalls.get(callId);
     }
 
@@ -295,14 +368,16 @@
 
     public void removeCallForId(String callId) {
         currentCalls.remove(callId);
+        currentConferences.remove(callId);
     }
 
-    private SipCall addCall(String accountId, String callId, String from, int direction) {
-        Account account = mAccountService.getAccount(accountId);
-        Conversation conversation = account.getByUri(new Uri(from).getUri());
+    private SipCall addCall(String accountId, String callId, String from, SipCall.Direction direction) {
         SipCall call = currentCalls.get(callId);
         if (call == null) {
-            CallContact contact = mContactService.findContact(account, new Uri(from));
+            Account account = mAccountService.getAccount(accountId);
+            Uri fromUri = new Uri(from);
+            Conversation conversation = account.getByUri(fromUri);
+            CallContact contact = mContactService.findContact(account, fromUri);
             call = new SipCall(callId, new Uri(from).getUri(), accountId, conversation, contact, direction);
             currentCalls.put(callId, call);
         } else {
@@ -311,8 +386,24 @@
         return call;
     }
 
+    private Conference addConference(SipCall call) {
+        String confId = call.getConfId();
+        if (confId == null) {
+            confId = call.getDaemonIdString();
+        }
+        Conference conference = currentConferences.get(confId);
+        if (conference == null) {
+            conference = new Conference(call);
+            currentConferences.put(confId, conference);
+            conferenceSubject.onNext(conference);
+        } else {
+            Log.w(TAG, "Conference already existed ! " + confId);
+        }
+        return conference;
+    }
+
     private SipCall parseCallState(String callId, String newState) {
-        SipCall.CallStatus callState = SipCall.stateFromString(newState);
+        SipCall.CallStatus callState = SipCall.CallStatus.fromString(newState);
         SipCall sipCall = currentCalls.get(callId);
         if (sipCall != null) {
             sipCall.setCallState(callState);
@@ -349,6 +440,7 @@
                 callSubject.onNext(call);
                 if (call.getCallStatus() == SipCall.CallStatus.OVER) {
                     currentCalls.remove(call.getDaemonIdString());
+                    currentConferences.remove(call.getDaemonIdString());
                 }
             }
         } catch (Exception e) {
@@ -383,8 +475,218 @@
         // todo needs more explainations on that
     }
 
-    void onRtcpReportReceived(String callId, IntegerMap stats) {
+    void onRtcpReportReceived(String callId) {
         Log.i(TAG, "on RTCP report received: " + callId);
     }
 
-}
\ No newline at end of file
+    public void removeConference(final String confId) {
+        mExecutor.execute(() -> Ringservice.removeConference(confId));
+    }
+
+    public void joinParticipant(final String selCallId, final String dragCallId) {
+        mExecutor.execute(() -> Ringservice.joinParticipant(selCallId, dragCallId));
+    }
+
+    public void addParticipant(final String callId, final String confId) {
+        mExecutor.execute(() -> Ringservice.addParticipant(callId, confId));
+    }
+
+    public void addMainParticipant(final String confId) {
+        mExecutor.execute(() -> Ringservice.addMainParticipant(confId));
+    }
+
+    public void detachParticipant(final String callId) {
+        mExecutor.execute(() -> Ringservice.detachParticipant(callId));
+    }
+
+    public void joinConference(final String selConfId, final String dragConfId) {
+        mExecutor.execute(() -> Ringservice.joinConference(selConfId, dragConfId));
+    }
+
+    public void hangUpConference(final String confId) {
+        mExecutor.execute(() -> Ringservice.hangUpConference(confId));
+    }
+
+    public void holdConference(final String confId) {
+        mExecutor.execute(() -> Ringservice.holdConference(confId));
+    }
+
+    public void unholdConference(final String confId) {
+        mExecutor.execute(() -> Ringservice.unholdConference(confId));
+    }
+
+    public boolean isConferenceParticipant(final String callId) {
+        try {
+            return mExecutor.submit(() -> {
+                Log.i(TAG, "isConferenceParticipant() running...");
+                return Ringservice.isConferenceParticipant(callId);
+            }).get();
+        } catch (Exception e) {
+            Log.e(TAG, "Error running isConferenceParticipant()", e);
+        }
+        return false;
+    }
+
+    public Map<String, ArrayList<String>> getConferenceList() {
+        try {
+            return mExecutor.submit(() -> {
+                Log.i(TAG, "getConferenceList() running...");
+                StringVect callIds = Ringservice.getCallList();
+                HashMap<String, ArrayList<String>> confs = new HashMap<>(callIds.size());
+                for (int i = 0; i < callIds.size(); i++) {
+                    String callId = callIds.get(i);
+                    String confId = Ringservice.getConferenceId(callId);
+                    Map<String, String> callDetails = Ringservice.getCallDetails(callId).toNative();
+
+                    //todo remove condition when callDetails does not contains sips ids anymore
+                    if (!callDetails.get("PEER_NUMBER").contains("sips")) {
+                        if (confId == null || confId.isEmpty()) {
+                            confId = callId;
+                        }
+                        ArrayList<String> calls = confs.get(confId);
+                        if (calls == null) {
+                            calls = new ArrayList<>();
+                            confs.put(confId, calls);
+                        }
+                        calls.add(callId);
+                    }
+                }
+                return confs;
+            }).get();
+        } catch (Exception e) {
+            Log.e(TAG, "Error running isConferenceParticipant()", e);
+        }
+        return null;
+    }
+
+    public List<String> getParticipantList(final String confId) {
+        try {
+            return mExecutor.submit(() -> {
+                Log.i(TAG, "getParticipantList() running...");
+                return new ArrayList<>(Ringservice.getParticipantList(confId));
+            }).get();
+        } catch (Exception e) {
+            Log.e(TAG, "Error running getParticipantList()", e);
+        }
+        return null;
+    }
+
+    public Conference getConference(SipCall call) {
+        return addConference(call);
+    }
+
+    public String getConferenceId(String callId) {
+        return Ringservice.getConferenceId(callId);
+    }
+
+    public String getConferenceState(final String callId) {
+        try {
+            return mExecutor.submit(() -> {
+                Log.i(TAG, "getConferenceDetails() thread running...");
+                return Ringservice.getConferenceDetails(callId).get("CONF_STATE");
+            }).get();
+        } catch (Exception e) {
+            Log.e(TAG, "Error running getParticipantList()", e);
+        }
+        return null;
+    }
+
+    public Conference getConference(final String id) {
+        return currentConferences.get(id);
+    }
+
+    public Map<String, String> getConferenceDetails(final String id) {
+        try {
+            return mExecutor.submit(() -> {
+                Log.i(TAG, "getCredentials() thread running...");
+                return Ringservice.getConferenceDetails(id).toNative();
+            }).get();
+        } catch (Exception e) {
+            Log.e(TAG, "Error running getParticipantList()", e);
+        }
+        return null;
+    }
+
+    void conferenceCreated(final String confId) {
+        Log.d(TAG, "conference created: " + confId);
+
+        Conference conf = currentConferences.get(confId);
+        if (conf == null) {
+            conf = new Conference(confId);
+            currentConferences.put(confId, conf);
+        }
+        StringVect participants = Ringservice.getParticipantList(confId);
+        for (String callId : participants) {
+            SipCall call = getCurrentCallForId(callId);
+            if (call != null) {
+                Log.d(TAG, "conference created: adding participant " + callId + " " + call.getContact().getDisplayName());
+                call.setConfId(confId);
+                conf.addParticipant(call);
+            }
+            Conference rconf = currentConferences.remove(callId);
+            Log.d(TAG, "conference created: removing conference " + callId + " " + rconf + " now " + currentConferences.size());
+        }
+        conferenceSubject.onNext(conf);
+    }
+
+    void conferenceRemoved(String confId) {
+        Log.d(TAG, "conference removed: " + confId);
+
+        Conference conf = currentConferences.remove(confId);
+        if (conf != null) {
+            for (SipCall call : conf.getParticipants()) {
+                call.setConfId(null);
+            }
+            conf.removeParticipants();
+            conferenceSubject.onNext(conf);
+        }
+    }
+
+    void conferenceChanged(String confId, String state) {
+        Log.d(TAG, "conference changed: " + confId + ", " + state);
+        try {
+            Conference conf = currentConferences.get(confId);
+            if (conf == null) {
+                conf = new Conference(confId);
+                currentConferences.put(confId, conf);
+            }
+            Set<String> participants = new HashSet<>(Ringservice.getParticipantList(confId));
+            // Add new participants
+            for (String callId : participants) {
+                if (!conf.contains(callId)) {
+                    SipCall call = getCurrentCallForId(callId);
+                    if (call != null) {
+                        Log.d(TAG, "conference changed: adding participant " + callId + " " + call.getContact().getDisplayName());
+                        call.setConfId(confId);
+                        conf.addParticipant(call);
+                    }
+                    currentConferences.remove(callId);
+                }
+            }
+
+            // Remove participants
+            List<SipCall> calls = conf.getParticipants();
+            Iterator<SipCall> i = calls.iterator();
+            boolean removed = false;
+            while (i.hasNext()) {
+                SipCall call = i.next();
+                if (!participants.contains(call.getDaemonIdString())) {
+                    Log.d(TAG, "conference changed: removing participant " + call.getDaemonIdString() + " " + call.getContact().getDisplayName());
+                    call.setConfId(null);
+                    i.remove();
+                    removed = true;
+                }
+            }
+
+            conferenceSubject.onNext(conf);
+
+            if (removed && conf.getParticipants().size() == 1 && conf.getConfId() != null) {
+                SipCall call = conf.getCall();
+                call.setConfId(null);
+                addConference(call);
+            }
+        } catch (Exception e) {
+            Log.w(TAG, "exception in conferenceChanged", e);
+        }
+    }
+}
diff --git a/ring-android/libringclient/src/main/java/cx/ring/services/DaemonService.java b/ring-android/libringclient/src/main/java/cx/ring/services/DaemonService.java
index b2a022b..bff6d67 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/services/DaemonService.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/services/DaemonService.java
@@ -54,9 +54,6 @@
     protected CallService mCallService;
 
     @Inject
-    protected ConferenceService mConferenceService;
-
-    @Inject
     protected HardwareService mHardwareService;
 
     @Inject
@@ -250,17 +247,17 @@
 
         @Override
         public void conferenceCreated(final String confId) {
-            mConferenceService.conferenceCreated(confId);
+            mCallService.conferenceCreated(confId);
         }
 
         @Override
         public void conferenceRemoved(String confId) {
-            mConferenceService.conferenceRemoved(confId);
+            mCallService.conferenceRemoved(confId);
         }
 
         @Override
         public void conferenceChanged(String confId, String state) {
-            mConferenceService.conferenceChanged(confId, state);
+            mCallService.conferenceChanged(confId, state);
         }
 
         @Override
@@ -270,9 +267,8 @@
 
         @Override
         public void onRtcpReportReceived(String callId, IntegerMap stats) {
-            mCallService.onRtcpReportReceived(callId, stats);
+            mCallService.onRtcpReportReceived(callId);
         }
-
     }
 
     class DaemonPresenceCallback extends PresenceCallback {
diff --git a/ring-android/libringclient/src/main/java/cx/ring/services/HardwareService.java b/ring-android/libringclient/src/main/java/cx/ring/services/HardwareService.java
index 0ee6a30..9abcfc5 100644
--- a/ring-android/libringclient/src/main/java/cx/ring/services/HardwareService.java
+++ b/ring-android/libringclient/src/main/java/cx/ring/services/HardwareService.java
@@ -32,6 +32,7 @@
 import cx.ring.daemon.RingserviceJNI;
 import cx.ring.daemon.StringMap;
 import cx.ring.daemon.UintVect;
+import cx.ring.model.Conference;
 import cx.ring.model.SipCall;
 import cx.ring.utils.Log;
 import io.reactivex.Completable;
@@ -135,8 +136,9 @@
     public abstract void requestKeyFrame();
 
     public abstract void addVideoSurface(String id, Object holder);
+    public abstract void updateVideoSurfaceId(String currentId, String newId);
 
-    public abstract void addPreviewVideoSurface(Object holder, SipCall call);
+    public abstract void addPreviewVideoSurface(Object holder, Conference conference);
 
     public abstract void removeVideoSurface(String id);