Changes to reflect new conference API

Should fix various conference UI issues

More UI fixes related to conference

Fixes & improvements

Fixed remove participant button invisible in dark mode

API changes

Handle conference enter and leave

Fixed conference UI issues

Small UI improvements

Improve logging

Improved paused conference cell

Use isMe if participant added or removed is focus

Update method names after changes to conference API
This commit is contained in:
Sylvain Berfini 2020-07-16 11:15:19 +02:00
parent 63205cb33f
commit b803ae9a61
19 changed files with 506 additions and 371 deletions

View file

@ -203,11 +203,17 @@ repositories {
maven { maven {
name "local linphone-sdk maven repository" name "local linphone-sdk maven repository"
url file(LinphoneSdkBuildDir + '/maven_repository/') url file(LinphoneSdkBuildDir + '/maven_repository/')
content {
includeGroup "org.linphone"
}
} }
maven { maven {
name "linphone.org maven repository" name "linphone.org maven repository"
url "https://linphone.org/maven_repository" url "https://linphone.org/maven_repository"
content {
includeGroup "org.linphone"
}
} }
} }
@ -286,4 +292,4 @@ if (crashlyticsEnabled()) {
assembleDebug.finalizedBy(uploadCrashlyticsSymbolFileDebug) assembleDebug.finalizedBy(uploadCrashlyticsSymbolFileDebug)
packageDebugBundle.finalizedBy(uploadCrashlyticsSymbolFileDebug) packageDebugBundle.finalizedBy(uploadCrashlyticsSymbolFileDebug)
} }
} }

View file

@ -39,7 +39,7 @@ abstract class ProximitySensorActivity : GenericActivity() {
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { } override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { }
override fun onSensorChanged(event: SensorEvent) { override fun onSensorChanged(event: SensorEvent) {
if (event.timestamp == 0L) return if (event.timestamp == 0L || !proximitySensorEnabled) return
if (isProximitySensorNearby(event)) { if (isProximitySensorNearby(event)) {
if (!proximityWakeLock.isHeld) { if (!proximityWakeLock.isHeld) {
Log.i("[Proximity Sensor Activity] Acquiring proximity wake lock") Log.i("[Proximity Sensor Activity] Acquiring proximity wake lock")
@ -89,6 +89,12 @@ abstract class ProximitySensorActivity : GenericActivity() {
super.onPause() super.onPause()
} }
override fun onDestroy() {
enableProximitySensor(false)
super.onDestroy()
}
protected fun enableProximitySensor(enable: Boolean) { protected fun enableProximitySensor(enable: Boolean) {
if (!proximitySensorFound) { if (!proximitySensorFound) {
Log.w("[Proximity Sensor Activity] Couldn't find proximity sensor in this device, skipping") Log.w("[Proximity Sensor Activity] Couldn't find proximity sensor in this device, skipping")

View file

@ -35,6 +35,7 @@ import org.linphone.LinphoneApplication.Companion.corePreferences
import org.linphone.R import org.linphone.R
import org.linphone.activities.GenericFragment import org.linphone.activities.GenericFragment
import org.linphone.activities.call.viewmodels.CallsViewModel import org.linphone.activities.call.viewmodels.CallsViewModel
import org.linphone.activities.call.viewmodels.ConferenceViewModel
import org.linphone.activities.call.viewmodels.ControlsViewModel import org.linphone.activities.call.viewmodels.ControlsViewModel
import org.linphone.activities.call.viewmodels.SharedCallViewModel import org.linphone.activities.call.viewmodels.SharedCallViewModel
import org.linphone.activities.main.MainActivity import org.linphone.activities.main.MainActivity
@ -51,6 +52,7 @@ import org.linphone.utils.PermissionHelper
class ControlsFragment : GenericFragment<CallControlsFragmentBinding>() { class ControlsFragment : GenericFragment<CallControlsFragmentBinding>() {
private lateinit var callsViewModel: CallsViewModel private lateinit var callsViewModel: CallsViewModel
private lateinit var controlsViewModel: ControlsViewModel private lateinit var controlsViewModel: ControlsViewModel
private lateinit var conferenceViewModel: ConferenceViewModel
private lateinit var sharedViewModel: SharedCallViewModel private lateinit var sharedViewModel: SharedCallViewModel
private var dialog: Dialog? = null private var dialog: Dialog? = null
@ -75,6 +77,9 @@ class ControlsFragment : GenericFragment<CallControlsFragmentBinding>() {
controlsViewModel = ViewModelProvider(this).get(ControlsViewModel::class.java) controlsViewModel = ViewModelProvider(this).get(ControlsViewModel::class.java)
binding.controlsViewModel = controlsViewModel binding.controlsViewModel = controlsViewModel
conferenceViewModel = ViewModelProvider(this).get(ConferenceViewModel::class.java)
binding.conferenceViewModel = conferenceViewModel
callsViewModel.currentCallViewModel.observe(viewLifecycleOwner, { callsViewModel.currentCallViewModel.observe(viewLifecycleOwner, {
if (it != null) { if (it != null) {
binding.activeCallTimer.base = binding.activeCallTimer.base =

View file

@ -22,9 +22,8 @@ package org.linphone.activities.call.viewmodels
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import org.linphone.LinphoneApplication.Companion.coreContext import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.core.Call import org.linphone.core.*
import org.linphone.core.Core import org.linphone.core.tools.Log
import org.linphone.core.CoreListenerStub
import org.linphone.utils.Event import org.linphone.utils.Event
import org.linphone.utils.PermissionHelper import org.linphone.utils.PermissionHelper
@ -35,10 +34,6 @@ class CallsViewModel : ViewModel() {
val pausedCalls = MutableLiveData<ArrayList<CallViewModel>>() val pausedCalls = MutableLiveData<ArrayList<CallViewModel>>()
val conferenceCalls = MutableLiveData<ArrayList<CallViewModel>>()
val isConferencePaused = MutableLiveData<Boolean>()
val noMoreCallEvent: MutableLiveData<Event<Boolean>> by lazy { val noMoreCallEvent: MutableLiveData<Event<Boolean>> by lazy {
MutableLiveData<Event<Boolean>>() MutableLiveData<Event<Boolean>>()
} }
@ -52,14 +47,9 @@ class CallsViewModel : ViewModel() {
} }
private val listener = object : CoreListenerStub() { private val listener = object : CoreListenerStub() {
override fun onCallStateChanged( override fun onCallStateChanged(core: Core, call: Call, state: Call.State, message: String) {
core: Core, Log.i("[Calls VM] Call state changed: $state")
call: Call, callPausedByRemote.value = (state == Call.State.PausedByRemote) and (call.conference == null)
state: Call.State,
message: String
) {
callPausedByRemote.value = state == Call.State.PausedByRemote
isConferencePaused.value = !coreContext.core.isInConference
val currentCall = core.currentCall val currentCall = core.currentCall
if (currentCall == null) { if (currentCall == null) {
@ -71,14 +61,11 @@ class CallsViewModel : ViewModel() {
if (state == Call.State.End || state == Call.State.Released || state == Call.State.Error) { if (state == Call.State.End || state == Call.State.Released || state == Call.State.Error) {
if (core.callsNb == 0) { if (core.callsNb == 0) {
noMoreCallEvent.value = Event(true) noMoreCallEvent.value = Event(true)
conferenceCalls.value = arrayListOf()
} else { } else {
removeCallFromPausedListIfPresent(call) removeCallFromPausedListIfPresent(call)
removeCallFromConferenceIfPresent(call)
} }
} else if (state == Call.State.Paused) { } else if (state == Call.State.Paused) {
addCallToPausedList(call) addCallToPausedList(call)
removeCallFromConferenceIfPresent(call)
} else if (state == Call.State.Resuming) { } else if (state == Call.State.Resuming) {
removeCallFromPausedListIfPresent(call) removeCallFromPausedListIfPresent(call)
} else if (call.state == Call.State.UpdatedByRemote) { } else if (call.state == Call.State.UpdatedByRemote) {
@ -91,16 +78,8 @@ class CallsViewModel : ViewModel() {
call.deferUpdate() call.deferUpdate()
callUpdateEvent.value = Event(call) callUpdateEvent.value = Event(call)
} }
} else { } else if (state == Call.State.StreamsRunning) {
if (state == Call.State.StreamsRunning) { callUpdateEvent.value = Event(call)
callUpdateEvent.value = Event(call)
}
if (call.conference != null) {
addCallToConferenceListIfNotAlreadyInIt(call)
} else {
removeCallFromConferenceIfPresent(call)
}
} }
} }
} }
@ -112,20 +91,14 @@ class CallsViewModel : ViewModel() {
if (currentCall != null) { if (currentCall != null) {
currentCallViewModel.value = CallViewModel(currentCall) currentCallViewModel.value = CallViewModel(currentCall)
} }
callPausedByRemote.value = currentCall?.state == Call.State.PausedByRemote
isConferencePaused.value = !coreContext.core.isInConference
val conferenceList = arrayListOf<CallViewModel>() callPausedByRemote.value = currentCall?.state == Call.State.PausedByRemote
for (call in coreContext.core.calls) { for (call in coreContext.core.calls) {
if (call.state == Call.State.Paused || call.state == Call.State.Pausing) { if (call.state == Call.State.Paused || call.state == Call.State.Pausing) {
addCallToPausedList(call) addCallToPausedList(call)
} else {
if (call.conference != null) {
conferenceList.add(CallViewModel(call))
}
} }
} }
conferenceCalls.value = conferenceList
} }
override fun onCleared() { override fun onCleared() {
@ -138,20 +111,6 @@ class CallsViewModel : ViewModel() {
coreContext.answerCallVideoUpdateRequest(call, accept) coreContext.answerCallVideoUpdateRequest(call, accept)
} }
fun pauseConference() {
if (coreContext.core.isInConference) {
coreContext.core.leaveConference()
isConferencePaused.value = true
}
}
fun resumeConference() {
if (!coreContext.core.isInConference) {
coreContext.core.enterConference()
isConferencePaused.value = false
}
}
fun takeScreenshot() { fun takeScreenshot() {
if (!PermissionHelper.get().hasWriteExternalStorage()) { if (!PermissionHelper.get().hasWriteExternalStorage()) {
askWriteExternalStoragePermissionEvent.value = Event(true) askWriteExternalStoragePermissionEvent.value = Event(true)
@ -161,9 +120,17 @@ class CallsViewModel : ViewModel() {
} }
private fun addCallToPausedList(call: Call) { private fun addCallToPausedList(call: Call) {
if (call.conference != null) return // Conference will be displayed as paused, no need to display the call as well
val list = arrayListOf<CallViewModel>() val list = arrayListOf<CallViewModel>()
list.addAll(pausedCalls.value.orEmpty()) list.addAll(pausedCalls.value.orEmpty())
for (pausedCallViewModel in list) {
if (pausedCallViewModel.call == call) {
return
}
}
val viewModel = CallViewModel(call) val viewModel = CallViewModel(call)
list.add(viewModel) list.add(viewModel)
pausedCalls.value = list pausedCalls.value = list
@ -182,31 +149,4 @@ class CallsViewModel : ViewModel() {
pausedCalls.value = list pausedCalls.value = list
} }
private fun addCallToConferenceListIfNotAlreadyInIt(call: Call) {
val list = arrayListOf<CallViewModel>()
list.addAll(conferenceCalls.value.orEmpty())
for (viewModel in list) {
if (viewModel.call == call) return
}
val viewModel = CallViewModel(call)
list.add(viewModel)
conferenceCalls.value = list
}
private fun removeCallFromConferenceIfPresent(call: Call) {
val list = arrayListOf<CallViewModel>()
list.addAll(conferenceCalls.value.orEmpty())
for (viewModel in list) {
if (viewModel.call == call) {
list.remove(viewModel)
break
}
}
conferenceCalls.value = list
}
} }

View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-android
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.linphone.activities.call.viewmodels
import androidx.lifecycle.MutableLiveData
import org.linphone.contact.GenericContactViewModel
import org.linphone.core.Conference
import org.linphone.core.Participant
import org.linphone.core.tools.Log
class ConferenceParticipantViewModel(
private val conference: Conference,
val participant: Participant
) :
GenericContactViewModel(participant.address) {
private val isAdmin = MutableLiveData<Boolean>()
val isMeAdmin = MutableLiveData<Boolean>()
init {
isAdmin.value = participant.isAdmin
isMeAdmin.value = conference.me.isAdmin
Log.i("[Conference Participant VM] Participant ${participant.address.asStringUriOnly()} is ${if (participant.isAdmin) "admin" else "not admin"}")
Log.i("[Conference Participant VM] Me is ${if (conference.me.isAdmin) "admin" else "not admin"} and is ${if (conference.me.isFocus) "focus" else "not focus"}")
}
fun removeFromConference() {
Log.i("[Conference Participant VM] Removing participant ${participant.address.asStringUriOnly()} from conference $conference")
conference.removeParticipant(participant)
}
}

View file

@ -0,0 +1,156 @@
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-android
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.linphone.activities.call.viewmodels
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.core.*
import org.linphone.core.tools.Log
class ConferenceViewModel : ViewModel() {
val isConferencePaused = MutableLiveData<Boolean>()
val isMeConferenceFocus = MutableLiveData<Boolean>()
val conferenceAddress = MutableLiveData<Address>()
val conferenceParticipants = MutableLiveData<List<ConferenceParticipantViewModel>>()
val isInConference = MutableLiveData<Boolean>()
private val conferenceListener = object : ConferenceListenerStub() {
override fun onParticipantAdded(conference: Conference, participant: Participant) {
if (conference.isMe(participant.address)) {
Log.i("[Conference VM] Entered conference")
isConferencePaused.value = false
} else {
Log.i("[Conference VM] Participant added")
updateParticipantsList(conference)
}
}
override fun onParticipantRemoved(conference: Conference, participant: Participant) {
if (conference.isMe(participant.address)) {
Log.i("[Conference VM] Left conference")
isConferencePaused.value = true
} else {
Log.i("[Conference VM] Participant removed")
updateParticipantsList(conference)
}
}
override fun onParticipantAdminStatusChanged(
conference: Conference,
participant: Participant
) {
Log.i("[Conference VM] Participant admin status changed")
updateParticipantsList(conference)
}
}
private val listener = object : CoreListenerStub() {
override fun onConferenceStateChanged(
core: Core,
conference: Conference,
state: Conference.State
) {
Log.i("[Conference VM] Conference state changed: $state")
isConferencePaused.value = !conference.isIn
if (state == Conference.State.Instantiated) {
conference.addListener(conferenceListener)
} else if (state == Conference.State.Created) {
updateParticipantsList(conference)
isMeConferenceFocus.value = conference.me.isFocus
conferenceAddress.value = conference.conferenceAddress
} else if (state == Conference.State.Terminated || state == Conference.State.TerminationFailed) {
isInConference.value = false
conference.removeListener(conferenceListener)
conferenceParticipants.value = arrayListOf()
}
}
}
init {
coreContext.core.addListener(listener)
isConferencePaused.value = coreContext.core.conference?.isIn != true
isMeConferenceFocus.value = false
conferenceParticipants.value = arrayListOf()
isInConference.value = false
val conference = coreContext.core.conference
if (conference != null) {
conference.addListener(conferenceListener)
isMeConferenceFocus.value = conference.me.isFocus
updateParticipantsList(conference)
}
}
override fun onCleared() {
coreContext.core.removeListener(listener)
super.onCleared()
}
fun pauseConference() {
val defaultProxyConfig = coreContext.core.defaultProxyConfig
val localAddress = defaultProxyConfig?.identityAddress
val participants = arrayOf<Address>()
val remoteConference = coreContext.core.searchConference(null, localAddress, conferenceAddress.value, participants)
val localConference = coreContext.core.searchConference(null, conferenceAddress.value, conferenceAddress.value, participants)
val conference = remoteConference ?: localConference
if (conference != null) {
Log.i("[Conference VM] Leaving conference with address ${conferenceAddress.value?.asStringUriOnly()} temporarily")
conference.leave()
} else {
Log.w("[Conference VM] Unable to find conference with address ${conferenceAddress.value?.asStringUriOnly()}")
}
}
fun resumeConference() {
val defaultProxyConfig = coreContext.core.defaultProxyConfig
val localAddress = defaultProxyConfig?.identityAddress
val participants = arrayOf<Address>()
val remoteConference = coreContext.core.searchConference(null, localAddress, conferenceAddress.value, participants)
val localConference = coreContext.core.searchConference(null, conferenceAddress.value, conferenceAddress.value, participants)
val conference = remoteConference ?: localConference
if (conference != null) {
Log.i("[Conference VM] Entering again conference with address ${conferenceAddress.value?.asStringUriOnly()}")
conference.enter()
} else {
Log.w("[Conference VM] Unable to find conference with address ${conferenceAddress.value?.asStringUriOnly()}")
}
}
private fun updateParticipantsList(conference: Conference) {
val participants = arrayListOf<ConferenceParticipantViewModel>()
for (participant in conference.participantList) {
Log.i("[Conference VM] Participant found: ${participant.address.asStringUriOnly()}")
val viewModel = ConferenceParticipantViewModel(conference, participant)
participants.add(viewModel)
}
conferenceParticipants.value = participants
isInConference.value = participants.isNotEmpty()
}
}

View file

@ -285,8 +285,8 @@ class ControlsViewModel : ViewModel() {
if (conference != null && core.isInConference) { if (conference != null && core.isInConference) {
val params = core.createConferenceParams() val params = core.createConferenceParams()
val videoEnabled = conference.currentParams.videoEnabled() val videoEnabled = conference.currentParams.isVideoEnabled
params.enableVideo(!videoEnabled) params.isVideoEnabled = !videoEnabled
Log.i("[Controls VM] Conference current param for video is $videoEnabled") Log.i("[Controls VM] Conference current param for video is $videoEnabled")
conference.updateParams(params) conference.updateParams(params)
} else if (currentCall != null) { } else if (currentCall != null) {
@ -362,7 +362,7 @@ class ControlsViewModel : ViewModel() {
val currentCallVideoEnabled = core.currentCall?.currentParams?.videoEnabled() ?: false val currentCallVideoEnabled = core.currentCall?.currentParams?.videoEnabled() ?: false
val params = core.createConferenceParams() val params = core.createConferenceParams()
params.enableVideo(currentCallVideoEnabled) params.isVideoEnabled = currentCallVideoEnabled
Log.i("[Call] Setting videoEnabled to [$currentCallVideoEnabled] in conference params") Log.i("[Call] Setting videoEnabled to [$currentCallVideoEnabled] in conference params")
val conference = core.conference ?: core.createConferenceWithParams(params) val conference = core.conference ?: core.createConferenceWithParams(params)

View file

@ -37,16 +37,8 @@ class StatisticsListViewModel : ViewModel() {
state: Call.State, state: Call.State,
message: String message: String
) { ) {
if (state == Call.State.End || state == Call.State.Error) { if (state == Call.State.End || state == Call.State.Error || state == Call.State.Connected) {
val newList = arrayListOf<CallStatisticsData>() computeCallsList()
for (stat in callStatsList.value.orEmpty()) {
if (stat.call != call) {
newList.add(stat)
} else {
stat.destroy()
}
}
callStatsList.value = newList
} }
} }
} }
@ -54,13 +46,7 @@ class StatisticsListViewModel : ViewModel() {
init { init {
coreContext.core.addListener(listener) coreContext.core.addListener(listener)
val list = arrayListOf<CallStatisticsData>() computeCallsList()
for (call in coreContext.core.calls) {
if (call.state != Call.State.End && call.state != Call.State.Released && call.state != Call.State.Error) {
list.add(CallStatisticsData(call))
}
}
callStatsList.value = list
} }
override fun onCleared() { override fun onCleared() {
@ -69,4 +55,14 @@ class StatisticsListViewModel : ViewModel() {
super.onCleared() super.onCleared()
} }
private fun computeCallsList() {
val list = arrayListOf<CallStatisticsData>()
for (call in coreContext.core.calls) {
if (call.state != Call.State.End && call.state != Call.State.Released && call.state != Call.State.Error) {
list.add(CallStatisticsData(call))
}
}
callStatsList.value = list
}
} }

View file

@ -133,7 +133,7 @@ class StatusViewModel : StatusViewModel() {
} }
private fun updateCallQualityIcon() { private fun updateCallQualityIcon() {
val call = coreContext.core.currentCall val call = coreContext.core.currentCall ?: coreContext.core.calls.firstOrNull()
val quality = call?.currentQuality ?: 0f val quality = call?.currentQuality ?: 0f
callQualityIcon.value = when { callQualityIcon.value = when {
quality >= 4 -> R.drawable.call_quality_indicator_4 quality >= 4 -> R.drawable.call_quality_indicator_4

View file

@ -26,11 +26,12 @@ import android.view.LayoutInflater
import android.widget.LinearLayout import android.widget.LinearLayout
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
import org.linphone.R import org.linphone.R
import org.linphone.activities.call.viewmodels.CallViewModel import org.linphone.activities.call.viewmodels.ConferenceParticipantViewModel
import org.linphone.databinding.CallConferenceBinding import org.linphone.core.tools.Log
import org.linphone.databinding.CallConferenceParticipantBinding
class ConferenceCallView : LinearLayout { class ConferenceParticipantView : LinearLayout {
private lateinit var binding: CallConferenceBinding private lateinit var binding: CallConferenceParticipantBinding
constructor(context: Context) : super(context) { constructor(context: Context) : super(context) {
init(context) init(context)
@ -53,15 +54,18 @@ class ConferenceCallView : LinearLayout {
fun init(context: Context) { fun init(context: Context) {
binding = DataBindingUtil.inflate( binding = DataBindingUtil.inflate(
LayoutInflater.from(context), R.layout.call_conference, this, true LayoutInflater.from(context), R.layout.call_conference_participant, this, true
) )
} }
fun setViewModel(viewModel: CallViewModel) { fun setViewModel(viewModel: ConferenceParticipantViewModel) {
binding.viewModel = viewModel binding.viewModel = viewModel
binding.callTimer.base = val currentTimeSecs = System.currentTimeMillis()
SystemClock.elapsedRealtime() - (1000 * viewModel.call.duration) // Linphone timestamps are in seconds val participantTime = viewModel.participant.creationTime * 1000 // Linphone timestamps are in seconds
val diff = currentTimeSecs - participantTime
Log.i("[Conference Participant] Participant joined conference at $participantTime == ${diff / 1000} seconds ago.")
binding.callTimer.base = SystemClock.elapsedRealtime() - diff
binding.callTimer.start() binding.callTimer.start()
} }
} }

View file

@ -506,7 +506,7 @@ class CoreContext(val context: Context, coreConfig: Config) {
fun isVideoCallOrConferenceActive(): Boolean { fun isVideoCallOrConferenceActive(): Boolean {
val conference = core.conference val conference = core.conference
return if (conference != null && core.isInConference) { return if (conference != null && core.isInConference) {
conference.currentParams.videoEnabled() conference.currentParams.isVideoEnabled()
} else { } else {
core.currentCall?.currentParams?.videoEnabled() ?: false core.currentCall?.currentParams?.videoEnabled() ?: false
} }

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<bitmap android:src="@drawable/options_start_conference_default"
android:tint="?attr/drawableTintColor2"/>
</item>
</selector>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<bitmap android:src="@drawable/conference_exit_default"
android:tint="?attr/drawableTintColor"/>
</item>
</selector>

View file

@ -12,6 +12,9 @@
<variable <variable
name="controlsViewModel" name="controlsViewModel"
type="org.linphone.activities.call.viewmodels.ControlsViewModel" /> type="org.linphone.activities.call.viewmodels.ControlsViewModel" />
<variable
name="conferenceViewModel"
type="org.linphone.activities.call.viewmodels.ConferenceViewModel" />
</data> </data>
<RelativeLayout <RelativeLayout
@ -26,7 +29,7 @@
<LinearLayout <LinearLayout
android:id="@+id/active_call_header" android:id="@+id/active_call_header"
android:visibility="@{viewModel.currentCallViewModel == null ? View.GONE : View.VISIBLE}" android:visibility="@{viewModel.currentCallViewModel == null || conferenceViewModel.isInConference() ? View.GONE : View.VISIBLE}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
@ -54,75 +57,16 @@
</LinearLayout> </LinearLayout>
<LinearLayout <include layout="@layout/call_conference"
android:visibility="@{viewModel.conferenceCalls.size() == 0 || viewModel.isConferencePaused ? View.GONE : View.VISIBLE, default=gone}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:background="?attr/backgroundColor" app:controlsViewModel="@{controlsViewModel}"
android:orientation="vertical"> app:conferenceViewModel="@{conferenceViewModel}" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingLeft="10dp"
android:textColor="?attr/primaryTextColor"
android:textSize="30sp"
android:text="@string/call_conference_title" />
<ImageView
android:onClick="@{() -> controlsViewModel.switchCamera()}"
android:visibility="@{controlsViewModel.isVideoEnabled ? View.VISIBLE : View.GONE, default=gone}"
android:contentDescription="@string/content_description_switch_camera"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_toLeftOf="@id/pause_conference"
android:adjustViewBounds="true"
android:padding="10dp"
android:scaleType="fitCenter"
android:background="@drawable/round_button_background"
android:src="@drawable/camera_switch" />
<ImageView
android:id="@+id/pause_conference"
android:onClick="@{() -> viewModel.pauseConference()}"
android:contentDescription="@string/content_description_pause_conference"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginRight="10dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:adjustViewBounds="true"
android:padding="10dp"
android:scaleType="fitCenter"
android:background="@drawable/round_button_background"
android:src="@drawable/call_pause" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dividerColor" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:orientation="vertical"
app:entries="@{viewModel.conferenceCalls}"
app:layout="@{@layout/call_conference_cell}"/>
</LinearLayout>
<org.linphone.contact.BigContactAvatarView <org.linphone.contact.BigContactAvatarView
android:visibility="@{controlsViewModel.isVideoEnabled ? View.GONE : View.VISIBLE, default=gone}" android:visibility="@{controlsViewModel.isVideoEnabled || conferenceViewModel.isInConference ? View.GONE : View.VISIBLE, default=gone}"
android:id="@+id/avatar" android:id="@+id/avatar"
android:layout_width="200dp" android:layout_width="200dp"
android:layout_height="200dp" android:layout_height="200dp"
@ -169,51 +113,15 @@
app:entries="@{viewModel.pausedCalls}" app:entries="@{viewModel.pausedCalls}"
app:layout="@{@layout/call_paused_cell}" /> app:layout="@{@layout/call_paused_cell}" />
<LinearLayout <include layout="@layout/conference_paused"
android:visibility="@{viewModel.isConferencePaused &amp;&amp; viewModel.conferenceCalls.size() > 1 ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="50dp" android:layout_height="50dp"
android:layout_above="@id/paused_calls" android:layout_above="@id/paused_calls"
android:alpha="0.5" app:conferenceViewModel="@{conferenceViewModel}" />
android:background="?attr/accentColor"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="5dp">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:contentDescription="@string/content_description_start_conference"
android:src="@drawable/options_start_conference" />
<TextView
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical|left"
android:singleLine="true"
android:ellipsize="end"
android:paddingLeft="20dp"
android:paddingRight="10dp"
android:textColor="?attr/secondaryTextColor"
android:textSize="15sp"
android:text="@string/call_conference_title" />
<ImageView
android:onClick="@{() -> viewModel.resumeConference()}"
android:layout_width="40dp"
android:layout_height="40dp"
android:gravity="center_vertical"
android:contentDescription="@string/content_description_resume_conference"
android:background="@drawable/round_button_background"
android:padding="10dp"
android:src="@drawable/call_pause" />
</LinearLayout>
<ImageView <ImageView
android:onClick="@{() -> viewModel.currentCallViewModel.pause()}" android:onClick="@{() -> viewModel.currentCallViewModel.pause()}"
android:visibility="@{viewModel.currentCallViewModel == null ? View.GONE : View.VISIBLE}" android:visibility="@{viewModel.currentCallViewModel == null || conferenceViewModel.isInConference ? View.GONE : View.VISIBLE}"
android:selected="@{viewModel.currentCallViewModel.isPaused ?? false}" android:selected="@{viewModel.currentCallViewModel.isPaused ?? false}"
android:enabled="@{!viewModel.callPausedByRemote &amp;&amp; controlsViewModel.isPauseEnabled}" android:enabled="@{!viewModel.callPausedByRemote &amp;&amp; controlsViewModel.isPauseEnabled}"
android:contentDescription="@string/content_description_pause_call" android:contentDescription="@string/content_description_pause_call"
@ -230,7 +138,7 @@
android:id="@+id/switch_camera" android:id="@+id/switch_camera"
android:onClick="@{() -> controlsViewModel.switchCamera()}" android:onClick="@{() -> controlsViewModel.switchCamera()}"
android:enabled="@{!viewModel.callPausedByRemote}" android:enabled="@{!viewModel.callPausedByRemote}"
android:visibility="@{controlsViewModel.isVideoEnabled &amp;&amp; controlsViewModel.showSwitchCamera &amp;&amp; (viewModel.conferenceCalls.size() == 0 || viewModel.isConferencePaused) ? View.VISIBLE : View.GONE, default=gone}" android:visibility="@{controlsViewModel.isVideoEnabled &amp;&amp; controlsViewModel.showSwitchCamera &amp;&amp; !conferenceViewModel.isInConference ? View.VISIBLE : View.GONE, default=gone}"
android:contentDescription="@string/content_description_switch_camera" android:contentDescription="@string/content_description_switch_camera"
android:layout_width="50dp" android:layout_width="50dp"
android:layout_height="50dp" android:layout_height="50dp"
@ -244,7 +152,7 @@
<ImageView <ImageView
android:onClick="@{() -> viewModel.takeScreenshot()}" android:onClick="@{() -> viewModel.takeScreenshot()}"
android:enabled="@{!viewModel.callPausedByRemote}" android:enabled="@{!viewModel.callPausedByRemote}"
android:visibility="@{controlsViewModel.isVideoEnabled &amp;&amp; controlsViewModel.takeScreenshotEnabled &amp;&amp; (viewModel.conferenceCalls.size() == 0 || viewModel.isConferencePaused) ? View.VISIBLE : View.GONE, default=gone}" android:visibility="@{controlsViewModel.isVideoEnabled &amp;&amp; controlsViewModel.takeScreenshotEnabled &amp;&amp; !conferenceViewModel.isInConference ? View.VISIBLE : View.GONE, default=gone}"
android:contentDescription="@string/content_description_take_screenshot" android:contentDescription="@string/content_description_take_screenshot"
android:layout_width="50dp" android:layout_width="50dp"
android:layout_height="50dp" android:layout_height="50dp"

View file

@ -1,79 +1,89 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android" <layout xmlns:tools="http://schemas.android.com/tools"
xmlns:tools="http://schemas.android.com/tools" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto">
<data> <data>
<import type="android.view.View" /> <import type="android.view.View" />
<variable <variable
name="viewModel" name="controlsViewModel"
type="org.linphone.activities.call.viewmodels.CallViewModel" /> type="org.linphone.activities.call.viewmodels.ControlsViewModel" />
<variable
name="conferenceViewModel"
type="org.linphone.activities.call.viewmodels.ConferenceViewModel" />
</data> </data>
<LinearLayout <LinearLayout
android:visibility="@{!conferenceViewModel.isInConference || conferenceViewModel.isConferencePaused ? View.GONE : View.VISIBLE}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="70dp" android:layout_height="wrap_content"
android:background="?attr/backgroundColor"
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="60dp">
android:orientation="horizontal"
android:layout_margin="10dp">
<org.linphone.contact.ContactAvatarView <TextView
android:id="@+id/avatar"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="center" android:layout_centerVertical="true"
app:viewModel="@{viewModel}" android:paddingLeft="10dp"
tools:layout="@layout/contact_avatar" /> android:textColor="?attr/primaryTextColor"
android:textSize="30sp"
<LinearLayout android:text="@string/call_conference_title" />
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:paddingLeft="5dp"
android:paddingRight="10dp"
android:orientation="vertical">
<org.linphone.views.MarqueeTextView
android:text="@{viewModel.contact.fullName ?? viewModel.displayName}"
style="@style/contact_name_list_cell_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|left"
android:singleLine="true"/>
<Chronometer
android:id="@+id/call_timer"
android:textColor="?attr/accentColor"
android:textSize="16sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical|right" />
</LinearLayout>
<ImageView <ImageView
android:onClick="@{() -> viewModel.removeFromConference()}" android:onClick="@{() -> controlsViewModel.switchCamera()}"
android:contentDescription="@string/content_description_remove_from_conference" android:visibility="@{controlsViewModel.isVideoEnabled ? View.VISIBLE : View.GONE}"
android:layout_width="30dp" android:contentDescription="@string/content_description_switch_camera"
android:layout_height="30dp" android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginRight="10dp" android:layout_marginRight="10dp"
android:layout_gravity="center_vertical" android:layout_toLeftOf="@id/pause_conference"
android:layout_centerVertical="true"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:gravity="center_vertical" android:padding="10dp"
android:src="@drawable/conference_exit_default" /> android:scaleType="fitCenter"
android:background="@drawable/round_button_background"
android:src="@drawable/camera_switch" />
</LinearLayout> <ImageView
android:id="@+id/pause_conference"
android:onClick="@{() -> conferenceViewModel.pauseConference()}"
android:contentDescription="@string/content_description_pause_conference"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginRight="10dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:adjustViewBounds="true"
android:padding="10dp"
android:scaleType="fitCenter"
android:background="@drawable/round_button_background"
android:src="@drawable/call_pause" />
</RelativeLayout>
<View <View
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="1dp" android:layout_height="1dp"
android:background="?attr/dividerColor" /> android:background="?attr/dividerColor" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:entries="@{conferenceViewModel.conferenceParticipants}"
app:layout="@{@layout/call_conference_cell}"/>
</ScrollView>
</LinearLayout> </LinearLayout>
</layout> </layout>

View file

@ -5,10 +5,10 @@
<data> <data>
<variable <variable
name="data" name="data"
type="org.linphone.activities.call.viewmodels.CallViewModel" /> type="org.linphone.activities.call.viewmodels.ConferenceParticipantViewModel" />
</data> </data>
<org.linphone.activities.call.views.ConferenceCallView <org.linphone.activities.call.views.ConferenceParticipantView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
bind:viewModel="@{data}"/> bind:viewModel="@{data}"/>

View file

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<import type="android.view.View" />
<variable
name="viewModel"
type="org.linphone.activities.call.viewmodels.ConferenceParticipantViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="70dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_margin="10dp">
<org.linphone.contact.ContactAvatarView
android:id="@+id/avatar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
app:viewModel="@{viewModel}"
tools:layout="@layout/contact_avatar" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:paddingLeft="5dp"
android:paddingRight="10dp"
android:orientation="vertical">
<org.linphone.views.MarqueeTextView
android:text="@{viewModel.contact.fullName ?? viewModel.displayName}"
style="@style/contact_name_list_cell_font"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|left"
android:singleLine="true"/>
<Chronometer
android:id="@+id/call_timer"
android:textColor="?attr/accentColor"
android:textSize="16sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical|right" />
</LinearLayout>
<ImageView
android:onClick="@{() -> viewModel.removeFromConference()}"
android:visibility="@{viewModel.isMeAdmin ? View.VISIBLE : View.GONE, default=gone}"
android:contentDescription="@string/content_description_remove_from_conference"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginRight="10dp"
android:layout_gravity="center_vertical"
android:adjustViewBounds="true"
android:gravity="center_vertical"
android:src="@drawable/conference_remove_participant" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dividerColor" />
</LinearLayout>
</layout>

View file

@ -11,6 +11,9 @@
<variable <variable
name="controlsViewModel" name="controlsViewModel"
type="org.linphone.activities.call.viewmodels.ControlsViewModel" /> type="org.linphone.activities.call.viewmodels.ControlsViewModel" />
<variable
name="conferenceViewModel"
type="org.linphone.activities.call.viewmodels.ConferenceViewModel" />
</data> </data>
<RelativeLayout <RelativeLayout
@ -25,7 +28,7 @@
<LinearLayout <LinearLayout
android:id="@+id/active_call_header" android:id="@+id/active_call_header"
android:visibility="@{viewModel.currentCallViewModel == null ? View.GONE : View.VISIBLE}" android:visibility="@{viewModel.currentCallViewModel == null || conferenceViewModel.isInConference() ? View.GONE : View.VISIBLE}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
@ -53,75 +56,16 @@
</LinearLayout> </LinearLayout>
<LinearLayout <include layout="@layout/call_conference"
android:visibility="@{viewModel.conferenceCalls.size() == 0 || viewModel.isConferencePaused ? View.GONE : View.VISIBLE, default=gone}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentTop="true" android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:background="?attr/backgroundColor" app:controlsViewModel="@{controlsViewModel}"
android:orientation="vertical"> app:conferenceViewModel="@{conferenceViewModel}" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:paddingLeft="10dp"
android:textColor="?attr/primaryTextColor"
android:textSize="30sp"
android:text="@string/call_conference_title" />
<ImageView
android:onClick="@{() -> controlsViewModel.switchCamera()}"
android:visibility="@{controlsViewModel.isVideoEnabled ? View.VISIBLE : View.GONE, default=gone}"
android:contentDescription="@string/content_description_switch_camera"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_toLeftOf="@id/pause_conference"
android:adjustViewBounds="true"
android:padding="10dp"
android:scaleType="fitCenter"
android:background="@drawable/round_button_background"
android:src="@drawable/camera_switch" />
<ImageView
android:id="@+id/pause_conference"
android:onClick="@{() -> viewModel.pauseConference()}"
android:contentDescription="@string/content_description_pause_conference"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginRight="10dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:adjustViewBounds="true"
android:padding="10dp"
android:scaleType="fitCenter"
android:background="@drawable/round_button_background"
android:src="@drawable/call_pause" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dividerColor" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:orientation="vertical"
app:entries="@{viewModel.conferenceCalls}"
app:layout="@{@layout/call_conference_cell}"/>
</LinearLayout>
<org.linphone.contact.BigContactAvatarView <org.linphone.contact.BigContactAvatarView
android:visibility="@{controlsViewModel.isVideoEnabled ? View.GONE : View.VISIBLE, default=gone}" android:visibility="@{controlsViewModel.isVideoEnabled || conferenceViewModel.isInConference ? View.GONE : View.VISIBLE, default=gone}"
android:id="@+id/avatar" android:id="@+id/avatar"
android:layout_width="200dp" android:layout_width="200dp"
android:layout_height="200dp" android:layout_height="200dp"
@ -148,7 +92,7 @@
android:src="@drawable/waiting_time" /> android:src="@drawable/waiting_time" />
<TextView <TextView
android:textColor="?attr/secondaryTextColor" android:textColor="@color/white_color"
android:textSize="15sp" android:textSize="15sp"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -169,51 +113,15 @@
app:entries="@{viewModel.pausedCalls}" app:entries="@{viewModel.pausedCalls}"
app:layout="@{@layout/call_paused_cell}" /> app:layout="@{@layout/call_paused_cell}" />
<LinearLayout <include layout="@layout/conference_paused"
android:visibility="@{viewModel.isConferencePaused &amp;&amp; viewModel.conferenceCalls.size() > 1 ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="50dp" android:layout_height="50dp"
android:layout_above="@id/paused_calls" android:layout_above="@id/paused_calls"
android:alpha="0.5" app:conferenceViewModel="@{conferenceViewModel}" />
android:background="?attr/accentColor"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="5dp">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:contentDescription="@string/content_description_start_conference"
android:src="@drawable/options_start_conference" />
<TextView
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical|left"
android:singleLine="true"
android:ellipsize="end"
android:paddingLeft="20dp"
android:paddingRight="10dp"
android:textColor="?attr/secondaryTextColor"
android:textSize="15sp"
android:text="@string/call_conference_title" />
<ImageView
android:onClick="@{() -> viewModel.resumeConference()}"
android:layout_width="40dp"
android:layout_height="40dp"
android:gravity="center_vertical"
android:contentDescription="@string/content_description_resume_conference"
android:background="@drawable/round_button_background"
android:padding="10dp"
android:src="@drawable/call_pause" />
</LinearLayout>
<ImageView <ImageView
android:onClick="@{() -> viewModel.currentCallViewModel.pause()}" android:onClick="@{() -> viewModel.currentCallViewModel.pause()}"
android:visibility="@{viewModel.currentCallViewModel == null ? View.GONE : View.VISIBLE}" android:visibility="@{viewModel.currentCallViewModel == null || conferenceViewModel.isInConference ? View.GONE : View.VISIBLE}"
android:selected="@{viewModel.currentCallViewModel.isPaused ?? false}" android:selected="@{viewModel.currentCallViewModel.isPaused ?? false}"
android:enabled="@{!viewModel.callPausedByRemote &amp;&amp; controlsViewModel.isPauseEnabled}" android:enabled="@{!viewModel.callPausedByRemote &amp;&amp; controlsViewModel.isPauseEnabled}"
android:contentDescription="@string/content_description_pause_call" android:contentDescription="@string/content_description_pause_call"
@ -230,7 +138,7 @@
android:id="@+id/switch_camera" android:id="@+id/switch_camera"
android:onClick="@{() -> controlsViewModel.switchCamera()}" android:onClick="@{() -> controlsViewModel.switchCamera()}"
android:enabled="@{!viewModel.callPausedByRemote}" android:enabled="@{!viewModel.callPausedByRemote}"
android:visibility="@{controlsViewModel.isVideoEnabled &amp;&amp; controlsViewModel.showSwitchCamera &amp;&amp; (viewModel.conferenceCalls.size() == 0 || viewModel.isConferencePaused) ? View.VISIBLE : View.GONE, default=gone}" android:visibility="@{controlsViewModel.isVideoEnabled &amp;&amp; controlsViewModel.showSwitchCamera &amp;&amp; !conferenceViewModel.isInConference ? View.VISIBLE : View.GONE, default=gone}"
android:contentDescription="@string/content_description_switch_camera" android:contentDescription="@string/content_description_switch_camera"
android:layout_width="50dp" android:layout_width="50dp"
android:layout_height="50dp" android:layout_height="50dp"
@ -244,7 +152,7 @@
<ImageView <ImageView
android:onClick="@{() -> viewModel.takeScreenshot()}" android:onClick="@{() -> viewModel.takeScreenshot()}"
android:enabled="@{!viewModel.callPausedByRemote}" android:enabled="@{!viewModel.callPausedByRemote}"
android:visibility="@{controlsViewModel.isVideoEnabled &amp;&amp; controlsViewModel.takeScreenshotEnabled &amp;&amp; (viewModel.conferenceCalls.size() == 0 || viewModel.isConferencePaused) ? View.VISIBLE : View.GONE, default=gone}" android:visibility="@{controlsViewModel.isVideoEnabled &amp;&amp; controlsViewModel.takeScreenshotEnabled &amp;&amp; !conferenceViewModel.isInConference ? View.VISIBLE : View.GONE, default=gone}"
android:contentDescription="@string/content_description_take_screenshot" android:contentDescription="@string/content_description_take_screenshot"
android:layout_width="50dp" android:layout_width="50dp"
android:layout_height="50dp" android:layout_height="50dp"

View file

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<import type="android.view.View" />
<variable
name="conferenceViewModel"
type="org.linphone.activities.call.viewmodels.ConferenceViewModel" />
</data>
<LinearLayout
android:visibility="@{conferenceViewModel.isConferencePaused &amp;&amp; conferenceViewModel.isInConference ? View.VISIBLE : View.GONE}"
android:layout_width="match_parent"
android:layout_height="50dp"
android:alpha="0.5"
android:background="?attr/accentColor"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="5dp">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:padding="5dp"
android:contentDescription="@string/content_description_start_conference"
android:src="@drawable/conference" />
<TextView
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical|left"
android:singleLine="true"
android:ellipsize="end"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:textColor="?attr/secondaryTextColor"
android:textSize="21sp"
android:text="@string/call_conference_title" />
<ImageView
android:onClick="@{() -> conferenceViewModel.resumeConference()}"
android:layout_width="40dp"
android:layout_height="40dp"
android:gravity="center_vertical"
android:contentDescription="@string/content_description_resume_conference"
android:background="@drawable/round_button_background"
android:padding="10dp"
android:src="@drawable/call_pause" />
</LinearLayout>
</layout>