diff --git a/ring-android/app/src/main/AndroidManifest.xml b/ring-android/app/src/main/AndroidManifest.xml
index ff781502e42bed815864633551550352b7ef831a..dcf7fff296041c6e8b19c93a2ce029b6c70f3cd3 100644
--- a/ring-android/app/src/main/AndroidManifest.xml
+++ b/ring-android/app/src/main/AndroidManifest.xml
@@ -111,7 +111,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
             android:configChanges="screenSize|screenLayout|smallestScreenSize"
             android:icon="@mipmap/ic_launcher"
             android:label="@string/app_name"
-            android:launchMode="singleTask"
             android:theme="@style/AppTheme.Navigation"
             android:windowSoftInputMode="adjustResize">
             <intent-filter>
@@ -217,6 +216,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
         <activity
             android:name=".client.CallActivity"
+            android:launchMode="singleTask"
             android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
             android:label="@string/app_name"
             android:resizeableActivity="true"
diff --git a/ring-android/app/src/main/java/cx/ring/client/CallActivity.kt b/ring-android/app/src/main/java/cx/ring/client/CallActivity.kt
index 0fa6f6c34fb3aaa2d70dd819579fe70297e877eb..5f043279c66ab5d420c8b41211c47de2692c0895 100644
--- a/ring-android/app/src/main/java/cx/ring/client/CallActivity.kt
+++ b/ring-android/app/src/main/java/cx/ring/client/CallActivity.kt
@@ -96,23 +96,15 @@ class CallActivity : AppCompatActivity() {
 
     private fun handleNewIntent(intent: Intent) {
         val action = intent.action
-        if (Intent.ACTION_CALL == action || ACTION_CALL == action) {
-            val audioOnly = intent.getBooleanExtra(CallFragment.KEY_AUDIO_ONLY, true)
+        val hasVideo = intent.getBooleanExtra(CallFragment.KEY_HAS_VIDEO, false)
+        if (Intent.ACTION_CALL == action) {
             val contactId = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER)
-            val callFragment = CallFragment.newInstance(
-                CallFragment.ACTION_PLACE_CALL,
-                fromIntent(intent),
-                contactId,
-                audioOnly
-            )
+            val callFragment = CallFragment.newInstance(action, fromIntent(intent), contactId, hasVideo)
             supportFragmentManager.beginTransaction()
                 .replace(R.id.main_call_layout, callFragment, CALL_FRAGMENT_TAG).commit()
         } else if (Intent.ACTION_VIEW == action || ACTION_CALL_ACCEPT == action) {
             val confId = intent.getStringExtra(NotificationService.KEY_CALL_ID)
-            val callFragment = CallFragment.newInstance(
-                if (Intent.ACTION_VIEW == action) CallFragment.ACTION_GET_CALL else ACTION_CALL_ACCEPT,
-                confId
-            )
+            val callFragment = CallFragment.newInstance(action, confId, hasVideo)
             supportFragmentManager.beginTransaction()
                 .replace(R.id.main_call_layout, callFragment, CALL_FRAGMENT_TAG).commit()
         }
@@ -201,7 +193,6 @@ class CallActivity : AppCompatActivity() {
         }
 
     companion object {
-        const val ACTION_CALL = BuildConfig.APPLICATION_ID + ".action.call"
         const val ACTION_CALL_ACCEPT = BuildConfig.APPLICATION_ID + ".action.CALL_ACCEPT"
         private const val CALL_FRAGMENT_TAG = "CALL_FRAGMENT_TAG"
 
diff --git a/ring-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.kt b/ring-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.kt
index 3b79991a9579011f8af0ddc961df1a274f8fcaae..7b05e2f2c052dc1cda4ad32a72d99b2dc68fc13e 100644
--- a/ring-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.kt
+++ b/ring-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.kt
@@ -400,7 +400,7 @@ class ContactDetailsActivity : AppCompatActivity() {
         binding = null
     }
 
-    private fun goToCallActivity(conversation: Conversation, contactUri: Uri, audioOnly: Boolean) {
+    private fun goToCallActivity(conversation: Conversation, contactUri: Uri, hasVideo: Boolean) {
         val conf = conversation.currentCall
         if (conf != null && conf.participants.isNotEmpty()
             && conf.participants[0].callStatus != Call.CallStatus.INACTIVE
@@ -413,7 +413,7 @@ class ContactDetailsActivity : AppCompatActivity() {
                 .setClass(applicationContext, CallActivity::class.java)
                 .putExtras(ConversationPath.toBundle(conversation))
                 .putExtra(Intent.EXTRA_PHONE_NUMBER, contactUri.uri)
-                .putExtra(CallFragment.KEY_AUDIO_ONLY, audioOnly)
+                .putExtra(CallFragment.KEY_HAS_VIDEO, hasVideo)
             startActivityForResult(intent, HomeActivity.REQUEST_CODE_CALL)
         }
     }
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.kt b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.kt
index 9b3b0587eaf4bff0eb324263edacee241062bb80..1c6bbfb7d162c9e2caeec645073162ec68ed7ec9 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.kt
+++ b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.kt
@@ -137,18 +137,24 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
 
     private enum class PreviewPosition { LEFT, RIGHT }
     private var previewPosition = PreviewPosition.RIGHT
-
     @Inject
     lateinit var mDeviceRuntimeService: DeviceRuntimeService
 
     private val mCompositeDisposable = CompositeDisposable()
+
     override fun initPresenter(presenter: CallPresenter) {
+        Log.w(TAG, "DEBUG fn initPresenter [CallFragment.kt] -> chose between prepareCall and initIncomingCall")
         val args = requireArguments()
+        presenter.wantVideo = args.getBoolean(KEY_HAS_VIDEO, false)
         args.getString(KEY_ACTION)?.let { action ->
-            if (action == ACTION_PLACE_CALL)
+            if (action == Intent.ACTION_CALL) {
+                Log.w(TAG, "DEBUG fn initPresenter [CallFragment.kt] -> requesting fn prepareCall(false) ")
                 prepareCall(false)
-            else if (action == ACTION_GET_CALL || action == CallActivity.ACTION_CALL_ACCEPT)
-                presenter.initIncomingCall(args.getString(KEY_CONF_ID)!!, action == ACTION_GET_CALL)
+            }
+            else if (action == Intent.ACTION_VIEW || action == CallActivity.ACTION_CALL_ACCEPT) {
+                Log.w(TAG, "DEBUG fn initPresenter [CallFragment.kt] -> requesting fn initIncomingCall( CONF_ID, GET_CALL)")
+                presenter.initIncomingCall(args.getString(KEY_CONF_ID)!!, action == Intent.ACTION_VIEW)
+            }
         }
     }
 
@@ -197,8 +203,9 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
 
     override fun onStart() {
         super.onStart()
+        Log.w(TAG, "DEBUG fn onStart [CallFragment.kt] -> on start, value hasVideo = ${presenter.wantVideo}, restartvideo : $restartVideo | restartPreview : $restartPreview")
         if (restartVideo && restartPreview) {
-            displayVideoSurface(true, !presenter.isPipMode)
+            displayVideoSurface(true, !presenter.isPipMode && presenter.wantVideo)
             restartVideo = false
             restartPreview = false
         } else if (restartVideo) {
@@ -649,6 +656,10 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
         if (requestCode != REQUEST_PERMISSION_INCOMING && requestCode != REQUEST_PERMISSION_OUTGOING) return
         var i = 0
         val n = permissions.size
+
+        val hasVideo = presenter.wantVideo
+        Log.w(TAG, "DEBUG fn onRequestPermissionsResult [CallFragment.kt] -> value hasVideo = $hasVideo")
+
         while (i < n) {
             val audioGranted = mDeviceRuntimeService.hasAudioPermission()
             val granted = grantResults[i] == PackageManager.PERMISSION_GRANTED
@@ -656,12 +667,12 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
                 Manifest.permission.CAMERA -> {
                     presenter.cameraPermissionChanged(granted)
                     if (audioGranted) {
-                        initializeCall(requestCode == REQUEST_PERMISSION_INCOMING)
+                        initializeCall(requestCode == REQUEST_PERMISSION_INCOMING, hasVideo)
                     }
                 }
                 Manifest.permission.RECORD_AUDIO -> {
                     presenter.audioPermissionChanged(granted)
-                    initializeCall(requestCode == REQUEST_PERMISSION_INCOMING)
+                    initializeCall(requestCode == REQUEST_PERMISSION_INCOMING, hasVideo)
                 }
             }
             i++
@@ -739,15 +750,18 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
         displayVideoSurface: Boolean,
         displayPreviewContainer: Boolean
     ) {
-        binding!!.videoSurface.visibility =
-            if (displayVideoSurface) View.VISIBLE else View.GONE
+        Log.w(TAG, "DEBUG fn displayVideoSurface [CallFragment.kt] -> changement des affichages videos  displayVideoSurface: $displayVideoSurface; displayPreviewContainer: $displayPreviewContainer")
+        binding!!.videoSurface.visibility = if (displayVideoSurface) View.VISIBLE else View.GONE
+
         if (isChoosePluginMode) {
+            Log.w(TAG, "DEBUG fn displayVideoSurface |1| inside => if (isChoosePluginMode) {displayPreviewContainer: $displayPreviewContainer}")
             binding!!.pluginPreviewSurface.visibility =
                 if (displayPreviewContainer) View.VISIBLE else View.GONE
             binding!!.pluginPreviewContainer.visibility =
                 if (displayPreviewContainer) View.VISIBLE else View.GONE
             binding!!.previewContainer.visibility = View.GONE
         } else {
+            Log.w(TAG, "DEBUG fn displayVideoSurface |2| inside => else { displayPreviewContainer : $displayPreviewContainer}")
             binding!!.pluginPreviewSurface.visibility = View.GONE
             binding!!.pluginPreviewContainer.visibility = View.GONE
             binding!!.previewContainer.visibility =
@@ -756,6 +770,7 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
         updateMenu()
     }
 
+    // todo Change function name, this name is misleading, this function concerns PIP preview
     override fun displayPreviewSurface(display: Boolean) {
         if (display) {
             binding!!.videoSurface.setZOrderOnTop(false)
@@ -783,8 +798,13 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
         imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY)
     }
 
-    override fun switchCameraIcon(isFront: Boolean) {
-        binding!!.callCameraFlipBtn.setImageResource(if (isFront) R.drawable.baseline_camera_front_24 else R.drawable.baseline_camera_rear_24)
+    override fun switchCameraIcon() {
+        //binding!!.callCameraFlipBtn.setImageResource(if (isFront) R.drawable.baseline_camera_front_24 else R.drawable.baseline_camera_rear_24)
+    }
+
+    fun switchCamera() {
+        presenter.switchOnOffCamera()
+        binding?.callCameraSwitchBtn?.setImageResource(if (binding?.callCameraSwitchBtn?.isChecked == true) R.drawable.baseline_videocam_off_24 else R.drawable.baseline_videocam_24)
     }
 
     override fun updateAudioState(state: AudioState) {
@@ -828,6 +848,9 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
                 }
                 ab.setDisplayShowTitleEnabled(true)
             }
+            val call = contacts[0]
+            val conversationUri = if (call.conversationId != null) Uri(Uri.SWARM_SCHEME, call.conversationId!!) else call.contact!!.conversationUri.blockingFirst()
+            activity.intent = Intent(Intent.ACTION_VIEW, ConversationPath.toUri(call.account!!, conversationUri))
         }
         if (hasProfileName) {
             binding!!.contactBubbleNumTxt.visibility = View.VISIBLE
@@ -918,8 +941,8 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
                     })
             }
             confAdapter!!.updateFromCalls(participantInfo)
-            if (binding!!.confControlGroup.adapter == null) binding!!.confControlGroup.adapter =
-                confAdapter
+            if (binding!!.confControlGroup.adapter == null)
+                binding!!.confControlGroup.adapter = confAdapter
         }
     }
 
@@ -944,17 +967,21 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
         }
     }
 
-    override fun updateCallStatus(callStatus: CallStatus) {
-        binding!!.callStatusTxt.setText(callStateToHumanState(callStatus))
+    override fun updateCallStatus(callState: CallStatus) {
+        binding!!.callStatusTxt.setText(callStateToHumanState(callState))
     }
 
     override fun initMenu(
-        isSpeakerOn: Boolean, displayFlip: Boolean, canDial: Boolean,
-        showPluginBtn: Boolean, onGoingCall: Boolean
+        isSpeakerOn: Boolean, hasMultipleCamera: Boolean, canDial: Boolean,
+        showPluginBtn: Boolean, onGoingCall: Boolean, hasActiveVideo: Boolean
     ) {
-        if (binding != null) {
-            binding!!.callCameraFlipBtn.visibility = if (displayFlip) View.VISIBLE else View.GONE
+        //
+        if (!hasActiveVideo) {
+            binding!!.callCameraSwitchBtn.isChecked = true
+            binding!!.callCameraSwitchBtn.setImageResource(R.drawable.baseline_videocam_off_24)
         }
+        binding!!.callCameraFlipBtn.visibility = if (hasMultipleCamera && !binding!!.callCameraSwitchBtn.isChecked) View.VISIBLE else View.GONE
+
         if (dialPadBtn != null) {
             dialPadBtn!!.isVisible = canDial
         }
@@ -969,6 +996,7 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
         binding?.apply {
             shapeRipple.stopRipple()
             callAcceptBtn.visibility = View.GONE
+            callAcceptAudioBtn.visibility = View.GONE
             callRefuseBtn.visibility = View.GONE
             callControlGroup.visibility = View.VISIBLE
             callHangupBtn.visibility = View.VISIBLE
@@ -980,10 +1008,11 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
         callActivity?.showSystemUI()
     }
 
-    override fun initIncomingCallDisplay() {
+    override fun initIncomingCallDisplay(hasVideo: Boolean) {
         Log.w(TAG, "initIncomingCallDisplay")
         binding?.apply {
-            callAcceptBtn.visibility = View.VISIBLE
+            if (hasVideo) callAcceptBtn.visibility = View.VISIBLE else callAcceptBtn.visibility = View.GONE
+            callAcceptAudioBtn.visibility = View.VISIBLE
             callRefuseBtn.visibility = View.VISIBLE
             callControlGroup.visibility = View.GONE
             callHangupBtn.visibility = View.GONE
@@ -1117,17 +1146,15 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
      */
     override fun prepareCall(isIncoming: Boolean) {
         val audioGranted = mDeviceRuntimeService.hasAudioPermission()
-        val audioOnly: Boolean
-        val permissionType: Int
-        if (isIncoming) {
-            audioOnly = presenter.isAudioOnly
-            permissionType = REQUEST_PERMISSION_INCOMING
-        } else {
-            val args = arguments
-            audioOnly = args != null && args.getBoolean(KEY_AUDIO_ONLY)
-            permissionType = REQUEST_PERMISSION_OUTGOING
-        }
-        if (!audioOnly) {
+        val hasVideo = presenter.wantVideo
+
+        Log.w(TAG, "DEBUG fn prepareCall -> define the permission based on hasVideo : $hasVideo and then call initializeCall($isIncoming, $hasVideo) ")
+        //Log.w(TAG, "fn prepareCall [CallFragment.kt] -> value of presenter.hasVideo() : $hasVideo")
+
+        val permissionType =
+            if (isIncoming) REQUEST_PERMISSION_INCOMING else REQUEST_PERMISSION_OUTGOING
+
+        if (hasVideo) {
             val videoGranted = mDeviceRuntimeService.hasVideoPermission()
             if ((!audioGranted || !videoGranted) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                 val perms = ArrayList<String>()
@@ -1139,13 +1166,15 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
                 }
                 requestPermissions(perms.toTypedArray(), permissionType)
             } else if (audioGranted && videoGranted) {
-                initializeCall(isIncoming)
+                Log.w(TAG, "DEBUG fn prepareCall [CallFragment.kt] -> calling initializeCall($isIncoming, $hasVideo) ")
+                initializeCall(isIncoming, hasVideo)
             }
         } else {
             if (!audioGranted && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                 requestPermissions(arrayOf(Manifest.permission.RECORD_AUDIO), permissionType)
             } else if (audioGranted) {
-                initializeCall(isIncoming)
+                Log.w(TAG, "DEBUG fn prepareCall [CallFragment.kt] -> calling initializeCall($isIncoming, $hasVideo) ")
+                initializeCall(isIncoming, hasVideo)
             }
         }
     }
@@ -1154,10 +1183,13 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
      * Starts a call. Takes into account whether call is incoming or outgoing.
      *
      * @param isIncoming true if call is incoming, false for outgoing
+     * @param hasVideo true if we already know that conversation has video
      */
-    private fun initializeCall(isIncoming: Boolean) {
+
+    private fun initializeCall(isIncoming: Boolean, hasVideo: Boolean) {
+        Log.w(TAG, "DEBUG fn initializeCall [CallFragment.kt] -> if isIncoming ( = $isIncoming ) == true : presenter.AcceptCall(hasVideo: $hasVideo) : presenter.initOutGoing(conversation.accountId,conversation.conversationUri,args.getString(Intent.EXTRA_PHONE_NUMBER), hasVideo: $hasVideo)")
         if (isIncoming) {
-            presenter.acceptCall()
+            presenter.acceptCall(hasVideo)
         } else {
             arguments?.let { args ->
                 val conversation = ConversationPath.fromBundle(args)!!
@@ -1165,7 +1197,7 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
                     conversation.accountId,
                     conversation.conversationUri,
                     args.getString(Intent.EXTRA_PHONE_NUMBER),
-                    args.getBoolean(KEY_AUDIO_ONLY)
+                    hasVideo
                 )
             }
         }
@@ -1182,8 +1214,10 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
         }
     }
 
+    //todo if videomode, should mute/unmute audio output, if audio only, should switch between speaker options
     fun speakerClicked() {
         presenter.speakerClick(binding!!.callSpeakerBtn.isChecked)
+        //binding!!.callSpeakerBtn.setImageResource(if (binding!!.callSpeakerBtn.isChecked) R.drawable.baseline_sound_on_24 else R.drawable.baseline_sound_off_24)
     }
 
     private fun startScreenShare(mediaProjection: MediaProjection?) {
@@ -1227,7 +1261,17 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
         presenter.refuseCall()
     }
 
+    fun acceptAudioClicked() {
+        Log.w(TAG, "DEBUG fn acceptClicked() [CallFragment.kt] -> hasVideo current value is : $ (${presenter.wantVideo})")
+        presenter.wantVideo = false
+        Log.w(TAG, "DEBUG fn acceptClicked() [CallFragment.kt] -> hasVideo new value is : $ (${presenter.wantVideo})")
+        prepareCall(true)
+    }
+
     fun acceptClicked() {
+        Log.w(TAG, "DEBUG fn acceptClicked() [CallFragment.kt] -> hasVideo current value is : $ (${presenter.wantVideo})")
+        presenter.wantVideo = true
+        Log.w(TAG, "DEBUG fn acceptClicked() [CallFragment.kt] -> hasVideo new value is : $ (${presenter.wantVideo})")
         prepareCall(true)
     }
 
@@ -1370,7 +1414,7 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
         }
 
         //change preview image
-        displayVideoSurface(true, true)
+        displayVideoSurface(true, presenter.wantVideo)
     }
 
     /**
@@ -1425,32 +1469,32 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView,
     companion object {
         val TAG = CallFragment::class.simpleName!!
         const val ACTION_PLACE_CALL = "PLACE_CALL"
-        const val ACTION_GET_CALL = "GET_CALL"
         const val KEY_ACTION = "action"
         const val KEY_CONF_ID = "confId"
-        const val KEY_AUDIO_ONLY = "AUDIO_ONLY"
+        const val KEY_HAS_VIDEO = "HAS_VIDEO"
         private const val REQUEST_CODE_ADD_PARTICIPANT = 6
         private const val REQUEST_PERMISSION_INCOMING = 1003
         private const val REQUEST_PERMISSION_OUTGOING = 1004
         private const val REQUEST_CODE_SCREEN_SHARE = 7
 
-        fun newInstance(action: String, path: ConversationPath?, contactId: String?, audioOnly: Boolean): CallFragment {
+        fun newInstance(action: String, path: ConversationPath?, contactId: String?, hasVideo: Boolean): CallFragment {
             val bundle = Bundle()
             bundle.putString(KEY_ACTION, action)
             path?.toBundle(bundle)
             bundle.putString(Intent.EXTRA_PHONE_NUMBER, contactId)
-            bundle.putBoolean(KEY_AUDIO_ONLY, audioOnly)
+            bundle.putBoolean(KEY_HAS_VIDEO, hasVideo)
             val countDownFragment = CallFragment()
             countDownFragment.arguments = bundle
             return countDownFragment
         }
 
-        fun newInstance(action: String, confId: String?): CallFragment {
-            val bundle = Bundle()
-            bundle.putString(KEY_ACTION, action)
-            bundle.putString(KEY_CONF_ID, confId)
+        fun newInstance(action: String, confId: String?, hasVideo: Boolean): CallFragment {
             val countDownFragment = CallFragment()
-            countDownFragment.arguments = bundle
+            countDownFragment.arguments = Bundle().apply {
+                putString(KEY_ACTION, action)
+                putString(KEY_CONF_ID, confId)
+                putBoolean(KEY_HAS_VIDEO, hasVideo)
+            }
             return countDownFragment
         }
 
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.kt b/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.kt
index 349c2ff1d5ff5916f8aed6639c72d6e9df5fd7ba..4a80a29e09378d8f13c8ab352370cab3e82e2208 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.kt
+++ b/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.kt
@@ -787,10 +787,10 @@ class ConversationFragment : BaseSupportFragment<ConversationPresenter, Conversa
             startActivity(Intent(activity, HomeActivity::class.java))
             return true
         } else if (itemId == R.id.conv_action_audiocall) {
-            presenter.goToCall(true)
+            presenter.goToCall(false)
             return true
         } else if (itemId == R.id.conv_action_videocall) {
-            presenter.goToCall(false)
+            presenter.goToCall(true)
             return true
         } else if (itemId == R.id.conv_contact_details) {
             presenter.openContact()
@@ -915,11 +915,6 @@ class ConversationFragment : BaseSupportFragment<ConversationPresenter, Conversa
         startActivityForResult(ActionHelper.getAddNumberIntentForContact(contact), REQ_ADD_CONTACT)
     }
 
-    override fun goToCallActivity(conferenceId: String) {
-        startActivity(Intent(Intent.ACTION_VIEW)
-                .setClass(requireContext().applicationContext, CallActivity::class.java)
-                .putExtra(NotificationService.KEY_CALL_ID, conferenceId))
-    }
 
     override fun goToContactActivity(accountId: String, uri: net.jami.model.Uri) {
         val toolbar: Toolbar = requireActivity().findViewById(R.id.main_toolbar)
@@ -930,17 +925,21 @@ class ConversationFragment : BaseSupportFragment<ConversationPresenter, Conversa
                 .toBundle())
     }
 
-    override fun goToCallActivityWithResult(
-        accountId: String,
-        conversationUri: net.jami.model.Uri,
-        contactUri: net.jami.model.Uri,
-        audioOnly: Boolean
-    ) {
+    override fun goToCallActivity(conferenceId: String, withCamera: Boolean) {
+        Log.w(TAG, "DEBUG fn goToCallActivity")
+        startActivity(Intent(Intent.ACTION_VIEW)
+            .setClass(requireContext().applicationContext, CallActivity::class.java)
+            .putExtra(NotificationService.KEY_CALL_ID, conferenceId)
+        )
+    }
+
+    override fun goToCallActivityWithResult(accountId: String, conversationUri: net.jami.model.Uri, contactUri: net.jami.model.Uri, withCamera: Boolean) {
+        Log.w(TAG, "DEBUG fn goToCallActivityWithResult || hasVideo : $withCamera")
         val intent = Intent(Intent.ACTION_CALL)
             .setClass(requireContext(), CallActivity::class.java)
             .putExtras(ConversationPath.toBundle(accountId, conversationUri))
             .putExtra(Intent.EXTRA_PHONE_NUMBER, contactUri.uri)
-            .putExtra(CallFragment.KEY_AUDIO_ONLY, audioOnly)
+            .putExtra(CallFragment.KEY_HAS_VIDEO, withCamera)
         startActivityForResult(intent, HomeActivity.REQUEST_CODE_CALL)
     }
 
diff --git a/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.kt b/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.kt
index 5909959ad9d1b7205352eeb7bc13586f0bf9aa2b..f517b053ab9005c98c57c51b33d8fe0175a86cea 100644
--- a/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.kt
+++ b/ring-android/app/src/main/java/cx/ring/fragments/SmartListFragment.kt
@@ -251,7 +251,7 @@ class SmartListFragment : BaseSupportFragment<SmartListPresenter, SmartListView>
             .setTitle(R.string.choose_number)
             .setItems(numbers) { _: DialogInterface?, which: Int ->
                 val selected = numbers[which]
-                val intent = Intent(CallActivity.ACTION_CALL)
+                val intent = Intent(Intent.ACTION_CALL)
                     .setClass(context, CallActivity::class.java)
                     .setData(android.net.Uri.parse(selected.toString()))
                 startActivityForResult(intent, HomeActivity.REQUEST_CODE_CALL)
@@ -355,10 +355,10 @@ class SmartListFragment : BaseSupportFragment<SmartListPresenter, SmartListView>
     }
 
     override fun goToCallActivity(accountId: String, conversationUri: Uri, contactId: String) {
-        val intent = Intent(CallActivity.ACTION_CALL)
+        val intent = Intent(Intent.ACTION_CALL)
             .setClass(requireContext(), CallActivity::class.java)
             .putExtras(ConversationPath.toBundle(accountId, conversationUri))
-            .putExtra(CallFragment.KEY_AUDIO_ONLY, false)
+            .putExtra(CallFragment.KEY_HAS_VIDEO, true)
             .putExtra(Intent.EXTRA_PHONE_NUMBER, contactId)
         startActivityForResult(intent, HomeActivity.REQUEST_CODE_CALL)
     }
diff --git a/ring-android/app/src/main/java/cx/ring/service/DRingService.kt b/ring-android/app/src/main/java/cx/ring/service/DRingService.kt
index d14b38df81bacf0ed007276090bc4aaece53cada..0647f491e3ef68523e737d7850025f4bdba1cb11 100644
--- a/ring-android/app/src/main/java/cx/ring/service/DRingService.kt
+++ b/ring-android/app/src/main/java/cx/ring/service/DRingService.kt
@@ -243,6 +243,12 @@ class DRingService : Service() {
             return
         }
         when (action) {
+            ACTION_CALL_ACCEPT_AUDIO -> {
+                startActivity(Intent(ACTION_CALL_ACCEPT)
+                    .putExtras(extras)
+                    .setClass(applicationContext, CallActivity::class.java)
+                    .setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK))
+            }
             ACTION_CALL_ACCEPT -> {
                 startActivity(Intent(ACTION_CALL_ACCEPT)
                         .putExtras(extras)
@@ -337,6 +343,7 @@ class DRingService : Service() {
         const val ACTION_TRUST_REQUEST_ACCEPT = BuildConfig.APPLICATION_ID + ".action.TRUST_REQUEST_ACCEPT"
         const val ACTION_TRUST_REQUEST_REFUSE = BuildConfig.APPLICATION_ID + ".action.TRUST_REQUEST_REFUSE"
         const val ACTION_TRUST_REQUEST_BLOCK = BuildConfig.APPLICATION_ID + ".action.TRUST_REQUEST_BLOCK"
+        const val ACTION_CALL_ACCEPT_AUDIO = BuildConfig.APPLICATION_ID + ".action.CALL_ACCEPT_AUDIO"
         const val ACTION_CALL_ACCEPT = BuildConfig.APPLICATION_ID + ".action.CALL_ACCEPT"
         const val ACTION_CALL_HOLD_ACCEPT = BuildConfig.APPLICATION_ID + ".action.CALL_HOLD_ACCEPT"
         const val ACTION_CALL_END_ACCEPT = BuildConfig.APPLICATION_ID + ".action.CALL_END_ACCEPT"
diff --git a/ring-android/app/src/main/java/cx/ring/services/HardwareServiceImpl.kt b/ring-android/app/src/main/java/cx/ring/services/HardwareServiceImpl.kt
index 3e618299b50975c2b57a4d7f7ec75823948d779f..77b0d779e1344a8b964d1db4e4c29a60e3372e43 100644
--- a/ring-android/app/src/main/java/cx/ring/services/HardwareServiceImpl.kt
+++ b/ring-android/app/src/main/java/cx/ring/services/HardwareServiceImpl.kt
@@ -539,7 +539,7 @@ class HardwareServiceImpl(
         val surfaceHolder = WeakReference(holder)
         videoSurfaces[id] = surfaceHolder
         if (shm != null && shm.window == 0L) {
-            shm.window = startVideo(shm.id, surfaceHolder.get()!!.surface, shm.w, shm.h)
+            shm.window = startVideo(shm.id, holder.surface, shm.w, shm.h)
         }
         if (shm == null || shm.window == 0L) {
             Log.i(TAG, "DJamiService.addVideoSurface() no window !")
diff --git a/ring-android/app/src/main/java/cx/ring/services/NotificationServiceImpl.kt b/ring-android/app/src/main/java/cx/ring/services/NotificationServiceImpl.kt
index 9d4b9079d40cec01b7157cbe276e39e62f06a9af..044f6035d4c318bbd21afae384fbde2b01fb265c 100644
--- a/ring-android/app/src/main/java/cx/ring/services/NotificationServiceImpl.kt
+++ b/ring-android/app/src/main/java/cx/ring/services/NotificationServiceImpl.kt
@@ -50,6 +50,7 @@ import cx.ring.client.CallActivity
 import cx.ring.client.ConversationActivity
 import cx.ring.client.HomeActivity
 import cx.ring.contactrequests.ContactRequestsFragment
+import cx.ring.fragments.CallFragment
 import cx.ring.fragments.ConversationFragment
 import cx.ring.service.CallNotificationService
 import cx.ring.service.DRingService
@@ -79,7 +80,6 @@ class NotificationServiceImpl(
     private val currentCalls = LinkedHashMap<String, Conference>()
     private val callNotifications = ConcurrentHashMap<Int, Notification>()
     private val dataTransferNotifications = ConcurrentHashMap<Int, Notification>()
-
     @SuppressLint("CheckResult")
     fun initHelper() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -141,21 +141,42 @@ class NotificationServiceImpl(
                     .setSound(null)
                     .setVibrate(null)
                     .setFullScreenIntent(viewIntent, true)
-                    .addAction(R.drawable.baseline_call_end_24,
-                        mContext.getText(R.string.action_call_decline),
-                        PendingIntent.getService(mContext, random.nextInt(),
-                            Intent(DRingService.ACTION_CALL_REFUSE)
+                    .addAction(
+                        R.drawable.baseline_call_end_24, mContext.getText(R.string.action_call_decline),
+                        PendingIntent.getService(mContext, random.nextInt(), Intent(DRingService.ACTION_CALL_REFUSE)
                                 .setClass(mContext, DRingService::class.java)
-                                .putExtra(NotificationService.KEY_CALL_ID, call.daemonIdString),
-                            PendingIntent.FLAG_ONE_SHOT))
-                    .addAction(R.drawable.baseline_call_24,
-                        mContext.getText(if (ongoingCallId == null) R.string.action_call_accept else R.string.action_call_end_accept),
-                        PendingIntent.getService(mContext, random.nextInt(),
-                            Intent(if (ongoingCallId == null) DRingService.ACTION_CALL_ACCEPT else DRingService.ACTION_CALL_END_ACCEPT)
+                                .putExtra(NotificationService.KEY_CALL_ID, call.daemonIdString), PendingIntent.FLAG_ONE_SHOT
+                        )
+                    )
+                Log.w(TAG, "DEBUG fn buildCallNotification [NotificationServiceImpl.kt] -> conference.hasvideo = ${conference.hasVideo()} ")
+
+                if (conference.hasVideo()){
+                        messageNotificationBuilder
+                            .addAction(R.id.btnAcceptAudio, if (ongoingCallId == null) mContext.getText(R.string.action_call_accept_audio) else mContext.getText(R.string.action_call_end_accept),
+                                PendingIntent.getService(mContext, random.nextInt(), Intent(if (ongoingCallId == null) DRingService.ACTION_CALL_ACCEPT else DRingService.ACTION_CALL_END_ACCEPT)
+                                    .setClass(mContext, DRingService::class.java)
+                                    .putExtra(NotificationService.KEY_END_ID, ongoingCallId)
+                                    .putExtra(NotificationService.KEY_CALL_ID, call.daemonIdString)
+                                    .putExtra(CallFragment.KEY_HAS_VIDEO, false), PendingIntent.FLAG_ONE_SHOT)
+                            )
+                            .addAction(R.id.btnAcceptVideo, if (ongoingCallId == null) mContext.getText(R.string.action_call_accept_video) else mContext.getText(R.string.action_call_end_accept),
+                                PendingIntent.getService(mContext, random.nextInt(), Intent(if (ongoingCallId == null) DRingService.ACTION_CALL_ACCEPT else DRingService.ACTION_CALL_END_ACCEPT)
+                                    .setClass(mContext, DRingService::class.java)
+                                    .putExtra(NotificationService.KEY_END_ID, ongoingCallId)
+                                    .putExtra(NotificationService.KEY_CALL_ID, call.daemonIdString)
+                                    .putExtra(CallFragment.KEY_HAS_VIDEO, true), PendingIntent.FLAG_ONE_SHOT)
+                            )
+
+                    } else {
+                        messageNotificationBuilder.addAction(
+                            R.id.btnAcceptAudio, if (ongoingCallId == null) mContext.getText(R.string.action_call_accept_audio) else mContext.getText(R.string.action_call_end_accept),
+                            PendingIntent.getService(mContext, random.nextInt(), Intent(if (ongoingCallId == null) DRingService.ACTION_CALL_ACCEPT else DRingService.ACTION_CALL_END_ACCEPT)
                                 .setClass(mContext, DRingService::class.java)
                                 .putExtra(NotificationService.KEY_END_ID, ongoingCallId)
-                                .putExtra(NotificationService.KEY_CALL_ID, call.daemonIdString),
-                            PendingIntent.FLAG_ONE_SHOT))
+                                .putExtra(NotificationService.KEY_CALL_ID, call.daemonIdString)
+                                .putExtra(CallFragment.KEY_HAS_VIDEO, false), PendingIntent.FLAG_ONE_SHOT)
+                        )
+                    }
                 if (ongoingCallId != null) {
                     messageNotificationBuilder.addAction(R.drawable.baseline_call_24,
                         mContext.getText(R.string.action_call_hold_accept),
@@ -555,6 +576,7 @@ class NotificationServiceImpl(
         }
     }
 
+    @SuppressLint("RestrictedApi")
     override fun showFileTransferNotification(conversation: Conversation, info: DataTransfer) {
         val event = info.status ?: return
         if (event == InteractionStatus.FILE_AVAILABLE)
diff --git a/ring-android/app/src/main/java/cx/ring/tv/call/TVCallActivity.kt b/ring-android/app/src/main/java/cx/ring/tv/call/TVCallActivity.kt
index 9c011f9c8a6aea2f27a65bad352bbde1e15db1a5..17a94b98afb9f36ae5b3d47d531bc2f060037234 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/call/TVCallActivity.kt
+++ b/ring-android/app/src/main/java/cx/ring/tv/call/TVCallActivity.kt
@@ -59,7 +59,7 @@ class TVCallActivity : FragmentActivity() {
         if (path != null) {
             Log.d(TAG, "onCreate: outgoing call $path ${intent.action}")
             callFragment = TVCallFragment.newInstance(intent.action!!, path.accountId, path.conversationId,
-                intent.extras!!.getString(Intent.EXTRA_PHONE_NUMBER, path.conversationId), false)
+                intent.extras!!.getString(Intent.EXTRA_PHONE_NUMBER, path.conversationId),  true)
             fragmentTransaction.replace(R.id.main_call_layout, callFragment!!, CALL_FRAGMENT_TAG)
                 .commit()
         } else {
diff --git a/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.kt b/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.kt
index 7943c454eb9b7ffe8a9153824b93c22f0bfb761e..0e027af9651f7c4a86cacd3426b7ffe821bd3384 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.kt
+++ b/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.kt
@@ -300,7 +300,7 @@ class TVCallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView
     }
 
     override fun displayDialPadKeyboard() {}
-    override fun switchCameraIcon(isFront: Boolean) {}
+    override fun switchCameraIcon() {}
     override fun updateAudioState(state: AudioState) {}
     override fun updateMenu() {}
     override fun updateTime(duration: Long) {
@@ -378,7 +378,7 @@ class TVCallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView
 
     override fun initMenu(
         isSpeakerOn: Boolean, displayFlip: Boolean, canDial: Boolean,
-        showPluginBtn: Boolean, onGoingCall: Boolean
+        showPluginBtn: Boolean, onGoingCall: Boolean, hasActiveVideo: Boolean
     ) {
     }
 
@@ -395,7 +395,8 @@ class TVCallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView
         handleVisibilityTimer()
     }
 
-    override fun initIncomingCallDisplay() {
+
+    override fun initIncomingCallDisplay(hasVideo: Boolean) {
         mSession!!.isActive = true
         binding?.apply {
             callAcceptBtn.visibility = View.VISIBLE
@@ -482,16 +483,16 @@ class TVCallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView
      */
     override fun prepareCall(isIncoming: Boolean) {
         val audioGranted = mDeviceRuntimeService.hasAudioPermission()
-        val audioOnly: Boolean
+        val hasVideo: Boolean
         val permissionType: Int
         if (isIncoming) {
-            audioOnly = presenter.isAudioOnly
+            hasVideo = presenter.wantVideo
             permissionType = REQUEST_PERMISSION_INCOMING
         } else {
-            audioOnly = requireArguments().getBoolean(CallFragment.KEY_AUDIO_ONLY)
+            hasVideo = requireArguments().getBoolean(CallFragment.KEY_HAS_VIDEO)
             permissionType = REQUEST_PERMISSION_OUTGOING
         }
-        if (!audioOnly) {
+        if (!hasVideo) {
             val videoGranted = mDeviceRuntimeService.hasVideoPermission()
             if ((!audioGranted || !videoGranted) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                 val perms = ArrayList<String>()
@@ -520,9 +521,10 @@ class TVCallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView
      * @param isIncoming true if call is incoming, false for outgoing
      */
     private fun initializeCall(isIncoming: Boolean) {
-        Log.w(TAG, "initializeCall $isIncoming")
+        val hasVideo : Boolean = presenter.wantVideo
+        Log.w(TAG, "DEBUG fn initializeCall() -> isIncoming = $isIncoming and hasVideo = $hasVideo")
         if (isIncoming) {
-            presenter.acceptCall()
+            presenter.acceptCall(hasVideo)
         } else {
             arguments?.let { args ->
                 Log.w(TAG, "initializeCall presenter.initOutGoing")
@@ -531,7 +533,7 @@ class TVCallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView
                     conversation.accountId,
                     conversation.conversationUri,
                     args.getString(Intent.EXTRA_PHONE_NUMBER),
-                    args.getBoolean(CallFragment.KEY_AUDIO_ONLY)
+                    args.getBoolean(CallFragment.KEY_HAS_VIDEO)
                 )
             }
         }
@@ -651,6 +653,7 @@ class TVCallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView
     }
 
     fun acceptClicked() {
+        presenter.wantVideo = true
         prepareCall(true)
     }
 
@@ -717,12 +720,12 @@ class TVCallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView
         private const val REQUEST_PERMISSION_INCOMING = 1003
         private const val REQUEST_PERMISSION_OUTGOING = 1004
 
-        fun newInstance(action: String, accountId: String, conversationId: String, contactUri: String, audioOnly: Boolean): TVCallFragment {
+        fun newInstance(action: String, accountId: String, conversationId: String, contactUri: String, hasVideo: Boolean): TVCallFragment {
             return TVCallFragment().apply { arguments = Bundle().apply {
                 putString(CallFragment.KEY_ACTION, action)
                 putAll(ConversationPath.toBundle(accountId, conversationId))
                 putString(Intent.EXTRA_PHONE_NUMBER, contactUri)
-                putBoolean(CallFragment.KEY_AUDIO_ONLY, audioOnly)
+                putBoolean(CallFragment.KEY_HAS_VIDEO, hasVideo)
             }}
         }
 
diff --git a/ring-android/app/src/main/java/cx/ring/tv/contact/TVContactFragment.kt b/ring-android/app/src/main/java/cx/ring/tv/contact/TVContactFragment.kt
index fd71d5fa7562d1fbb7295b1fa4c2f79e6d84b00b..9fce6330f4d0bf41cd880053a24aaad2a47b04e6 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/contact/TVContactFragment.kt
+++ b/ring-android/app/src/main/java/cx/ring/tv/contact/TVContactFragment.kt
@@ -27,6 +27,7 @@ import android.view.View
 import androidx.core.content.ContextCompat
 import androidx.leanback.widget.*
 import cx.ring.R
+import cx.ring.fragments.CallFragment
 import cx.ring.tv.call.TVCallActivity
 import cx.ring.tv.contact.more.TVContactMoreActivity
 import cx.ring.tv.contact.more.TVContactMoreFragment
@@ -144,7 +145,8 @@ class TVContactFragment : BaseDetailFragment<TVContactPresenter>(), TVContactVie
         startActivity(Intent(Intent.ACTION_CALL)
             .setClass(requireContext(), TVCallActivity::class.java)
             .putExtras(ConversationPath.toBundle(accountId, conversationUri))
-            .putExtra(Intent.EXTRA_PHONE_NUMBER, uri.uri))
+            .putExtra(Intent.EXTRA_PHONE_NUMBER, uri.uri)
+            .putExtra(CallFragment.KEY_HAS_VIDEO, true))
     }
 
     override fun goToCallActivity(id: String) {
diff --git a/ring-android/app/src/main/java/cx/ring/tv/conversation/TvConversationFragment.kt b/ring-android/app/src/main/java/cx/ring/tv/conversation/TvConversationFragment.kt
index d8796797a980f6c0b0b171ba3cb4588a49d042f4..c51aa5f316d127b1255312bfa90a484caef82994 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/conversation/TvConversationFragment.kt
+++ b/ring-android/app/src/main/java/cx/ring/tv/conversation/TvConversationFragment.kt
@@ -631,7 +631,7 @@ class TvConversationFragment : BaseSupportFragment<ConversationPresenter, Conver
     override fun clearMsgEdit() {}
     override fun goToHome() {}
     override fun goToAddContact(contact: Contact) {}
-    override fun goToCallActivity(conferenceId: String) {}
+    override fun goToCallActivity(conferenceId: String, hasVideo: Boolean) {}
     override fun goToCallActivityWithResult(
         accountId: String,
         conversationUri: net.jami.model.Uri,
diff --git a/ring-android/app/src/main/java/cx/ring/tv/main/MainFragment.kt b/ring-android/app/src/main/java/cx/ring/tv/main/MainFragment.kt
index e09dcfffb67404bb9c884de7ed24d3830947c8eb..6e794627d016bb3800effc7155c0cbb3ea451934 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/main/MainFragment.kt
+++ b/ring-android/app/src/main/java/cx/ring/tv/main/MainFragment.kt
@@ -62,6 +62,7 @@ import io.reactivex.rxjava3.core.Single
 import io.reactivex.rxjava3.disposables.CompositeDisposable
 import io.reactivex.rxjava3.schedulers.Schedulers
 import net.jami.model.Account
+import net.jami.model.Profile
 import net.jami.navigation.HomeNavigationViewModel
 import net.jami.smartlist.SmartListViewModel
 import net.jami.utils.QRCodeUtils
@@ -221,34 +222,28 @@ class MainFragment : BaseBrowseFragment<MainPresenter>(), MainView {
     }
 
     override fun displayAccountInfo(viewModel: HomeNavigationViewModel) {
-        updateModel(viewModel.account)
+        updateModel(viewModel.account, viewModel.profile)
     }
 
-    override fun updateModel(account: Account) {
+    private fun updateModel(account: Account, profile: Profile) {
         val context = requireContext()
         val address = account.displayUsername
-        mDisposable.clear()
-        mDisposable.add(VCardServiceImpl.loadProfile(context, account)
-            .observeOn(AndroidSchedulers.mainThread())
-            .doOnNext { profile ->
-                val name = profile.displayName
-                if (name != null && name.isNotEmpty()) {
-                    mTitleView?.setAlias(name)
-                    title = address ?: ""
-                } else {
-                    mTitleView?.setAlias(address)
-                }
-            }
-            .map { p -> AvatarDrawable.build(context, account, p, true) }
-            .subscribe { a ->
-                mTitleView?.apply {
-                    settingsButton.visibility = View.VISIBLE
-                    logoView.visibility = View.VISIBLE
-                    logoView.setImageDrawable(a)
-                }
-            })
-        qrCard?.setDrawable(prepareAccountQr(context, account.uri)!!)
-        accountSettingsRow?.adapter!!.notifyItemRangeChanged(QR_ITEM_POSITION, 1)
+        val name = profile.displayName
+        if (name != null && name.isNotEmpty()) {
+            mTitleView?.setAlias(name)
+            title = address ?: ""
+        } else {
+            mTitleView?.setAlias(address)
+        }
+        mTitleView?.apply {
+            settingsButton.visibility = View.VISIBLE
+            logoView.visibility = View.VISIBLE
+            logoView.setImageDrawable(AvatarDrawable.build(context, account, profile, true))
+        }
+        prepareAccountQr(context, account.uri)?.let { qr ->
+            qrCard?.setDrawable(qr)
+            accountSettingsRow?.adapter?.notifyItemRangeChanged(QR_ITEM_POSITION, 1)
+        }
     }
 
     override fun showExportDialog(pAccountID: String, hasPassword: Boolean) {
diff --git a/ring-android/app/src/main/java/cx/ring/tv/main/MainPresenter.kt b/ring-android/app/src/main/java/cx/ring/tv/main/MainPresenter.kt
index 84037c0f3cc033daa1e59200495e81cbec469fcc..8684ce5ba3d06a20e85c329d174cefebbdc9b947 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/main/MainPresenter.kt
+++ b/ring-android/app/src/main/java/cx/ring/tv/main/MainPresenter.kt
@@ -78,11 +78,6 @@ class MainPresenter @Inject constructor(
             .observeOn(mUiScheduler)
             .subscribe({ accountProfile -> view?.displayAccountInfo(HomeNavigationViewModel(accountProfile.first, accountProfile.second)) })
             { e: Throwable -> Log.d(TAG, "reloadAccountInfos getProfileAccountList onError", e) })
-
-        mCompositeDisposable.add(mAccountService.observableAccounts
-            .observeOn(mUiScheduler)
-            .subscribe({ account: Account -> view?.updateModel(account) })
-            { e: Throwable -> Log.e(TAG, "Error loading account list !", e) })
     }
 
     fun onExportClicked() {
diff --git a/ring-android/app/src/main/java/cx/ring/tv/main/MainView.kt b/ring-android/app/src/main/java/cx/ring/tv/main/MainView.kt
index 96e3f0025d2ee2868661a112ea74b01ae5732fe4..e5a1a9abf05fec15542e2e13a630f93059db7777 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/main/MainView.kt
+++ b/ring-android/app/src/main/java/cx/ring/tv/main/MainView.kt
@@ -30,7 +30,6 @@ interface MainView {
     fun showContactRequests(contactRequests: List<SmartListViewModel>)
     fun callContact(accountID: String, ringID: String)
     fun displayAccountInfo(viewModel: HomeNavigationViewModel)
-    fun updateModel(account: Account)
     fun showExportDialog(pAccountID: String, hasPassword: Boolean)
     fun showProfileEditing()
     fun showAccountShare()
diff --git a/ring-android/app/src/main/java/cx/ring/tv/search/ContactSearchFragment.kt b/ring-android/app/src/main/java/cx/ring/tv/search/ContactSearchFragment.kt
index fe5843efc1ba9871304cdf3423150b3bf0335eae..6b092fc81e01a556ba2a06aeff5b666aeb2f0dda 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/search/ContactSearchFragment.kt
+++ b/ring-android/app/src/main/java/cx/ring/tv/search/ContactSearchFragment.kt
@@ -109,7 +109,7 @@ class ContactSearchFragment : BaseSearchFragment<ContactSearchPresenter>(),
     }
 
     override fun startCall(accountID: String, number: String) {
-        val intent = Intent(CallActivity.ACTION_CALL, toUri(accountID, number), activity, TVCallActivity::class.java)
+        val intent = Intent(Intent.ACTION_CALL, toUri(accountID, number), activity, TVCallActivity::class.java)
         intent.putExtra(Intent.EXTRA_PHONE_NUMBER, number)
         startActivity(intent)
         activity?.finish()
diff --git a/ring-android/app/src/main/java/cx/ring/tv/views/CustomTitleView.kt b/ring-android/app/src/main/java/cx/ring/tv/views/CustomTitleView.kt
index ad365f7d6218d9f19811fbb55bca54e2dcd33f87..1a37021fd383a77a2ca0d2855ad0bfdeb664cdd2 100644
--- a/ring-android/app/src/main/java/cx/ring/tv/views/CustomTitleView.kt
+++ b/ring-android/app/src/main/java/cx/ring/tv/views/CustomTitleView.kt
@@ -57,11 +57,11 @@ class CustomTitleView @JvmOverloads constructor(context: Context?, attrs: Attrib
             return mSearchOrbView
         }
 
-        override fun setTitle(titleText: CharSequence) {
+        override fun setTitle(titleText: CharSequence?) {
             this@CustomTitleView.setTitle(titleText)
         }
 
-        override fun setBadgeDrawable(drawable: Drawable) {
+        override fun setBadgeDrawable(drawable: Drawable?) {
             //NOOP
         }
 
diff --git a/ring-android/app/src/main/java/cx/ring/utils/ConversationPath.kt b/ring-android/app/src/main/java/cx/ring/utils/ConversationPath.kt
index 24619fcbd1fbafd611ca12ba5579b9fddb1cccee..9007b9b4c6493b87b3b07eeffe264595e6f73454 100644
--- a/ring-android/app/src/main/java/cx/ring/utils/ConversationPath.kt
+++ b/ring-android/app/src/main/java/cx/ring/utils/ConversationPath.kt
@@ -96,7 +96,7 @@ class ConversationPath {
                 .build()
         }
 
-        fun toUri(accountId: String?, conversationUri: Uri): android.net.Uri {
+        fun toUri(accountId: String, conversationUri: Uri): android.net.Uri {
             return ContentUriHandler.CONVERSATION_CONTENT_URI.buildUpon()
                 .appendEncodedPath(accountId)
                 .appendEncodedPath(conversationUri.uri)
@@ -109,9 +109,9 @@ class ConversationPath {
 
         fun toUri(interaction: Interaction): android.net.Uri {
             return if (interaction.conversation is Conversation)
-                toUri(interaction.account, (interaction.conversation as Conversation).uri)
+                toUri(interaction.account!!, (interaction.conversation as Conversation).uri)
             else
-                toUri(interaction.account, Uri.fromString(interaction.conversation!!.participant!!))
+                toUri(interaction.account!!, Uri.fromString(interaction.conversation!!.participant!!))
         }
 
         fun toBundle(accountId: String, uri: String): Bundle {
diff --git a/ring-android/app/src/main/res/drawable/background_call_menu.xml b/ring-android/app/src/main/res/drawable/background_call_menu.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3d9d6abad22d07f4a9ecdce785f53b551165c59c
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable/background_call_menu.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#99323232"/>
+        <padding
+        android:left="5dp"
+        android:top="5dp"
+        android:right="5dp"
+        android:bottom="5dp"/>
+    <corners
+        android:topLeftRadius="20dp"
+        android:topRightRadius="20dp"/>
+</shape>
+
diff --git a/ring-android/app/src/main/res/drawable/baseline_call_24_primary.xml b/ring-android/app/src/main/res/drawable/baseline_call_24_primary.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9bf1b3d78c6e447b4b892ab5252c4bd09ceb32b9
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable/baseline_call_24_primary.xml
@@ -0,0 +1,11 @@
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0"
+    android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="@color/colorPrimary"
+        android:pathData="M20.01,15.38c-1.23,0 -2.42,-0.2 -3.53,-0.56 -0.35,-0.12 -0.74,-0.03 -1.01,0.24l-1.57,1.97c-2.83,-1.35 -5.48,-3.9 -6.89,-6.83l1.95,-1.66c0.27,-0.28 0.35,-0.67 0.24,-1.02 -0.37,-1.11 -0.56,-2.3 -0.56,-3.53 0,-0.54 -0.45,-0.99 -0.99,-0.99H4.19C3.65,3 3,3.24 3,3.99 3,13.28 10.73,21 20.01,21c0.71,0 0.99,-0.63 0.99,-1.18v-3.45c0,-0.54 -0.45,-0.99 -0.99,-0.99z"/>
+</vector>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/drawable/baseline_call_end_24_primary.xml b/ring-android/app/src/main/res/drawable/baseline_call_end_24_primary.xml
new file mode 100644
index 0000000000000000000000000000000000000000..eef40e80476ab99f3a0e670a67a118763a7e25c4
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable/baseline_call_end_24_primary.xml
@@ -0,0 +1,11 @@
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0"
+    android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="@color/colorPrimary"
+        android:pathData="M12,9c-1.6,0 -3.15,0.25 -4.6,0.72v3.1c0,0.39 -0.23,0.74 -0.56,0.9 -0.98,0.49 -1.87,1.12 -2.66,1.85 -0.18,0.18 -0.43,0.28 -0.7,0.28 -0.28,0 -0.53,-0.11 -0.71,-0.29L0.29,13.08c-0.18,-0.17 -0.29,-0.42 -0.29,-0.7 0,-0.28 0.11,-0.53 0.29,-0.71C3.34,8.78 7.46,7 12,7s8.66,1.78 11.71,4.67c0.18,0.18 0.29,0.43 0.29,0.71 0,0.28 -0.11,0.53 -0.29,0.71l-2.48,2.48c-0.18,0.18 -0.43,0.29 -0.71,0.29 -0.27,0 -0.52,-0.11 -0.7,-0.28 -0.79,-0.74 -1.69,-1.36 -2.67,-1.85 -0.33,-0.16 -0.56,-0.5 -0.56,-0.9v-3.1C15.15,9.25 13.6,9 12,9z"/>
+</vector>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/drawable/baseline_flip_camera_24.xml b/ring-android/app/src/main/res/drawable/baseline_flip_camera_24.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d0b4daa426cd2897443064835250322786b2376c
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable/baseline_flip_camera_24.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M22.2,11.4c-0.3,-0.2 -0.8,-0.1 -1,0.2c-0.2,0.3 -0.1,0.8 0.2,1c0.6,0.3 1.1,0.9 1.2,1.6c0,1.5 -3.1,3.2 -8.3,3.7c-0.4,0 -0.7,0.4 -0.7,0.8s0.4,0.7 0.8,0.7h0.1c4.8,-0.4 9.7,-2.1 9.7,-5.2C23.9,13 23.2,12 22.2,11.4z"
+      android:fillColor="#FFFFFF"/>
+  <path
+      android:pathData="M8.8,15.2c-0.3,-0.3 -0.8,-0.3 -1.1,0c-0.3,0.3 -0.3,0.8 0,1.1l1.6,1.6c-4.7,-0.5 -7.8,-2.2 -7.8,-3.6C1.6,13.6 2,13 2.7,12.6C2.9,12.5 3,12.2 3,12s-0.2,-0.5 -0.4,-0.6s-0.5,-0.1 -0.7,0.1C0.8,12 0.1,13 0,14.2c0,2.9 4.6,4.7 9.5,5.1l-1.8,1.8c-0.2,0.2 -0.3,0.5 -0.2,0.7s0.3,0.5 0.5,0.5c0.3,0.1 0.5,0 0.7,-0.2l3,-3c0.3,-0.3 0.3,-0.8 0,-1.1L8.8,15.2z"
+      android:fillColor="#FFFFFF"/>
+  <path
+      android:pathData="M6,13.5h12c0.8,0 1.5,-0.7 1.5,-1.5V4.5C19.5,3.7 18.8,3 18,3h-2.7L14,1.7c-0.1,-0.1 -0.3,-0.2 -0.5,-0.2h-3c-0.2,0 -0.4,0.1 -0.5,0.2L8.7,3H6C5.2,3 4.5,3.7 4.5,4.5V12C4.5,12.8 5.2,13.5 6,13.5zM12,5.2c1.7,0 3,1.3 3,3s-1.3,3 -3,3s-3,-1.3 -3,-3S10.3,5.2 12,5.2z"
+      android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/ring-android/app/src/main/res/drawable/baseline_mic_24.xml b/ring-android/app/src/main/res/drawable/baseline_mic_24.xml
index d699f0954da85fb2c920125be6d18b915d442070..0d88b269802e97456f64ce6bf2d43f113a8822e6 100644
--- a/ring-android/app/src/main/res/drawable/baseline_mic_24.xml
+++ b/ring-android/app/src/main/res/drawable/baseline_mic_24.xml
@@ -2,10 +2,11 @@
     android:width="24dp"
     android:height="24dp"
     android:viewportWidth="24"
-    android:viewportHeight="24"
-    android:tint="?attr/colorControlNormal">
+    android:viewportHeight="24">
   <path
-      android:fillColor="@android:color/white"
-      android:pathData="M12,14c1.66,0 2.99,-1.34 2.99,-3L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6c0,1.66 1.34,3 3,3zM17.3,11c0,3 -2.54,5.1 -5.3,5.1S6.7,14 6.7,11L5,11c0,3.41 2.72,6.23 6,6.72L11,21h2v-3.28c3.28,-0.48 6,-3.3 6,-6.72h-1.7z"/>
+      android:pathData="M11.7,14.1c2.2,0 4.1,-1.7 4.1,-4.1V4.1c0,-2.2 -1.7,-4.1 -4.1,-4.1S7.6,1.9 7.6,4.1v6C7.6,12.4 9.5,14.1 11.7,14.1L11.7,14.1z"
+      android:fillColor="#FFFFFF"/>
+  <path
+      android:pathData="M15.8,13.5c-1,1.1 -2.5,1.7 -4,1.7c-1.6,0 -3,-0.6 -4,-1.7c-0.5,-0.6 -1.6,-0.8 -2.2,-0.2C5,14 4.9,14.9 5.5,15.6c1.3,1.4 3,2.4 4.9,2.7v4.1c0,0.8 0.6,1.6 1.6,1.6c0.8,0 1.6,-0.6 1.6,-1.6l0,0v-4.1c1.9,-0.3 3.7,-1.3 4.9,-2.7c0.5,-0.6 0.5,-1.6 -0.2,-2.2C17.3,12.7 16.3,12.7 15.8,13.5L15.8,13.5z"
+      android:fillColor="#FFFFFF"/>
 </vector>
-
diff --git a/ring-android/app/src/main/res/drawable/baseline_mic_off_24.xml b/ring-android/app/src/main/res/drawable/baseline_mic_off_24.xml
index 6109c69b3fea555b6fe6be85d981f390d4d13df6..3ff2537146e86278a124424a0580583b2f76ea8c 100755
--- a/ring-android/app/src/main/res/drawable/baseline_mic_off_24.xml
+++ b/ring-android/app/src/main/res/drawable/baseline_mic_off_24.xml
@@ -1,10 +1,18 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?attr/colorControlNormal">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M19,11h-1.7c0,0.74 -0.16,1.43 -0.43,2.05l1.23,1.23c0.56,-0.98 0.9,-2.09 0.9,-3.28zM14.98,11.17c0,-0.06 0.02,-0.11 0.02,-0.17L15,5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v0.18l5.98,5.99zM4.27,3L3,4.27l6.01,6.01L9.01,11c0,1.66 1.33,3 2.99,3 0.22,0 0.44,-0.03 0.65,-0.08l1.66,1.66c-0.71,0.33 -1.5,0.52 -2.31,0.52 -2.76,0 -5.3,-2.1 -5.3,-5.1L5,11c0,3.41 2.72,6.23 6,6.72L11,21h2v-3.28c0.91,-0.13 1.77,-0.45 2.54,-0.9L19.73,21 21,19.73 4.27,3z"/>
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M16.2,13.5c-1,1.1 -2.5,1.7 -4,1.7c-1.6,0 -3,-0.6 -4,-1.7c-0.5,-0.6 -1.6,-0.8 -2.2,-0.2c-0.6,0.6 -0.8,1.6 -0.2,2.2c1.3,1.4 3,2.4 4.9,2.7v4.1c0,0.8 0.6,1.6 1.6,1.6c0.8,0 1.6,-0.6 1.6,-1.6l0,0v-4.1c1.9,-0.3 3.7,-1.3 4.9,-2.7c0.5,-0.6 0.5,-1.6 -0.2,-2.2C17.6,12.7 16.7,12.7 16.2,13.5L16.2,13.5z"
+      android:fillColor="#CC0022"/>
+  <path
+      android:pathData="M5.4,23.4c-0.2,0 -0.3,0 -0.5,-0.2c-0.3,-0.2 -0.5,-0.8 -0.3,-1.1L18,1c0.2,-0.3 0.8,-0.5 1.1,-0.3s0.5,0.8 0.3,1.1L6.2,23C6,23.2 5.7,23.4 5.4,23.4z"
+      android:fillColor="#CC0022"/>
+  <path
+      android:pathData="M15.575,1.9C14.775,0.8 13.475,0 12.075,0C9.875,0 7.975,1.9 7.975,4.1v6c0,1 0.3,1.7 1,2.5L15.575,1.9z"
+      android:fillColor="#CC0022"/>
+  <path
+      android:pathData="M10.175,13.7c0.6,0.3 1.3,0.5 1.9,0.5c2.2,0 4.1,-1.7 4.1,-4.1L16.175,4.1c0,0 0,0 0,-0.2L10.175,13.7z"
+      android:fillColor="#CC0022"/>
 </vector>
diff --git a/ring-android/app/src/main/res/drawable/baseline_mobile_screen_share_24.xml b/ring-android/app/src/main/res/drawable/baseline_mobile_screen_share_24.xml
index 0349674349e2ec065a0c1f2e5b5e7a9cb9dc37dd..84f54a4e59db476a43deb5d9dca4a81e05d0e950 100755
--- a/ring-android/app/src/main/res/drawable/baseline_mobile_screen_share_24.xml
+++ b/ring-android/app/src/main/res/drawable/baseline_mobile_screen_share_24.xml
@@ -1,10 +1,9 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?attr/colorControlNormal">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M17,1.01L7,1c-1.1,0 -1.99,0.9 -1.99,2v18c0,1.1 0.89,2 1.99,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19L7,19L7,5h10v14zM12.8,13.22v1.75l3.2,-2.99L12.8,9v1.7c-3.11,0.43 -4.35,2.56 -4.8,4.7 1.11,-1.5 2.58,-2.18 4.8,-2.18z"/>
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M17.6,0c1,0 1.8,0.7 1.8,1.6l0,0v20.8c0,0.9 -0.8,1.6 -1.8,1.6l0,0H6.4c-1,0 -1.8,-0.7 -1.8,-1.6l0,0V1.6C4.6,0.7 5.4,0 6.4,0l0,0H17.6zM12.8,8v2c0,0 -0.1,0 -0.3,0l-0.2,0c-1.5,0 -5.4,0.5 -6.2,5.2c0,0 1.5,-3.4 6.7,-3.1v2l5.3,-3.1L12.8,8z"
+      android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/ring-android/app/src/main/res/drawable/baseline_person_add_24.xml b/ring-android/app/src/main/res/drawable/baseline_person_add_24.xml
index cf4e563df2370b69426c3f4e35bc46c458044066..296a2aa359ed96675bdaf0f4ed75a05802b883f3 100755
--- a/ring-android/app/src/main/res/drawable/baseline_person_add_24.xml
+++ b/ring-android/app/src/main/res/drawable/baseline_person_add_24.xml
@@ -1,10 +1,15 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?attr/colorControlNormal">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M15,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM6,10L6,7L4,7v3L1,10v2h3v3h2v-3h3v-2L6,10zM15,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M18,12c-3.3,0 -6,2.5 -6,6s2.5,6 6,6s6,-2.7 6,-6S21.2,12 18,12zM20.2,19.1H19v1.3c0,0.8 -0.6,1.3 -1.3,1.3c-0.6,0 -1,-0.6 -1,-1.4V19h-1.3c-0.6,0 -1.3,-0.5 -1.3,-1.3c0,-0.6 0.6,-1.3 1.3,-1.3h1.3v-1.3c0,-0.6 0.6,-1.3 1.3,-1.3c0.6,0 1.3,0.6 1.3,1.3v1.6h1.3c0.6,0 1.3,0.6 1.3,1.3C21.5,18.6 20.9,19.1 20.2,19.1z"
+      android:fillColor="#FFFFFF"/>
+  <path
+      android:pathData="M9.6,18c0,0.8 0.2,1.6 0.3,2.4H0.1c0,-5.2 4.3,-9.5 9.5,-9.5c1.3,0 2.2,0.2 3.2,0.6C10.9,12.8 9.6,15.1 9.6,18z"
+      android:fillColor="#FFFFFF"/>
+  <path
+      android:pathData="M9.6,4.8m-4.8,0a4.8,4.8 0,1 1,9.6 0a4.8,4.8 0,1 1,-9.6 0"
+      android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/ring-android/app/src/main/res/drawable/baseline_sound_off_24.xml b/ring-android/app/src/main/res/drawable/baseline_sound_off_24.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0cfd45bda772ca050f9b58d82bbab7fb3ff794b5
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable/baseline_sound_off_24.xml
@@ -0,0 +1,21 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M0.7,22.3c-0.1,0 -0.3,0 -0.4,-0.1C0,22 -0.2,21.4 0,21.2L17.5,2c0.1,-0.3 0.7,-0.4 1,-0.3c0.3,0.3 0.4,0.7 0.1,1.1L1.2,22C1.2,22.1 0.9,22.3 0.7,22.3z"
+      android:fillColor="#CC0022"/>
+  <path
+      android:pathData="M17.1,8.9c-0.7,0.3 -1,1 -0.7,1.6c0.1,0.5 0.3,1 0.3,1.5c0,0.5 -0.1,1.1 -0.3,1.5c-0.3,0.7 0.1,1.4 0.7,1.6c0.1,0 0.3,0.1 0.4,0.1c0.5,0 1,-0.3 1.2,-0.8c0.3,-0.8 0.4,-1.6 0.4,-2.5c0,-0.8 -0.1,-1.6 -0.4,-2.5C18.5,9 17.8,8.6 17.1,8.9z"
+      android:fillColor="#CC0022"/>
+  <path
+      android:pathData="M21.9,5.3c-0.4,-0.5 -1.2,-0.7 -1.8,-0.3c-0.5,0.4 -0.7,1.2 -0.3,1.8c1.1,1.5 1.6,3.4 1.6,5.3s-0.5,3.7 -1.6,5.3c-0.4,0.5 -0.3,1.4 0.3,1.8c0.1,0.1 0.4,0.1 0.7,0.1c0.4,0 0.8,-0.1 1.1,-0.5c1.4,-2.1 2.1,-4.4 2.1,-6.8S23.2,7.2 21.9,5.3z"
+      android:fillColor="#CC0022"/>
+  <path
+      android:pathData="M1.5,16.8h1L13.9,4.1v-1c0,-1.1 -1.2,-1.8 -2.2,-1.1L4.9,6.9C4.6,7.2 4.4,7.2 4.1,7.2H1.5c-0.8,0 -1.4,0.7 -1.4,1.4v6.7C0,16.1 0.7,16.8 1.5,16.8z"
+      android:fillColor="#CC0022"/>
+  <path
+      android:pathData="M4.2,16.8c0.3,0 0.5,0.1 0.8,0.3l6.7,4.9c1,0.7 2.2,0 2.2,-1.1V6.1L4.2,16.8z"
+      android:fillColor="#CC0022"/>
+</vector>
diff --git a/ring-android/app/src/main/res/drawable/baseline_sound_on_24.xml b/ring-android/app/src/main/res/drawable/baseline_sound_on_24.xml
new file mode 100644
index 0000000000000000000000000000000000000000..107a8988f8811b12b884022bad3ac04b29c1c67d
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable/baseline_sound_on_24.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M17.1,8.8c-0.7,0.3 -1,1 -0.7,1.7c0.1,0.6 0.3,1 0.3,1.5c0,0.6 -0.1,1.1 -0.3,1.5c-0.3,0.7 0.1,1.4 0.7,1.7c0.1,0 0.3,0.1 0.4,0.1c0.6,0 1,-0.3 1.2,-0.8c0.3,-0.8 0.4,-1.7 0.4,-2.5s-0.1,-1.7 -0.4,-2.5C18.5,9 17.8,8.6 17.1,8.8z"
+      android:fillColor="#FFFFFF"/>
+  <path
+      android:pathData="M21.9,5.3c-0.4,-0.6 -1.2,-0.7 -1.8,-0.3c-0.6,0.4 -0.7,1.2 -0.3,1.8c1.1,1.5 1.7,3.4 1.7,5.4s-0.6,3.7 -1.7,5.4c-0.4,0.6 -0.3,1.4 0.3,1.8c0.1,0.1 0.4,0.1 0.7,0.1c0.4,0 0.8,-0.1 1.1,-0.6c1.4,-2.1 2.1,-4.4 2.1,-6.9S23.3,7.2 21.9,5.3z"
+      android:fillColor="#FFFFFF"/>
+  <path
+      android:pathData="M11.6,2l-6.8,5C4.6,7.2 4.3,7.2 4,7.2H1.4C0.6,7.2 0,7.9 0,8.6v6.8c0,0.8 0.7,1.4 1.4,1.4H4c0.3,0 0.7,0.1 1,0.3l6.8,5c1,0.7 2.2,0 2.2,-1.1V2.9C13.8,2 12.6,1.3 11.6,2z"
+      android:fillColor="#FFFFFF"/>
+</vector>
diff --git a/ring-android/app/src/main/res/drawable/baseline_videocam_24.xml b/ring-android/app/src/main/res/drawable/baseline_videocam_24.xml
index 429061af062194f930a97ff06220ae6410f54a0c..0382accc5d2bd1570a93751bd98d3ca3235bb7df 100755
--- a/ring-android/app/src/main/res/drawable/baseline_videocam_24.xml
+++ b/ring-android/app/src/main/res/drawable/baseline_videocam_24.xml
@@ -1,10 +1,13 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?attr/colorControlNormal">
-    <path
-        android:fillColor="@android:color/white"
-        android:pathData="M17,10.5V7c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-3.5l4,4v-11l-4,4z"/>
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:pathData="M2.1,4.7H15c1.2,0 2.1,0.9 2.1,2.1v10.3c0,1.2 -0.9,2.1 -2.1,2.1H2.1c-1.2,0 -2.1,-0.9 -2.1,-2.1V6.9C0.1,5.7 1.1,4.7 2.1,4.7z"
+      android:fillColor="#FFFFFF"/>
+  <path
+      android:pathData="M23.1,6.2c-0.1,0 -0.3,0 -0.4,0.1l-4.1,3v5l4.1,3c0.4,0.3 0.9,0.1 1.2,-0.4c0.1,-0.1 0.1,-0.4 0.1,-0.5V7.3C23.9,6.7 23.5,6.2 23.1,6.2L23.1,6.2L23.1,6.2z"
+      android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/ring-android/app/src/main/res/drawable/baseline_videocam_24_primary.xml b/ring-android/app/src/main/res/drawable/baseline_videocam_24_primary.xml
new file mode 100644
index 0000000000000000000000000000000000000000..bdad9728c4b2d87c5c6da50d017ab5f707af232c
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable/baseline_videocam_24_primary.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0"
+    android:tint="?attr/colorControlNormal">
+    <path
+        android:fillColor="@color/colorPrimary"
+        android:pathData="M17,10.5V7c0,-0.55 -0.45,-1 -1,-1H4c-0.55,0 -1,0.45 -1,1v10c0,0.55 0.45,1 1,1h12c0.55,0 1,-0.45 1,-1v-3.5l4,4v-11l-4,4z"/>
+</vector>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/drawable/baseline_videocam_off_24.xml b/ring-android/app/src/main/res/drawable/baseline_videocam_off_24.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b1752195028dd64c1f6bc26756457830880ee40d
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable/baseline_videocam_off_24.xml
@@ -0,0 +1,18 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+  <path
+      android:pathData="M23.1,6.5c-0.1,0 -0.3,0 -0.4,0.1l-4.1,3v5l4.1,3c0.4,0.3 0.9,0.1 1.2,-0.4c0.1,-0.1 0.1,-0.4 0.1,-0.5v-9.1C23.9,7 23.5,6.5 23.1,6.5L23.1,6.5L23.1,6.5z"
+      android:fillColor="#CC0022"/>
+  <path
+      android:pathData="M13.5,5h-11.4c-1,0 -2,1 -2.1,2.2v10.2c0,0.3 0.1,0.6 0.2,0.9L13.5,5z"
+      android:fillColor="#CC0022"/>
+  <path
+      android:pathData="M15,5L15,5l-14.2,14.1c0.3,0.3 0.8,0.4 1.3,0.4h12.9c1.2,0 2.1,-0.9 2.1,-2.1v-10.3C17.1,5.9 16.2,5 15,5z"
+      android:fillColor="#CC0022"/>
+  <path
+      android:pathData="M1.1,20c-0.1,0 -0.3,0 -0.4,-0.1c-0.2,-0.2 -0.2,-0.5 0,-0.7L15.8,4.1c0.2,-0.2 0.5,-0.2 0.7,0s0.2,0.5 0,0.7L1.4,19.9C1.3,20 1.2,20 1.1,20z"
+      android:fillColor="#CC0022"/>
+</vector>
diff --git a/ring-android/app/src/main/res/drawable/drawer_handlebar.xml b/ring-android/app/src/main/res/drawable/drawer_handlebar.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2c8ebdf960936fc8ddd7c88a27fb386f1e8ae9a0
--- /dev/null
+++ b/ring-android/app/src/main/res/drawable/drawer_handlebar.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/grey_600" />
+    <corners
+        android:topLeftRadius="25dp"
+        android:topRightRadius="25dp"
+        android:bottomLeftRadius="25dp"
+        android:bottomRightRadius="25dp"/>
+</shape>
\ No newline at end of file
diff --git a/ring-android/app/src/main/res/layout/call_notification.xml b/ring-android/app/src/main/res/layout/call_notification.xml
new file mode 100644
index 0000000000000000000000000000000000000000..93a331ed58123a65007e696cd03d1bb555e89335
--- /dev/null
+++ b/ring-android/app/src/main/res/layout/call_notification.xml
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_vertical"
+    android:orientation="vertical">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center_vertical"
+        android:orientation="vertical"
+        android:paddingHorizontal="16dp"
+        android:paddingVertical="4dp">
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:paddingVertical="4dp"
+            tools:ignore="UseCompoundDrawables">
+            <ImageView
+                android:id="@+id/ivAppIcon"
+                android:layout_width="15dp"
+                android:layout_height="15dp"
+                android:background="@drawable/ic_ring_logo_white"
+                android:backgroundTint="@color/colorPrimary"
+                android:contentDescription="@string/app_name" />
+            <TextView
+                android:id="@+id/tvNotificationAppName"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="2dp"
+                android:text="@string/app_name"
+                android:textColor="@color/colorPrimary"
+                android:textSize="12sp" />
+        </LinearLayout>
+        <RelativeLayout
+            android:id="@+id/notification_main"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content">
+            <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentStart="true"
+                android:layout_centerVertical="true"
+                android:layout_toStartOf="@+id/ivAvatar"
+                android:orientation="vertical">
+                <TextView
+                    android:id="@+id/tvNotificationTitle"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:ellipsize="end"
+                    android:lines="1"
+                    android:textColor="@android:color/black"
+                    android:textSize="16sp" />
+                <TextView
+                    android:id="@+id/tvNotificationContent"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:ellipsize="end"
+                    android:lines="1"
+                    android:textAppearance="@style/TextAppearance.Compat.Notification.Title"
+                    android:textColor="@color/grey_700" />
+            </LinearLayout>
+            <ImageView
+                android:id="@+id/ivAvatar"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentTop="true"
+                android:layout_alignParentEnd="true"
+                android:contentDescription="@string/profile"
+                android:padding="8dp" />
+        </RelativeLayout>
+    </LinearLayout>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:paddingHorizontal="6dp"
+        android:weightSum="3">
+        <Button
+            android:id="@+id/btnRefuse"
+            style="@style/Widget.AppCompat.Button.Borderless"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:drawableStart="@drawable/baseline_call_end_24_primary"
+            android:drawablePadding="2dp"
+            android:ellipsize="end"
+            android:lines="1"
+            android:paddingHorizontal="2dp"
+            android:text="@string/action_call_decline"
+            android:textColor="@color/colorPrimary"
+            android:textSize="13sp" />
+        <Button
+            android:id="@+id/btnAcceptAudio"
+            style="@style/Widget.AppCompat.Button.Borderless"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:drawableStart="@drawable/baseline_call_24_primary"
+            android:ellipsize="end"
+            android:lines="2"
+            android:paddingHorizontal="2dp"
+            android:text="@string/action_call_accept_audio"
+            android:textColor="@color/colorPrimary"
+            android:textSize="13sp"
+            android:visibility="gone"
+            tools:visibility="visible" />
+        <Button
+            android:id="@+id/btnAcceptVideo"
+            style="@style/Widget.AppCompat.Button.Borderless"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:drawableStart="@drawable/baseline_videocam_24_primary"
+            android:ellipsize="end"
+            android:lines="2"
+            android:paddingHorizontal="2dp"
+            android:text="@string/action_call_accept_video"
+            android:textColor="@color/colorPrimary"
+            android:textSize="13sp"
+            android:visibility="gone"
+            tools:visibility="visible" />
+    </LinearLayout>
+</LinearLayout>
\ No newline at end of file
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 52b021247191863f7f9a8d5b866b763b80163ff0..ef5d20c9ae147c8f322f64bea7ddda449aebe0d9 100644
--- a/ring-android/app/src/main/res/layout/frag_call.xml
+++ b/ring-android/app/src/main/res/layout/frag_call.xml
@@ -142,9 +142,9 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
                 android:layout_centerInParent="true"
                 android:orientation="vertical"
                 android:visibility="gone"
+                app:alignItems="stretch"
                 app:flexDirection="column"
                 app:flexWrap="wrap"
-                app:alignItems="stretch"
                 tools:visibility="visible">
 
                 <RelativeLayout
@@ -235,12 +235,30 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
                             app:useCompatPadding="true"
                             tools:visibility="visible" />
 
+                        <com.google.android.material.floatingactionbutton.FloatingActionButton
+                            android:id="@+id/call_accept_audio_btn"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_margin="16dp"
+                            android:contentDescription="@string/action_call_accept_audio"
+                            android:onClick="@{() -> presenter.acceptAudioClicked()}"
+                            android:tint="@color/white"
+                            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"
+                            tools:visibility="visible" />
+
                         <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:contentDescription="@string/action_call_accept_video"
                             android:onClick="@{() -> presenter.acceptClicked()}"
                             android:visibility="gone"
                             app:backgroundTint="@color/green_500"
@@ -248,7 +266,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
                             app:fabSize="normal"
                             app:pressedTranslationZ="12dp"
                             app:rippleColor="@android:color/white"
-                            app:srcCompat="@drawable/baseline_call_24"
+                            app:srcCompat="@drawable/baseline_videocam_24"
                             app:useCompatPadding="true"
                             tools:visibility="visible" />
                     </LinearLayout>
@@ -268,9 +286,21 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
                 android:orientation="vertical"
                 android:visibility="gone"
                 app:flexDirection="column_reverse"
+                android:animateLayoutChanges="true"
                 app:flexWrap="wrap"
                 tools:visibility="visible">
 
+                <cx.ring.views.CheckableImageButton
+                    android:id="@+id/call_screenshare_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="@{(v) -> presenter.shareScreenClicked(((android.widget.Checkable)v).isChecked())}"
+                    android:padding="16dp"
+                    app:srcCompat="@drawable/baseline_mobile_screen_share_24" />
+
                 <ImageButton
                     android:id="@+id/call_camera_flip_btn"
                     android:layout_width="wrap_content"
@@ -280,19 +310,19 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
                     android:contentDescription="@string/ab_action_flipcamera"
                     android:onClick="@{() -> presenter.cameraFlip()}"
                     android:padding="16dp"
-                    android:tint="@color/white"
-                    app:srcCompat="@drawable/baseline_camera_front_24" />
+                    app:srcCompat="@drawable/baseline_flip_camera_24" />
 
-                <ImageButton
-                    android:id="@+id/call_conference_add"
+                <cx.ring.views.CheckableImageButton
+                    android:id="@+id/call_camera_switch_btn"
                     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:contentDescription="@string/ab_action_flipcamera"
+                    android:onClick="@{() -> presenter.switchCamera()}"
                     android:padding="16dp"
-                    android:tint="@color/white"
-                    app:srcCompat="@drawable/baseline_person_add_24" />
+                    android:visibility="visible"
+                    app:srcCompat="@drawable/baseline_videocam_24" />
 
                 <cx.ring.views.CheckableImageButton
                     android:id="@+id/call_mic_btn"
@@ -303,7 +333,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
                     android:contentDescription="@string/action_call_mic_mute"
                     android:onClick="@{() -> presenter.micClicked()}"
                     android:padding="16dp"
-                    android:tint="@color/white"
                     app:srcCompat="@drawable/baseline_mic_24"
                     tools:visibility="visible" />
 
@@ -316,20 +345,18 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
                     android:contentDescription="@string/ab_action_speakerphone"
                     android:onClick="@{() -> presenter.speakerClicked()}"
                     android:padding="16dp"
-                    android:tint="@color/white"
-                    app:srcCompat="@drawable/baseline_volume_up_24" />
+                    app:srcCompat="@drawable/baseline_sound_on_24" />
 
-                <cx.ring.views.CheckableImageButton
-                    android:id="@+id/call_screenshare_btn"
+
+                <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:contentDescription="@string/ab_action_speakerphone"
-                    android:onClick="@{(v) -> presenter.shareScreenClicked(((android.widget.Checkable)v).isChecked())}"
+                    android:onClick="@{() -> presenter.addParticipant()}"
                     android:padding="16dp"
-                    android:tint="@color/white"
-                    app:srcCompat="@drawable/baseline_mobile_screen_share_24" />
+                    app:srcCompat="@drawable/baseline_person_add_24" />
 
             </com.google.android.flexbox.FlexboxLayout>
 
@@ -374,11 +401,14 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
                 android:id="@+id/record_layout"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:orientation="horizontal"
-                android:layout_margin="16dp"
-                android:gravity="center_vertical"
                 android:layout_alignParentLeft="true"
+                android:layout_marginStart="16dp"
+                android:layout_marginTop="16dp"
+                android:layout_marginEnd="16dp"
+                android:layout_marginBottom="16dp"
                 android:layout_toLeftOf="@+id/conf_control_group"
+                android:gravity="center_vertical"
+                android:orientation="horizontal"
                 android:visibility="invisible"
                 tools:visibility="visible">
 
@@ -386,8 +416,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
                     android:id="@+id/record_indicator"
                     android:layout_width="13dp"
                     android:layout_height="13dp"
-                    android:backgroundTint="#BF0046"
-                    android:background="@drawable/item_color_background" />
+                    android:background="@drawable/item_color_background"
+                    android:backgroundTint="#BF0046" />
 
                 <TextView
                     android:id="@+id/record_name"
@@ -395,7 +425,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
                     android:layout_height="wrap_content"
                     android:layout_marginStart="8dp"
                     android:textSize="12sp"
-                    tools:text="Thomas"/>
+                    tools:text="Thomas" />
 
             </LinearLayout>
 
diff --git a/ring-android/app/src/main/res/values-fr-rFR/strings.xml b/ring-android/app/src/main/res/values-fr-rFR/strings.xml
index 6748d792ec6ac71269a255440856e1282e0555c4..f2beb2ba2e508d60024f480fe7e1f2d556ccf151 100644
--- a/ring-android/app/src/main/res/values-fr-rFR/strings.xml
+++ b/ring-android/app/src/main/res/values-fr-rFR/strings.xml
@@ -95,6 +95,8 @@
   <string name="start_error_title">Impossible de démarrer Jami !</string>
   <string name="start_error_mic_required">Jami requiert la permission d\'accéder à votre microphone pour fonctionner.</string>
   <string name="action_call_accept">Prendre un appel</string>
+  <string name="action_call_accept_audio">Répondre en audio</string>
+  <string name="action_call_accept_video">Répondre en video</string>
   <string name="action_call_hold_accept">Mettre en attente et prendre l\'appel</string>
   <string name="action_call_end_accept">Terminer et prendre l\'appel</string>
   <string name="action_call_decline">Refuser</string>
diff --git a/ring-android/app/src/main/res/values/strings.xml b/ring-android/app/src/main/res/values/strings.xml
index 888b0faa267cb8ad2783aa4d99bfc31df7eead67..03483258bf1fd0b3355607ae0d03e76e528e84c5 100644
--- a/ring-android/app/src/main/res/values/strings.xml
+++ b/ring-android/app/src/main/res/values/strings.xml
@@ -150,6 +150,8 @@ along with this program; if not, write to the Free Software
     <string name="start_error_title">Can\'t start Jami !</string>
     <string name="start_error_mic_required">Jami requires the microphone permission to work.</string>
     <string name="action_call_accept">Take call</string>
+    <string name="action_call_accept_audio">Answer in audio</string>
+    <string name="action_call_accept_video">Answer in video</string>
     <string name="action_call_hold_accept">Hold and take call</string>
     <string name="action_call_end_accept">End and take call</string>
     <string name="action_call_decline">Decline</string>
diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/call/CallPresenter.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/call/CallPresenter.kt
index 1fb3394605cb2ad9346552aa2202d75b77dc0288..daa02e14b70a1aa329066f4c4819f979df7f5bde 100644
--- a/ring-android/libjamiclient/src/main/kotlin/net/jami/call/CallPresenter.kt
+++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/call/CallPresenter.kt
@@ -56,7 +56,8 @@ class CallPresenter @Inject constructor(
     private val mPendingCalls: MutableList<Call> = ArrayList()
     private val mPendingSubject: Subject<List<Call>> = BehaviorSubject.createDefault(mPendingCalls)
     private var mOnGoingCall = false
-    var isAudioOnly = true
+    var wantVideo = false
+    var videoIsMuted = false
         private set
     private var permissionChanged = false
     var isPipMode = false
@@ -86,12 +87,12 @@ class CallPresenter @Inject constructor(
         }
     }
 
-    override fun unbindView() {
-        if (!isAudioOnly) {
+    /*override fun unbindView() {
+        if (wantVideo) {
             mHardwareService.endCapture()
         }
         super.unbindView()
-    }
+    }*/
 
     override fun bindView(view: CallView) {
         super.bindView(view)
@@ -118,20 +119,21 @@ class CallPresenter @Inject constructor(
                 }));*/
     }
 
-    fun initOutGoing(accountId: String?, conversationUri: Uri?, contactUri: String?, audioOnly: Boolean) {
+    fun initOutGoing(accountId: String?, conversationUri: Uri?, contactUri: String?, hasVideo: Boolean) {
         Log.e(TAG, "initOutGoing")
-        var audioOnly = audioOnly
+        var pHasVideo = hasVideo
         if (accountId == null || contactUri == null) {
             Log.e(TAG, "initOutGoing: null account or contact")
             hangupCall()
             return
         }
         if (!mHardwareService.hasCamera()) {
-            audioOnly = true
+            pHasVideo = false
         }
+        Log.w(TAG, "DEBUG fn initOutGoing() -> value of pHasVideo : $pHasVideo")
         //getView().blockScreenRotation();
         val callObservable = mCallService
-            .placeCall(accountId, conversationUri, fromString(toNumber(contactUri)!!), audioOnly)
+            .placeCall(accountId, conversationUri, fromString(toNumber(contactUri)!!), pHasVideo)
             //.map(mCallService::getConference)
             .flatMapObservable { call: Call -> mCallService.getConfUpdates(call) }
             .share()
@@ -155,6 +157,7 @@ class CallPresenter @Inject constructor(
      */
     fun initIncomingCall(confId: String, actionViewOnly: Boolean) {
         //getView().blockScreenRotation();
+        Log.w(TAG, "DEBUG fn initIncomingCall [CallPresenter.kt] -> if actionViewOnly ( = $actionViewOnly ) == true then getConfUpdate() who return a conference \n ,then if (!ActionViewOnly) call confUpdate() and prepareCall(isIncoming: true) or  ")
 
         // if the call is incoming through a full intent, this allows the incoming call to display
         incomingIsFullIntent = actionViewOnly
@@ -208,12 +211,14 @@ class CallPresenter @Inject constructor(
     fun prepareOptionMenu() {
         val isSpeakerOn: Boolean = mHardwareService.isSpeakerphoneOn
         //boolean hasContact = mSipCall != null && null != mSipCall.getContact() && mSipCall.getContact().isUnknown();
-        val canDial = mOnGoingCall && mConference != null
+        val conference = mConference
+        val canDial = mOnGoingCall && conference != null
+        val hasActiveVideo = conference?.hasActiveVideo() == true
         // get the preferences
         val displayPluginsButton = view!!.displayPluginsButton()
-        val showPluginBtn = displayPluginsButton && mOnGoingCall && mConference != null
-        val hasMultipleCamera = mHardwareService.cameraCount > 1 && mOnGoingCall && !isAudioOnly
-        view?.initMenu(isSpeakerOn, hasMultipleCamera, canDial, showPluginBtn, mOnGoingCall)
+        val showPluginBtn = displayPluginsButton && mOnGoingCall && conference != null
+        val hasMultipleCamera = mHardwareService.cameraCount > 1 && mOnGoingCall && hasActiveVideo
+        view?.initMenu(isSpeakerOn, hasMultipleCamera, canDial, showPluginBtn, mOnGoingCall, hasActiveVideo)
     }
 
     fun chatClick() {
@@ -246,7 +251,14 @@ class CallPresenter @Inject constructor(
     fun switchVideoInputClick() {
         val conference = mConference ?: return
         mHardwareService.switchInput(conference.id, false)
-        view?.switchCameraIcon(mHardwareService.isPreviewFromFrontCamera)
+        //view?.switchCameraIcon(mHardwareService.isPreviewFromFrontCamera)
+        view?.switchCameraIcon()
+    }
+
+    fun switchOnOffCamera() {
+        val conference = mConference ?: return
+        videoIsMuted = !videoIsMuted
+        mCallService.requestVideoMedia(conference, !videoIsMuted)
     }
 
     fun configurationChanged(rotation: Int) {
@@ -257,8 +269,8 @@ class CallPresenter @Inject constructor(
         view?.displayDialPadKeyboard()
     }
 
-    fun acceptCall() {
-        mConference?.let { mCallService.accept(it.id) }
+    fun acceptCall(hasVideo: Boolean) {
+        mConference?.let { mCallService.accept(it.id, hasVideo) }
     }
 
     fun hangupCall() {
@@ -425,36 +437,39 @@ class CallPresenter @Inject constructor(
         if (status === CallStatus.HOLD) {
             if (call.isSimpleCall) mCallService.unhold(call.id) else JamiService.addMainParticipant(call.id)
         }
-        isAudioOnly = !call.hasVideo()
+        val hasVideo = call.hasVideo()
+        val hasActiveVideo = call.hasActiveVideo()
+        videoIsMuted = !hasActiveVideo
         val view = view ?: return
         view.updateMenu()
         if (call.isOnGoing) {
             mOnGoingCall = true
-            view.initNormalStateDisplay(isAudioOnly, isMicrophoneMuted)
+            view.initNormalStateDisplay(!hasVideo, isMicrophoneMuted)
             view.updateMenu()
-            if (!isAudioOnly) {
+            if (hasVideo) {
                 mHardwareService.setPreviewSettings()
                 mHardwareService.updatePreviewVideoSurface(call)
                 videoSurfaceUpdateId(call.id)
                 pluginSurfaceUpdateId(call.pluginId)
-                view.displayVideoSurface(true, mDeviceRuntimeService.hasVideoPermission())
+                view.displayVideoSurface(true, hasActiveVideo && mDeviceRuntimeService.hasVideoPermission())
                 if (permissionChanged) {
-                    mHardwareService.switchInput(mConference!!.id, permissionChanged)
+                    mHardwareService.switchInput(call.id, permissionChanged)
                     permissionChanged = false
                 }
             }
             timeUpdateTask?.dispose()
             timeUpdateTask = mUiScheduler.schedulePeriodicallyDirect({ updateTime() }, 0, 1, TimeUnit.SECONDS)
         } else if (call.isRinging) {
+            //Log.w(TAG, "DEBUG fn confUpdate [CallPresenter] -> [ELSEIF] checking value of call.hasVideo() : ${call.hasVideo()}")
             val scall = call.call!!
-            view.handleCallWakelock(isAudioOnly)
+            view.handleCallWakelock(!hasVideo)
             if (scall.isIncoming) {
                 if (mAccountService.getAccount(scall.account!!)!!.isAutoanswerEnabled) {
                     Log.w(TAG, "Accept because of autoanswer")
-                    mCallService.accept(scall.daemonIdString!!)
+                    mCallService.accept(scall.daemonIdString!!, wantVideo)
                     // only display the incoming call screen if the notification is a full screen intent
                 } else if (incomingIsFullIntent) {
-                    view.initIncomingCallDisplay()
+                    view.initIncomingCallDisplay(hasVideo)
                 }
             } else {
                 mOnGoingCall = false
@@ -493,25 +508,33 @@ class CallPresenter @Inject constructor(
     }
 
     private fun onVideoEvent(event: VideoEvent) {
+        Log.w(TAG, "DEBUG fn onVideoEvent")
         Log.d(TAG, "VIDEO_EVENT: " + event.start + " " + event.callId + " " + event.w + "x" + event.h)
         val view = view ?: return
+        val conference = mConference
         if (event.start) {
-            view.displayVideoSurface(true, !isPipMode && mDeviceRuntimeService.hasVideoPermission())
-        } else if (mConference != null && mConference!!.id == event.callId) {
-            view.displayVideoSurface(event.started, event.started && !isPipMode && mDeviceRuntimeService.hasVideoPermission())
+            Log.w(TAG, "DEBUG fn onVideoEvent |1| inside => if (event.start) ")
+            view.displayVideoSurface(true, !isPipMode && mDeviceRuntimeService.hasVideoPermission() && conference?.hasActiveVideo() == true)
+        } else if (conference != null && conference.id == event.callId) {
+            Log.w(TAG, "DEBUG fn onVideoEvent |2| inside => else if (mConference != null && mConference!!.id == event.callId)")
+            Log.w(TAG, "DEBUG fn onVideoEvent |2| inside =>  event.started ${event.started} && !isPipMode ${!isPipMode} && mDeviceRuntimeService.hasVideoPermission() ${mDeviceRuntimeService.hasVideoPermission()} && hasVideo $wantVideo && !videoIsMuted ${!videoIsMuted}")
+            view.displayVideoSurface(event.started,
+                event.started && !isPipMode && mDeviceRuntimeService.hasVideoPermission() && conference.hasActiveVideo())
             if (event.started) {
                 videoWidth = event.w
                 videoHeight = event.h
                 view.resetVideoSize(videoWidth, videoHeight)
             }
         } else if (event.callId == null) {
+            Log.w(TAG, "DEBUG fn onVideoEvent |3| inside => else if (event.callId == null)")
             if (event.started) {
                 previewWidth = event.w
                 previewHeight = event.h
                 view.resetPreviewVideoSize(previewWidth, previewHeight, event.rot)
             }
         }
-        if (mConference != null && mConference!!.pluginId == event.callId) {
+        if (conference != null && conference.pluginId == event.callId) {
+            Log.w(TAG, "DEBUG fn onVideoEvent |4| inside => if (mConference != null && mConference!!.pluginId == event.callId)")
             if (event.started) {
                 previewWidth = event.w
                 previewHeight = event.h
@@ -525,7 +548,7 @@ class CallPresenter @Inject constructor(
 
     fun positiveButtonClicked() {
         if (mConference!!.isRinging && mConference!!.isIncoming) {
-            acceptCall()
+            acceptCall(true)
         } else {
             hangupCall()
         }
@@ -554,10 +577,12 @@ class CallPresenter @Inject constructor(
     fun pipModeChanged(pip: Boolean) {
         isPipMode = pip
         if (pip) {
+            Log.w(TAG, "DEBUG fn pipModeChanged |1| entering pipMode -> hangupButton : false; previewSurface: false; displayVideoSurface(true, false)")
             view!!.displayHangupButton(false)
             view!!.displayPreviewSurface(false)
             view!!.displayVideoSurface(true, false)
         } else {
+            Log.w(TAG, "DEBUG fn pipModeChanged |2| entering pipMode -> previewSurface: true; displayVideoSurface(true, mDeviceRuntimeService.hasVideoPermission() && hasVideo && !videoIsMuted)")
             view!!.displayPreviewSurface(true)
             view!!.displayVideoSurface(true, mDeviceRuntimeService.hasVideoPermission())
         }
@@ -565,6 +590,7 @@ class CallPresenter @Inject constructor(
 
     fun toggleCallMediaHandler(id: String, toggle: Boolean) {
         val conference = mConference ?: return
+        //Log.w(TAG, "fn toggleMediaHandler [CallPresenter] -> check value of conference.hasVideo : ${conference.hasVideo()}")
         if (conference.isOnGoing && conference.hasVideo()) {
             view?.toggleCallMediaHandler(id, conference.id, toggle)
         }
@@ -577,8 +603,8 @@ class CallPresenter @Inject constructor(
     fun addConferenceParticipant(accountId: String, uri: Uri) {
         mCompositeDisposable.add(mConversationFacade.startConversation(accountId, uri)
             .subscribe { conversation: Conversation ->
-                val confs: List<Conference> = conversation.currentCalls
-                if (confs.isEmpty()) {
+                val conf = conversation.currentCall
+                if (conf == null) {
                     val pendingObserver: Observer<Call> = object : Observer<Call> {
                         private var call: Call? = null
                         override fun onSubscribe(d: Disposable) {}
@@ -602,7 +628,7 @@ class CallPresenter @Inject constructor(
                     val contactUri = if (uri.isSwarm) conversation.contact!!.uri else uri
 
                     // Place new call, join to conference when answered
-                    val newCall = mCallService.placeCallObservable(accountId, null, contactUri, isAudioOnly)
+                    val newCall = mCallService.placeCallObservable(accountId, null, contactUri, wantVideo)
                         .doOnEach(pendingObserver)
                         .filter(Call::isOnGoing)
                         .firstElement()
@@ -616,21 +642,17 @@ class CallPresenter @Inject constructor(
                             mCallService.joinParticipant(id, call.daemonIdString!!).subscribe()
                         }
                     })
-                } else {
-                    // Selected contact already in call or conference, join it to current conference
-                    val selectedConf = confs[0]
-                    if (selectedConf !== mConference) {
-                        if (mConference!!.isConference) {
-                            if (selectedConf.isConference)
-                                mCallService.joinConference(mConference!!.id, selectedConf.id)
-                            else
-                                mCallService.addParticipant(selectedConf.id, mConference!!.id)
-                        } else {
-                            if (selectedConf.isConference)
-                                mCallService.addParticipant(mConference!!.id, selectedConf.id)
-                            else
-                                mCallService.joinParticipant(mConference!!.id, selectedConf.id).subscribe()
-                        }
+                } else if (conf !== mConference) {
+                    if (mConference!!.isConference) {
+                        if (conf.isConference)
+                            mCallService.joinConference(mConference!!.id, conf.id)
+                        else
+                            mCallService.addParticipant(conf.id, mConference!!.id)
+                    } else {
+                        if (conf.isConference)
+                            mCallService.addParticipant(mConference!!.id, conf.id)
+                        else
+                            mCallService.joinParticipant(mConference!!.id, conf.id).subscribe()
                     }
                 }
             })
diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/call/CallView.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/call/CallView.kt
index 62843bbe30c27c4414a78d24d91fef65cec59f00..d6970fa4098cc8a351b477f95d8024580b801075 100644
--- a/ring-android/libjamiclient/src/main/kotlin/net/jami/call/CallView.kt
+++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/call/CallView.kt
@@ -19,6 +19,7 @@
  */
 package net.jami.call
 
+import com.j256.ormlite.field.converter.BooleanNumberFieldConverter
 import net.jami.model.Call
 import net.jami.model.Call.CallStatus
 import net.jami.model.Conference.ParticipantInfo
@@ -32,15 +33,15 @@ interface CallView {
     fun displayPreviewSurface(display: Boolean)
     fun displayHangupButton(display: Boolean)
     fun displayDialPadKeyboard()
-    fun switchCameraIcon(isFront: Boolean)
+    fun switchCameraIcon()
     fun updateAudioState(state: AudioState)
     fun updateMenu()
     fun updateTime(duration: Long)
     fun updateContactBubble(contact: List<Call>)
     fun updateCallStatus(callState: CallStatus)
-    fun initMenu(isSpeakerOn: Boolean, displayFlip: Boolean, canDial: Boolean, showPluginBtn: Boolean, onGoingCall: Boolean)
+    fun initMenu(isSpeakerOn: Boolean, hasMultipleCamera: Boolean, canDial: Boolean, showPluginBtn: Boolean, onGoingCall: Boolean, hasActiveVideo: Boolean)
     fun initNormalStateDisplay(audioOnly: Boolean, muted: Boolean)
-    fun initIncomingCallDisplay()
+    fun initIncomingCallDisplay(hasVideo: Boolean)
     fun initOutGoingCallDisplay()
     fun resetPreviewVideoSize(previewWidth: Int, previewHeight: Int, rot: Int)
     fun resetPluginPreviewVideoSize(previewWidth: Int, previewHeight: Int, rot: Int)
diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/conversation/ConversationPresenter.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/conversation/ConversationPresenter.kt
index db178f86a8250e5f44d188548061e8838ab84483..69aeaef91280410973a7421182996dd38b54387d 100644
--- a/ring-android/libjamiclient/src/main/kotlin/net/jami/conversation/ConversationPresenter.kt
+++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/conversation/ConversationPresenter.kt
@@ -309,14 +309,16 @@ class ConversationPresenter @Inject constructor(
     fun clickOnGoingPane() {
         val conf = mConversation?.currentCall
         if (conf != null) {
-            view?.goToCallActivity(conf.id)
+            view?.goToCallActivity(conf.id, conf.hasActiveVideo())
         } else {
             view?.displayOnGoingCallPane(false)
         }
     }
 
-    fun goToCall(audioOnly: Boolean) {
-        if (audioOnly && !mHardwareService.hasMicrophone()) {
+    fun goToCall(withCamera: Boolean) {
+
+        Log.w(TAG, "DEBUG fn goToCall ||   hasVideo: $withCamera")
+        if (!withCamera && !mHardwareService.hasMicrophone()) {
             view!!.displayErrorToast(Error.NO_MICROPHONE)
             return
         }
@@ -329,9 +331,9 @@ class ConversationPresenter @Inject constructor(
                     if (conf != null && conf.participants.isNotEmpty()
                         && conf.participants[0].callStatus !== Call.CallStatus.INACTIVE
                         && conf.participants[0].callStatus !== Call.CallStatus.FAILURE) {
-                        view.goToCallActivity(conf.id)
+                        view.goToCallActivity(conf.id, conf.hasActiveVideo())
                     } else {
-                        view.goToCallActivityWithResult(conversation.accountId, conversation.uri, conversation.contact!!.uri, audioOnly)
+                        view.goToCallActivityWithResult(conversation.accountId, conversation.uri, conversation.contact!!.uri, withCamera)
                     }
                 }
             })
diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/conversation/ConversationView.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/conversation/ConversationView.kt
index 9eb95ec75a5a9cc96dfb64ec4ae6ddd0e8ba9f14..8b04bfc1ce1e4c3201bef9654c3766b04f8a2817 100644
--- a/ring-android/libjamiclient/src/main/kotlin/net/jami/conversation/ConversationView.kt
+++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/conversation/ConversationView.kt
@@ -22,6 +22,7 @@ package net.jami.conversation
 import net.jami.model.*
 import net.jami.model.Account.ComposingStatus
 import java.io.File
+import javax.swing.text.StyledEditorKit
 
 interface ConversationView {
     fun refreshView(conversation: List<Interaction>)
@@ -35,8 +36,8 @@ interface ConversationView {
     fun clearMsgEdit()
     fun goToHome()
     fun goToAddContact(contact: Contact)
-    fun goToCallActivity(conferenceId: String)
-    fun goToCallActivityWithResult(accountId: String, conversationUri: Uri, contactUri: Uri, audioOnly: Boolean)
+    fun goToCallActivity(conferenceId: String, withCamera: Boolean)
+    fun goToCallActivityWithResult(accountId: String, conversationUri: Uri, contactUri: Uri, withCamera: Boolean)
     fun goToContactActivity(accountId: String, uri: Uri)
     fun switchToUnknownView(name: String)
     fun switchToIncomingTrustRequestView(message: String)
diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Call.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Call.kt
index 6e7026b775aeb58ff3e79acdaf8bf1f72c9cf7a0..39dd51cfa49e8cba67c0ca557234e1debf1d6501 100644
--- a/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Call.kt
+++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Call.kt
@@ -19,13 +19,12 @@
  */
 package net.jami.model
 
-import net.jami.utils.StringUtils.isEmpty
-import net.jami.utils.ProfileChunk
-import ezvcard.VCard
-import net.jami.utils.VCardUtils
 import ezvcard.Ezvcard
+import ezvcard.VCard
 import net.jami.utils.Log
-import java.lang.Exception
+import net.jami.utils.ProfileChunk
+import net.jami.utils.StringUtils.isEmpty
+import net.jami.utils.VCardUtils
 import java.util.*
 
 class Call : Interaction {
@@ -35,8 +34,6 @@ class Call : Interaction {
         private set
     private var isVideoMuted = false
     private val isRecording = false
-    var isAudioOnly = false
-        private set
     var callStatus = CallStatus.NONE
         private set
     var timestampEnd: Long = 0
@@ -73,6 +70,9 @@ class Call : Interaction {
     var contactNumber: String? = null
         private set
     var confId: String? = null
+
+    var mediaList: List<Media>? = null
+
     private var mProfileChunk: ProfileChunk? = null
 
     constructor(
@@ -81,7 +81,8 @@ class Call : Interaction {
         account: String?,
         conversation: ConversationHistory?,
         contact: Contact?,
-        direction: Direction
+        direction: Direction,
+        mediaList: List<Media>,
     ) {
         daemonIdString = daemonId
         try {
@@ -97,6 +98,8 @@ class Call : Interaction {
         mType = InteractionType.CALL.toString()
         this.contact = contact
         mIsRead = 1
+        this.mediaList = mediaList
+
     }
 
     constructor(interaction: Interaction) {
@@ -145,16 +148,14 @@ class Call : Interaction {
     }
 
     fun setDetails(details: Map<String, String>) {
-        isPeerHolding = "true" == details[KEY_PEER_HOLDING]
-        isAudioMuted = "true" == details[KEY_AUDIO_MUTED]
-        isVideoMuted = "true" == details[KEY_VIDEO_MUTED]
-        isAudioOnly = "true" == details[KEY_AUDIO_ONLY]
+        isPeerHolding = details[KEY_PEER_HOLDING].toBoolean()
+        isAudioMuted = details[KEY_AUDIO_MUTED].toBoolean()
+        isVideoMuted = details[KEY_VIDEO_MUTED].toBoolean()
         audioCodec = details[KEY_AUDIO_CODEC]
         videoCodec = details[KEY_VIDEO_CODEC]
         val confId = details[KEY_CONF_ID]
         this.confId = if (isEmpty(confId)) null else confId
     }
-
     val isConferenceParticipant: Boolean
         get() = confId != null
 
@@ -230,6 +231,24 @@ class Call : Interaction {
         return null
     }
 
+    fun hasMedia(label: Media.MediaType): Boolean {
+        val mediaList = mediaList ?: return false
+        for (media in mediaList) {
+            // todo check -> isEnabled est il utile ? Si le media n'est pas activé alors le daemon ne nous le transmets pas ?
+            if (media.isEnabled && media.mediaType == label) {
+                return true
+            }
+        }
+        return false
+    }
+    fun hasActiveMedia(label: Media.MediaType): Boolean {
+        val mediaList = mediaList ?: return false
+        for (media in mediaList)
+            if (media.isEnabled && !media.isMuted && media.mediaType == label)
+                return true
+        return false
+    }
+
     enum class CallStatus {
         NONE, SEARCHING, CONNECTING, RINGING, CURRENT, HUNGUP, BUSY, FAILURE, HOLD, UNHOLD, INACTIVE, OVER;
 
@@ -275,7 +294,7 @@ class Call : Interaction {
     companion object {
         val TAG = Call::class.simpleName!!
         const val KEY_ACCOUNT_ID = "ACCOUNTID"
-        const val KEY_AUDIO_ONLY = "AUDIO_ONLY"
+        const val KEY_HAS_VIDEO = "HAS_VIDEO"
         const val KEY_CALL_TYPE = "CALL_TYPE"
         const val KEY_CALL_STATE = "CALL_STATE"
         const val KEY_PEER_NUMBER = "PEER_NUMBER"
diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Conference.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Conference.kt
index 5fd6757569534dba013270070037251aaca2b155..e08e40ed09d8bca60bb4b089d2c1dc5f753a2819 100644
--- a/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Conference.kt
+++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Conference.kt
@@ -25,6 +25,7 @@ import io.reactivex.rxjava3.subjects.BehaviorSubject
 import io.reactivex.rxjava3.subjects.Subject
 import net.jami.model.Call.CallStatus
 import net.jami.model.Call.CallStatus.Companion.fromConferenceString
+import net.jami.utils.Log
 import java.util.*
 import kotlin.math.min
 
@@ -135,8 +136,28 @@ class Conference {
     val isOnGoing: Boolean
         get() = mParticipants.size == 1 && mParticipants[0].isOnGoing || mParticipants.size > 1
 
+
+    fun getMediaList(): List<Media>? {
+        return if (mParticipants.size == 1) mParticipants[0].mediaList else ArrayList()
+    }
+
+    fun hasAudioMedia(): Boolean {
+        return mParticipants.size == 1  && mParticipants[0].hasMedia(Media.MediaType.MEDIA_TYPE_AUDIO)
+    }
+
     fun hasVideo(): Boolean {
-        for (call in mParticipants) if (!call.isAudioOnly) return true
+        for (call in mParticipants) if (call.hasMedia(Media.MediaType.MEDIA_TYPE_VIDEO)) return true
+        return false
+    }
+
+ /*   fun hasVideoMedia(): Boolean {
+        return mParticipants.size == 1 && mParticipants[0].hasMedia(Media.MediaType.MEDIA_TYPE_VIDEO)
+    }*/
+
+    fun hasActiveVideo(): Boolean {
+        for (call in mParticipants)
+            if (call.hasActiveMedia(Media.MediaType.MEDIA_TYPE_VIDEO))
+                return true
         return false
     }
 
@@ -168,4 +189,5 @@ class Conference {
         }
         mParticipantRecording.onNext(mParticipantRecordingSet)
     }
+
 }
\ No newline at end of file
diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Conversation.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Conversation.kt
index 389ecfac2382ad51831cef492be11ff2139cba36..5899800542e9a4c3b6749f848f4d9a0357088f9a 100644
--- a/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Conversation.kt
+++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Conversation.kt
@@ -39,7 +39,7 @@ class Conversation : ConversationHistory {
     val uri: Uri
     val contacts: MutableList<Contact>
     val rawHistory: NavigableMap<Long, Interaction> = TreeMap()
-    val currentCalls = ArrayList<Conference>()
+    private val currentCalls = ArrayList<Conference>()
     val aggregateHistory = ArrayList<Interaction>(32)
     private var lastDisplayed: Interaction? = null
     private val updatedElementSubject: Subject<Tuple<Interaction, ElementStatus>> = PublishSubject.create()
diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Media.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Media.kt
new file mode 100644
index 0000000000000000000000000000000000000000..f88729999ab21b0a3e04333770b33be3edb1c6d3
--- /dev/null
+++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Media.kt
@@ -0,0 +1,72 @@
+package net.jami.model
+
+import net.jami.daemon.StringMap
+import java.util.*
+
+data class Media(val source: String?,
+                 val mediaType: MediaType?,
+                 val label: String?,
+                 val isEnabled: Boolean,
+                 val isOnHold: Boolean,
+                 val isMuted: Boolean
+) {
+    constructor(mediaMap: Map<String, String>) : this(
+            source = mediaMap[SOURCE_KEY],
+            mediaType = MediaType.parseMediaType(mediaMap[MEDIA_TYPE_KEY]!!),
+            label = mediaMap[LABEL_KEY],
+            isEnabled = java.lang.Boolean.parseBoolean(mediaMap[ENABLED_KEY]),
+            isOnHold = java.lang.Boolean.parseBoolean(mediaMap[ON_HOLD_KEY]),
+            isMuted = java.lang.Boolean.parseBoolean(mediaMap[MUTED_KEY])
+    )
+
+    constructor(type: MediaType, label: String) : this(
+            source = "",
+            mediaType = type,
+            label = label,
+            isEnabled = true,
+            isOnHold = false,
+            isMuted = false
+    )
+
+    enum class MediaType {
+        MEDIA_TYPE_AUDIO,
+        MEDIA_TYPE_VIDEO;
+
+        companion object {
+            fun parseMediaType(mediaType: String): MediaType? {
+                for (mt in values()) {
+                    if (mt.name.contains(mediaType)) {
+                        return mt
+                    }
+                }
+                return null
+            }
+
+            fun getMediaTypeString(mediaType: MediaType?): String {
+                return mediaType?.name ?: "NULL"
+            }
+        }
+    }
+
+    fun toMap(): StringMap {
+        val map = StringMap()
+        if (source != null) map[SOURCE_KEY] = source
+        map[MEDIA_TYPE_KEY] = MediaType.getMediaTypeString(mediaType)
+        if (label != null) map[LABEL_KEY] = label
+        map[ENABLED_KEY] = java.lang.Boolean.toString(isEnabled)
+        map[ON_HOLD_KEY] = java.lang.Boolean.toString(isOnHold)
+        map[MUTED_KEY] = java.lang.Boolean.toString(isMuted)
+        return map
+    }
+
+    companion object {
+        private const val SOURCE_KEY = "SOURCE"
+        const val MEDIA_TYPE_KEY = "MEDIA_TYPE"
+        private const val LABEL_KEY = "LABEL"
+        private const val ENABLED_KEY = "ENABLED"
+        private const val ON_HOLD_KEY = "ON_HOLD"
+        const val MUTED_KEY = "MUTED"
+        val DEFAULT_AUDIO = Media(MediaType.MEDIA_TYPE_AUDIO, "audio_0")
+        val DEFAULT_VIDEO = Media(MediaType.MEDIA_TYPE_VIDEO, "video_0")
+    }
+}
diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/services/CallService.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/services/CallService.kt
index a4240fffe5d0a128d000aa5a0bdf3c13055d57a4..21ad4b92be601d489c2ea114af6a1e4602e312d9 100644
--- a/ring-android/libjamiclient/src/main/kotlin/net/jami/services/CallService.kt
+++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/services/CallService.kt
@@ -28,16 +28,26 @@ import io.reactivex.rxjava3.subjects.PublishSubject
 import net.jami.daemon.Blob
 import net.jami.daemon.JamiService
 import net.jami.daemon.StringMap
+import net.jami.daemon.VectMap
 import net.jami.model.Call
 import net.jami.model.Call.CallStatus
 import net.jami.model.Conference
 import net.jami.model.Conference.ParticipantInfo
+import net.jami.model.Media
 import net.jami.model.Uri
 import net.jami.utils.Log
 import net.jami.utils.StringUtils.isEmpty
+import net.jami.utils.SwigNativeConverter
+import org.w3c.dom.stylesheets.MediaList
 import java.util.*
 import java.util.concurrent.Callable
 import java.util.concurrent.ScheduledExecutorService
+import javax.xml.transform.Source
+import kotlin.collections.ArrayList
+
+
+
+
 
 class CallService(
     private val mExecutor: ScheduledExecutorService,
@@ -208,24 +218,25 @@ class CallService(
         SipCall call = getCurrentCallForId(callId);
         return call == null ? Observable.error(new IllegalArgumentException()) : getCallUpdates(call);
     }*/
-    fun placeCallObservable(accountId: String, conversationUri: Uri?, number: Uri, audioOnly: Boolean): Observable<Call> {
-        return placeCall(accountId, conversationUri, number, audioOnly)
+    fun placeCallObservable(accountId: String, conversationUri: Uri?, number: Uri, hasVideo: Boolean): Observable<Call> {
+        return placeCall(accountId, conversationUri, number, hasVideo)
             .flatMapObservable { call: Call -> getCallUpdates(call) }
     }
 
-    fun placeCall(account: String, conversationUri: Uri?, number: Uri, audioOnly: Boolean): Single<Call> {
+    fun placeCall(account: String, conversationUri: Uri?, number: Uri, hasVideo: Boolean): Single<Call> {
         return Single.fromCallable<Call> {
-            Log.i(TAG, "placeCall() thread running... $number audioOnly: $audioOnly")
-            val volatileDetails = HashMap<String, String>()
-            volatileDetails[Call.KEY_AUDIO_ONLY] = audioOnly.toString()
-            val callId = JamiService.placeCall(account, number.uri, StringMap.toSwig(volatileDetails))
+            Log.i(TAG, "placeCall() thread running... $number hasVideo: $hasVideo")
+            val media = VectMap()
+            media.reserve(if (hasVideo) 2L else 1L)
+            media.add(Media.DEFAULT_AUDIO.toMap())
+            if (hasVideo)
+                media.add(Media.DEFAULT_VIDEO.toMap())
+            val callId = JamiService.placeCallWithMedia(account, number.uri, media)
             if (callId == null || callId.isEmpty()) return@fromCallable null
-            if (audioOnly) {
-                JamiService.muteLocalMedia(callId, "MEDIA_TYPE_VIDEO", true)
-            }
-            val call = addCall(account, callId, number, Call.Direction.OUTGOING)
+            Log.w(TAG, "DEBUG fn placeCall() -> La valeur de hasVideo est $hasVideo et la valeur de !hasVideo est ${!hasVideo}")
+
+            val call = addCall(account, callId, number, Call.Direction.OUTGOING, if (hasVideo) listOf(Media.DEFAULT_AUDIO, Media.DEFAULT_VIDEO) else listOf(Media.DEFAULT_AUDIO))
             if (conversationUri != null && conversationUri.isSwarm) call.setSwarmInfo(conversationUri.rawRingId)
-            call.muteVideo(audioOnly)
             updateConnectionCount()
             call
         }.subscribeOn(Schedulers.from(mExecutor))
@@ -239,12 +250,33 @@ class CallService(
         }
     }
 
-    fun accept(callId: String) {
+/*    fun accept(callId: String) {
         mExecutor.execute {
             Log.i(TAG, "accept() running... $callId")
             JamiService.muteCapture(false)
             JamiService.accept(callId)
         }
+    }*/
+
+    fun accept(callId: String, hasVideo: Boolean = false) {
+        Log.w(TAG, "DEBUG fn accept [CallService.kt] -> based on value of hasvideo ( $hasVideo ) [IF] false then mute media type VIDEO and JamiService.accept [ELSE] add Media in VectMap and JamiService.acceptWithMedia() ")
+        mExecutor.execute {
+            Log.i(TAG, "accept() running... $callId")
+            val call = currentCalls[callId] ?: return@execute
+            val mediaList = call.mediaList ?: return@execute
+            val vectMapMedia = mediaList.mapTo(VectMap().apply { reserve(mediaList.size.toLong()) }, { media ->
+                if (!hasVideo && media.mediaType == Media.MediaType.MEDIA_TYPE_VIDEO)
+                    media.copy(isMuted = true).toMap()
+                else
+                    media.toMap()
+            })
+
+            for (i in vectMapMedia){
+                Log.w(TAG, "DEBUG fn accept [CallService.kt] -> $i")
+            }
+            Log.w(TAG, "DEBUG fn accept [CallService.kt] -> value of hasvideo : $hasVideo => on accept un appel avec media")
+            JamiService.acceptWithMedia(callId, vectMapMedia)
+        }
     }
 
     fun hangUp(callId: String) {
@@ -443,8 +475,9 @@ class CallService(
         }
     }
 
-    private fun addCall(accountId: String, callId: String, from: Uri, direction: Call.Direction): Call {
+    private fun addCall(accountId: String, callId: String, from: Uri, direction: Call.Direction, mediaList: List<Media>): Call {
         synchronized(currentCalls) {
+            Log.w(TAG, "DEBUG fn addCall() [CallService] -> if call == null ? create a new call instance and return it : update medialist of the call and return it => we go back to previous fn who will push the call as the updated subject ")
             var call = currentCalls[callId]
             if (call == null) {
                 val account = mAccountService.getAccount(accountId)!!
@@ -452,10 +485,11 @@ class CallService(
                 val conversationUri = contact.conversationUri.blockingFirst()
                 val conversation =
                     if (conversationUri.equals(from)) account.getByUri(from) else account.getSwarm(conversationUri.rawRingId)
-                call = Call(callId, from.uri, accountId, conversation, contact, direction)
+                call = Call(callId, from.uri, accountId, conversation, contact, direction, mediaList)
                 currentCalls[callId] = call
             } else {
                 Log.w(TAG, "Call already existed ! $callId $from")
+                call.mediaList = mediaList
             }
             return call
         }
@@ -534,13 +568,51 @@ class CallService(
         }
     }
 
-    fun incomingCall(accountId: String, callId: String, from: String) {
+    fun incomingCallWithMedia(accountId: String, callId: String, from: String, mediaList: VectMap?) {
         Log.d(TAG, "incoming call: $accountId, $callId, $from")
-        val call = addCall(accountId, callId, Uri.fromStringWithName(from).first, Call.Direction.INCOMING)
+        val nMediaList = mediaList ?: emptyList()
+        val medias = nMediaList.mapTo(ArrayList(nMediaList.size)) { mediaMap -> Media(mediaMap) }
+        val call = addCall(accountId, callId, Uri.fromStringWithName(from).first, Call.Direction.INCOMING, medias)
         callSubject.onNext(call)
         updateConnectionCount()
     }
 
+    fun mediaChangeRequested(accountId: String, callId: String, mediaList: VectMap) {
+        Log.w(TAG, "DEBUG fn mediaChangeRequested $accountId $callId $mediaList")
+        currentCalls[callId]?.let { call ->
+            if (!call.hasActiveMedia(Media.MediaType.MEDIA_TYPE_VIDEO)) {
+                for (e in mediaList)
+                    if (e[Media.MEDIA_TYPE_KEY]!! == MEDIA_TYPE_VIDEO)
+                        e[Media.MUTED_KEY] = true.toString()
+            }
+            JamiService.answerMediaChangeRequest(callId, mediaList)
+        }
+    }
+
+    fun mediaNegotiationStatus(callId: String, event: String, mediaList: VectMap) {
+        Log.w(TAG, "DEBUG fn mediaNegotiationStatus $callId $event $mediaList")
+        synchronized(currentCalls) {
+            currentCalls[callId]?.let { call ->
+                call.mediaList = mediaList.mapTo(ArrayList(mediaList.size), { media -> Media(media)})
+                callSubject.onNext(call)
+            }
+        }
+    }
+
+    fun requestVideoMedia(conf: Conference, enable: Boolean) {
+        Log.w(TAG, "DEBUG fn requestVideoMedia: ${conf.id} $enable")
+        if (conf.isConference || conf.hasVideo()) {
+            JamiService.muteLocalMedia(conf.id,  Media.MediaType.MEDIA_TYPE_VIDEO.name, !enable)
+        } else if (enable) {
+            val call = conf.firstCall ?: return
+            val mediaList = call.mediaList ?: return
+            JamiService.requestMediaChange(call.daemonIdString, mediaList.mapTo(VectMap()
+                    .apply { reserve(mediaList.size.toLong() + 1L) },
+                            { media -> media.toMap() })
+                    .apply { add(Media.DEFAULT_VIDEO.toMap()) })
+        }
+    }
+
     fun incomingMessage(callId: String, from: String, messages: Map<String, String>) {
         val call = currentCalls[callId]
         if (call == null) {
diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/services/ConversationFacade.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/services/ConversationFacade.kt
index 4bad9d94cea6393b53e4ac01e16e960d068df1a8..abb7ec8be0f85c020ff90360ca2259f0609937f7 100644
--- a/ring-android/libjamiclient/src/main/kotlin/net/jami/services/ConversationFacade.kt
+++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/services/ConversationFacade.kt
@@ -489,13 +489,16 @@ class ConversationFacade(
         Log.d(TAG, "onCallStateChange Thread id: " + Thread.currentThread().id)
         val newState = call.callStatus
         val incomingCall = newState === CallStatus.RINGING && call.isIncoming
-        mHardwareService.updateAudioState(newState, incomingCall, !call.isAudioOnly)
+        mHardwareService.updateAudioState(newState, incomingCall, call.hasMedia(Media.MediaType.MEDIA_TYPE_VIDEO))
         val account = mAccountService.getAccount(call.account!!) ?: return
         val contact = call.contact
         val conversationId = call.conversationId
         Log.w(TAG, "CallStateChange " + call.daemonIdString + " conversationId:" + conversationId)
         val conversation = if (conversationId == null)
-            if (contact == null) null else account.getByUri(contact.uri)
+            if (contact == null)
+                null
+            else
+                account.getByUri(contact.conversationUri.blockingFirst())
         else
             account.getSwarm(conversationId)
         val conference = if (conversation != null) (conversation.getConference(call.daemonIdString) ?: Conference(call).apply {
diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/services/DaemonService.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/services/DaemonService.kt
index 7ff7f380c70d877c45217ad3502c1adb448472e5..b481784e323c2c112f10ebbaecc21fe5dbeea69a 100644
--- a/ring-android/libjamiclient/src/main/kotlin/net/jami/services/DaemonService.kt
+++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/services/DaemonService.kt
@@ -19,6 +19,7 @@
  */
 package net.jami.services
 
+import net.jami.call.CallPresenter
 import net.jami.daemon.*
 import net.jami.model.Uri
 import net.jami.utils.Log
@@ -204,7 +205,23 @@ class DaemonService(
         }
 
         override fun incomingCall(accountId: String, callId: String, from: String) {
-            mCallService.incomingCall(accountId, callId, from)
+            // Should be kept while multi-stream is not enabled for Android by default
+            mCallService.incomingCallWithMedia(accountId, callId, from, null)
+        }
+
+        override fun incomingCallWithMedia(accountId: String, callId: String, from: String, mediaList: VectMap) {
+            for (i in mediaList){
+                Log.w(CallPresenter.TAG, "DEBUG fn incomingCallWithMedia [DaemonService] -> media.toMap() : ${i}")
+            }
+            mCallService.incomingCallWithMedia(accountId, callId, from, mediaList)
+        }
+
+        override fun mediaChangeRequested(accountId: String, callId: String, mediaList: VectMap) {
+            mCallService.mediaChangeRequested(accountId, callId, mediaList)
+        }
+
+        override fun mediaNegotiationStatus(callId: String, event: String, mediaList: VectMap) {
+            mCallService.mediaNegotiationStatus(callId, event, mediaList)
         }
 
         override fun connectionUpdate(id: String, state: Int) {