Reworked call UI a bit more

This commit is contained in:
Sylvain Berfini 2022-03-07 14:37:28 +01:00
parent 9fc2009b76
commit c93ea7a851
7 changed files with 234 additions and 302 deletions

View file

@ -43,7 +43,6 @@ import org.linphone.core.Call
import org.linphone.core.tools.Log
import org.linphone.databinding.VoipActivityBinding
import org.linphone.mediastream.Version
import org.linphone.utils.Event
import org.linphone.utils.PermissionHelper
class CallActivity : ProximitySensorActivity() {
@ -92,7 +91,7 @@ class CallActivity : ProximitySensorActivity() {
this
) {
it.consume { permission ->
Log.i("[Call] Asking for $permission permission")
Log.i("[Call Activity] Asking for $permission permission")
requestPermissions(arrayOf(permission), 0)
}
}
@ -119,10 +118,10 @@ class CallActivity : ProximitySensorActivity() {
this
) { callData ->
if (callData.call.conference == null) {
Log.i("[Call] Current call isn't linked to a conference, changing fragment")
Log.i("[Call Activity] Current call isn't linked to a conference, changing fragment")
navigateToActiveCall()
} else {
Log.i("[Call] Current call is linked to a conference, changing fragment")
Log.i("[Call Activity] Current call is linked to a conference, changing fragment")
navigateToConferenceCall()
}
}
@ -131,10 +130,10 @@ class CallActivity : ProximitySensorActivity() {
this
) { exists ->
if (exists) {
Log.i("[Call] Found active conference, changing fragment")
Log.i("[Call Activity] Found active conference, changing fragment")
navigateToConferenceCall()
} else {
Log.i("[Call] Conference no longer exists, changing fragment")
Log.i("[Call Activity] Conference no longer exists, changing fragment")
navigateToActiveCall()
}
}
@ -143,7 +142,7 @@ class CallActivity : ProximitySensorActivity() {
this
) { paused ->
if (!paused) {
Log.i("[Call] Entered conference, make sure conference fragment is active")
Log.i("[Call Activity] Entered conference, make sure conference fragment is active")
navigateToConferenceCall()
}
}
@ -157,7 +156,7 @@ class CallActivity : ProximitySensorActivity() {
super.onUserLeaveHint()
if (coreContext.core.currentCall?.currentParams?.isVideoEnabled == true) {
Log.i("[Call] Entering PiP mode")
Log.i("[Call Activity] Entering PiP mode")
Compatibility.enterPipMode(this)
}
}
@ -166,7 +165,7 @@ class CallActivity : ProximitySensorActivity() {
isInPictureInPictureMode: Boolean,
newConfig: Configuration
) {
Log.i("[Call] Activity is in PiP mode? $isInPictureInPictureMode")
Log.i("[Call Activity] Is in PiP mode? $isInPictureInPictureMode")
if (::controlsViewModel.isInitialized) {
// To hide UI except for TextureViews
controlsViewModel.pipMode.value = isInPictureInPictureMode
@ -177,7 +176,7 @@ class CallActivity : ProximitySensorActivity() {
super.onResume()
if (coreContext.core.callsNb == 0) {
Log.w("[Call] Resuming but no call found...")
Log.w("[Call Activity] Resuming but no call found...")
if (isTaskRoot) {
// When resuming app from recent tasks make sure MainActivity will be launched if there is no call
val intent = Intent()
@ -227,19 +226,19 @@ class CallActivity : ProximitySensorActivity() {
val permissionsRequiredList = arrayListOf<String>()
if (!PermissionHelper.get().hasRecordAudioPermission()) {
Log.i("[Call] Asking for RECORD_AUDIO permission")
Log.i("[Call Activity] Asking for RECORD_AUDIO permission")
permissionsRequiredList.add(Manifest.permission.RECORD_AUDIO)
}
if (callsViewModel.currentCallData.value?.call?.currentParams?.isVideoEnabled == true &&
!PermissionHelper.get().hasCameraPermission()
) {
Log.i("[Call] Asking for CAMERA permission")
Log.i("[Call Activity] Asking for CAMERA permission")
permissionsRequiredList.add(Manifest.permission.CAMERA)
}
if (Version.sdkAboveOrEqual(Version.API31_ANDROID_12) && !PermissionHelper.get().hasBluetoothConnectPermission()) {
Log.i("[Call] Asking for BLUETOOTH_CONNECT permission")
Log.i("[Call Activity] Asking for BLUETOOTH_CONNECT permission")
permissionsRequiredList.add(Compatibility.BLUETOOTH_CONNECT)
}
@ -259,15 +258,15 @@ class CallActivity : ProximitySensorActivity() {
for (i in permissions.indices) {
when (permissions[i]) {
Manifest.permission.RECORD_AUDIO -> if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
Log.i("[Call] RECORD_AUDIO permission has been granted")
Log.i("[Call Activity] RECORD_AUDIO permission has been granted")
controlsViewModel.updateMicState()
}
Manifest.permission.CAMERA -> if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
Log.i("[Call] CAMERA permission has been granted")
Log.i("[Call Activity] CAMERA permission has been granted")
coreContext.core.reloadVideoDevices()
}
Compatibility.BLUETOOTH_CONNECT -> if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
Log.i("[Call] BLUETOOTH_CONNECT permission has been granted")
Log.i("[Call Activity] BLUETOOTH_CONNECT permission has been granted")
}
}
}
@ -282,6 +281,7 @@ class CallActivity : ProximitySensorActivity() {
private fun updateConstraintSetDependingOnFoldingState() {
val feature = foldingFeature ?: return
controlsViewModel.foldingStateChangedEvent.value = Event(feature.state)
Log.i("[Call Activity] Folding feature state changed: $feature.state")
controlsViewModel.foldingState.value = feature.state
}
}

View file

@ -25,7 +25,6 @@ import android.os.Bundle
import android.os.SystemClock
import android.view.View
import android.widget.Chronometer
import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
@ -95,18 +94,15 @@ class ConferenceCallFragment : GenericFragment<VoipConferenceCallFragmentBinding
startTimer(R.id.active_speaker_conference_timer)
if (conferenceViewModel.conferenceExists.value == true) {
Log.i("[Call] Local participant is in conference and current layout is active speaker, updating Core's native window id")
Log.i("[Conference Call] Local participant is in conference and current layout is active speaker, updating Core's native window id")
val layout =
binding.root.findViewById<RelativeLayout>(R.id.conference_active_speaker_layout)
val window =
layout?.findViewById<RoundCornersTextureView>(R.id.conference_active_speaker_remote_video)
coreContext.core.nativeVideoWindowId = window
} else {
Log.i("[Call] Either not in conference or current layout isn't active speaker, updating Core's native window id")
val layout = binding.root.findViewById<LinearLayout>(R.id.remote_layout)
val window =
layout?.findViewById<RoundCornersTextureView>(R.id.remote_video_surface)
coreContext.core.nativeVideoWindowId = window
Log.i("[Conference Call] Either not in conference or current layout isn't active speaker, updating Core's native window id")
coreContext.core.nativeVideoWindowId = null
}
}
}
@ -174,12 +170,10 @@ class ConferenceCallFragment : GenericFragment<VoipConferenceCallFragmentBinding
}
}
controlsViewModel.foldingStateChangedEvent.observe(
controlsViewModel.foldingState.observe(
viewLifecycleOwner
) {
it.consume { state ->
updateHingeRelatedConstraints(state)
}
) { state ->
updateHingeRelatedConstraints(state)
}
callsViewModel.callUpdateEvent.observe(
@ -188,7 +182,7 @@ class ConferenceCallFragment : GenericFragment<VoipConferenceCallFragmentBinding
it.consume { call ->
val conference = call.conference
if (conference != null && conferenceViewModel.conference.value == null) {
Log.i("[Call] Found conference attached to call and no conference in dedicated view model, init & configure it")
Log.i("[Conference Call] Found conference attached to call and no conference in dedicated view model, init & configure it")
conferenceViewModel.initConference(conference)
conferenceViewModel.configureConference(conference)
}
@ -209,21 +203,21 @@ class ConferenceCallFragment : GenericFragment<VoipConferenceCallFragmentBinding
}
binding.stubbedConferenceActiveSpeakerLayout.setOnInflateListener { _, inflated ->
Log.i("[Call] Active speaker conference layout inflated")
Log.i("[Conference Call] Active speaker conference layout inflated")
val binding = DataBindingUtil.bind<ViewDataBinding>(inflated)
binding?.lifecycleOwner = viewLifecycleOwner
startTimer(R.id.active_speaker_conference_timer)
}
binding.stubbedConferenceGridLayout.setOnInflateListener { _, inflated ->
Log.i("[Call] Mosaic conference layout inflated")
Log.i("[Conference Call] Mosaic conference layout inflated")
val binding = DataBindingUtil.bind<ViewDataBinding>(inflated)
binding?.lifecycleOwner = viewLifecycleOwner
startTimer(R.id.grid_conference_timer)
}
binding.stubbedConferenceAudioOnlyLayout.setOnInflateListener { _, inflated ->
Log.i("[Call] Audio only conference layout inflated")
Log.i("[Conference Call] Audio only conference layout inflated")
val binding = DataBindingUtil.bind<ViewDataBinding>(inflated)
binding?.lifecycleOwner = viewLifecycleOwner
startTimer(R.id.audio_only_conference_timer)
@ -261,14 +255,14 @@ class ConferenceCallFragment : GenericFragment<VoipConferenceCallFragmentBinding
if (conference.currentParams.isVideoEnabled) {
when {
conference.me.devices.isEmpty() -> {
Log.w("[Call] Conference has video enabled but either our device hasn't joined yet")
Log.w("[Conference Call] Conference has video enabled but either our device hasn't joined yet")
}
conference.me.devices.find { it.getStreamAvailability(StreamType.Video) } != null -> {
Log.i("[Call] Conference has video enabled & our device has video enabled, enabling full screen mode")
Log.i("[Conference Call] Conference has video enabled & our device has video enabled, enabling full screen mode")
controlsViewModel.fullScreenMode.value = true
}
else -> {
Log.w("[Call] Conference has video enabled but our device video is disabled")
Log.w("[Conference Call] Conference has video enabled but our device video is disabled")
}
}
}
@ -290,7 +284,7 @@ class ConferenceCallFragment : GenericFragment<VoipConferenceCallFragmentBinding
private fun startTimer(timerId: Int) {
val timer: Chronometer? = binding.root.findViewById(timerId)
if (timer == null) {
Log.w("[Call] Timer not found, maybe view wasn't inflated yet?")
Log.w("[Conference Call] Timer not found, maybe view wasn't inflated yet?")
return
}
@ -299,13 +293,14 @@ class ConferenceCallFragment : GenericFragment<VoipConferenceCallFragmentBinding
val duration = 1000 * conference.duration // Linphone timestamps are in seconds
timer.base = SystemClock.elapsedRealtime() - duration
} else {
Log.e("[Call] Conference not found, timer will have no base")
Log.e("[Conference Call] Conference not found, timer will have no base")
}
timer.start()
}
private fun updateHingeRelatedConstraints(state: FoldingFeature.State) {
Log.i("[Conference Call] Updating constraint layout hinges")
/*val constraintLayout = binding.constraintLayout
val set = ConstraintSet()
set.clone(constraintLayout)

View file

@ -25,7 +25,6 @@ import android.os.Bundle
import android.os.SystemClock
import android.view.View
import android.widget.Chronometer
import android.widget.LinearLayout
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.navigation.navGraphViewModels
@ -39,11 +38,9 @@ import org.linphone.activities.voip.viewmodels.CallsViewModel
import org.linphone.activities.voip.viewmodels.ConferenceViewModel
import org.linphone.activities.voip.viewmodels.ControlsViewModel
import org.linphone.activities.voip.viewmodels.StatisticsListViewModel
import org.linphone.activities.voip.views.RoundCornersTextureView
import org.linphone.core.*
import org.linphone.core.tools.Log
import org.linphone.databinding.VoipSingleCallFragmentBinding
import org.linphone.mediastream.video.capture.CaptureTextureView
import org.linphone.utils.AppUtils
import org.linphone.utils.DialogUtils
@ -121,12 +118,10 @@ class SingleCallFragment : GenericFragment<VoipSingleCallFragmentBinding>() {
}
}
controlsViewModel.foldingStateChangedEvent.observe(
controlsViewModel.foldingState.observe(
viewLifecycleOwner
) {
it.consume { state ->
updateHingeRelatedConstraints(state)
}
) { state ->
updateHingeRelatedConstraints(state)
}
callsViewModel.callUpdateEvent.observe(
@ -143,7 +138,7 @@ class SingleCallFragment : GenericFragment<VoipSingleCallFragmentBinding>() {
showCallVideoUpdateDialog(call)
}
} else {
Log.w("[Call] Video display & capture are disabled, don't show video dialog")
Log.w("[Single Call] Video display & capture are disabled, don't show video dialog")
}
}
}
@ -162,11 +157,8 @@ class SingleCallFragment : GenericFragment<VoipSingleCallFragmentBinding>() {
}
}
val remoteLayout = binding.root.findViewById<LinearLayout>(R.id.remote_layout)
val remoteVideoView = remoteLayout.findViewById<RoundCornersTextureView>(R.id.remote_video_surface)
coreContext.core.nativeVideoWindowId = remoteVideoView
val localVideoView = remoteLayout.findViewById<CaptureTextureView>(R.id.local_preview_video_surface)
coreContext.core.nativePreviewWindowId = localVideoView
coreContext.core.nativeVideoWindowId = binding.remoteVideoSurface
coreContext.core.nativePreviewWindowId = binding.localPreviewVideoSurface
binding.stubbedAudioRoutes.setOnInflateListener { _, inflated ->
val binding = DataBindingUtil.bind<ViewDataBinding>(inflated)
@ -232,6 +224,7 @@ class SingleCallFragment : GenericFragment<VoipSingleCallFragmentBinding>() {
}
private fun updateHingeRelatedConstraints(state: FoldingFeature.State) {
Log.i("[Single Call] Updating constraint layout hinges")
/*val constraintLayout = binding.constraintLayout
val set = ConstraintSet()
set.clone(constraintLayout)

View file

@ -103,9 +103,7 @@ class ControlsViewModel : ViewModel() {
MutableLiveData<Event<Boolean>>()
}
val foldingStateChangedEvent: MutableLiveData<Event<FoldingFeature.State>> by lazy {
MutableLiveData<Event<FoldingFeature.State>>()
}
val foldingState = MutableLiveData<FoldingFeature.State>()
private val nonEarpieceOutputAudioDevice = MutableLiveData<Boolean>()
@ -144,6 +142,9 @@ class ControlsViewModel : ViewModel() {
isOutgoingEarlyMedia.value = state == Call.State.OutgoingEarlyMedia
if (state == Call.State.StreamsRunning) {
if (!call.currentParams.isVideoEnabled && fullScreenMode.value == true) {
fullScreenMode.value = false
}
isVideoUpdateInProgress.value = false
} else if (state == Call.State.PausedByRemote) {
fullScreenMode.value = false
@ -224,6 +225,7 @@ class ControlsViewModel : ViewModel() {
extraButtonsMenuTranslateY.value = AppUtils.getDimension(R.dimen.voip_call_extra_buttons_translate_y)
audioRoutesMenuTranslateY.value = AppUtils.getDimension(R.dimen.voip_audio_routes_menu_translate_y)
audioRoutesSelected.value = false
foldingState.value = FoldingFeature.State.FLAT
nonEarpieceOutputAudioDevice.value = coreContext.core.outputAudioDevice?.type != AudioDevice.Type.Earpiece
proximitySensorEnabled.value = shouldProximitySensorBeEnabled()

View file

@ -579,11 +579,11 @@ fun VoiceRecordProgressBar.setSecProgressTint(color: Int) {
}
@BindingAdapter("android:layout_margin")
fun ConstraintLayout.setMargins(margins: Float) {
val params = layoutParams as ConstraintLayout.LayoutParams
fun setConstraintLayoutMargins(view: View, margins: Float) {
val params = view.layoutParams as ConstraintLayout.LayoutParams
val m = margins.toInt()
params.setMargins(m, m, m, m)
layoutParams = params
view.layoutParams = params
}
@BindingAdapter("android:onTouch")

View file

@ -1,235 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<variable
name="viewModel"
type="org.linphone.activities.voip.data.CallData" />
<variable
name="controlsViewModel"
type="org.linphone.activities.voip.viewmodels.ControlsViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:visibility="@{controlsViewModel.fullScreenMode || controlsViewModel.pipMode ? View.GONE : View.VISIBLE}"
android:layout_width="match_parent"
android:layout_height="@dimen/voip_call_header_height"
android:layout_marginBottom="10dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/call_header_title"
android:text="@{viewModel.contact.fullName ?? viewModel.displayName}"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/call_header_title"
android:text=" - "/>
<Chronometer
android:id="@+id/active_call_timer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/call_header_title" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
style="@style/call_header_subtitle"
android:text="@{viewModel.address}" />
</LinearLayout>
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:visibility="@{viewModel.isRemotelyRecorded ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_max="@dimen/voip_views_max_width"
android:background="@drawable/shape_remote_recording_background">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/voip_remote_recording"
android:contentDescription="@null"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
style="@style/call_remote_recording_font"
android:layout_marginStart="10dp"
android:text="@string/call_remote_recording"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@drawable/shape_remote_background"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintWidth_max="@dimen/voip_views_max_width">
<include
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHeight_max="200dp"
app:data="@{viewModel}"
layout="@layout/voip_contact_avatar"/>
<TextView
android:text="@{viewModel.contact.fullName ?? viewModel.displayName}"
style="@style/call_remote_name_font"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginStart="10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<org.linphone.activities.voip.views.RoundCornersTextureView
android:id="@+id/remote_video_surface"
android:onClick="@{() -> controlsViewModel.toggleFullScreen()}"
android:visibility="@{controlsViewModel.isVideoEnabled &amp;&amp; controlsViewModel.isVideoSendReceive &amp;&amp; !viewModel.isRemotelyPaused ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintWidth_max="@dimen/voip_views_max_width" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintWidth_max="@dimen/voip_views_max_width">
<ImageView
android:onClick="@{() -> viewModel.toggleRecording()}"
android:selected="@{viewModel.isRecording}"
android:visibility="@{controlsViewModel.fullScreenMode || controlsViewModel.pipMode ? View.GONE : View.VISIBLE}"
android:layout_height="40dp"
android:layout_width="40dp"
android:background="@drawable/button_call_recording_background"
android:src="@drawable/icon_call_record"
android:contentDescription="@string/content_description_toggle_recording"
android:padding="7dp"
android:layout_margin="10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:onClick="@{() -> viewModel.togglePause()}"
android:selected="@{viewModel.isPaused}"
android:enabled="@{viewModel.isPaused || viewModel.canBePaused}"
android:visibility="@{controlsViewModel.fullScreenMode || controlsViewModel.pipMode ? View.GONE : View.VISIBLE}"
android:layout_height="40dp"
android:layout_width="40dp"
android:background="@drawable/button_toggle_background"
android:src="@drawable/icon_pause"
android:contentDescription="@string/content_description_pause_call"
android:padding="5dp"
android:layout_margin="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:onTouch="@{controlsViewModel.previewTouchListener}"
android:visibility="@{controlsViewModel.isVideoEnabled &amp;&amp; !viewModel.isRemotelyPaused ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="25dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<org.linphone.activities.voip.views.RoundCornersTextureView
android:id="@+id/local_preview_video_surface"
android:layout_size="@{controlsViewModel.pipMode ? @dimen/video_preview_pip_max_size : @dimen/video_preview_max_size}"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintHeight_max="200dp"
app:layout_constraintWidth_max="200dp"
app:alignTopRight="true"
app:displayMode="black_bars"
tools:ignore="MissingConstraints" />
<ImageView
android:onClick="@{() -> controlsViewModel.switchCamera()}"
android:visibility="@{controlsViewModel.isSwitchCameraAvailable &amp;&amp; !controlsViewModel.pipMode ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:padding="10dp"
android:src="@drawable/icon_call_camera_switch"
android:contentDescription="@string/content_description_switch_camera"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</layout>

View file

@ -31,20 +31,197 @@
android:layout_height="match_parent"
android:background="@{controlsViewModel.fullScreenMode ? @color/black_color : @color/transparent_color}">
<LinearLayout
android:id="@+id/call_header"
android:visibility="@{controlsViewModel.fullScreenMode || controlsViewModel.pipMode ? View.GONE : View.VISIBLE}"
android:layout_width="0dp"
android:layout_height="@dimen/voip_call_header_height"
android:layout_margin="10dp"
android:gravity="center_vertical"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/call_header_title"
android:text="@{callsViewModel.currentCallData.contact.fullName ?? callsViewModel.currentCallData.displayName}"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/call_header_title"
android:text=" - "/>
<Chronometer
android:id="@+id/active_call_timer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/call_header_title" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
style="@style/call_header_subtitle"
android:text="@{callsViewModel.currentCallData.address}" />
</LinearLayout>
<LinearLayout
android:id="@+id/remotely_recorded"
android:visibility="@{callsViewModel.currentCallData.isRemotelyRecorded ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/call_header"
app:layout_constraintWidth_max="@dimen/voip_views_max_width"
android:background="@drawable/shape_remote_recording_background">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/voip_remote_recording"
android:contentDescription="@null"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
style="@style/call_remote_recording_font"
android:layout_marginStart="10dp"
android:text="@string/call_remote_recording"/>
</LinearLayout>
<androidx.constraintlayout.widget.Barrier
android:id="@+id/call_header_barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="call_header,remotely_recorded" />
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_margin="@{controlsViewModel.fullScreenMode || controlsViewModel.pipMode ? @dimen/voip_remote_margin_full_screen : @dimen/voip_remote_margin, default=@dimen/voip_remote_margin}"
android:background="@drawable/shape_remote_background"
app:layout_constraintTop_toBottomOf="@id/call_header_barrier"
app:layout_constraintBottom_toTopOf="@id/primary_buttons"
android:layout_margin="@{controlsViewModel.fullScreenMode || controlsViewModel.pipMode ? @dimen/voip_remote_margin_full_screen : @dimen/voip_remote_margin, default=@dimen/voip_remote_margin}">
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintWidth_max="@dimen/voip_views_max_width">
<include
android:id="@+id/remote_layout"
layout="@layout/voip_call"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:viewModel="@{callsViewModel.currentCallData}"
app:controlsViewModel="@{controlsViewModel}"/>
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_margin="10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHeight_max="200dp"
app:data="@{callsViewModel.currentCallData}"
layout="@layout/voip_contact_avatar"/>
<TextView
android:text="@{callsViewModel.currentCallData.contact.fullName ?? callsViewModel.currentCallData.displayName}"
style="@style/call_remote_name_font"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginStart="10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<org.linphone.activities.voip.views.RoundCornersTextureView
android:id="@+id/remote_video_surface"
android:onClick="@{() -> controlsViewModel.toggleFullScreen()}"
android:visibility="@{controlsViewModel.isVideoEnabled &amp;&amp; controlsViewModel.isVideoSendReceive &amp;&amp; !callsViewModel.currentCallData.isRemotelyPaused ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
<ImageView
android:onClick="@{() -> callsViewModel.currentCallData.toggleRecording()}"
android:selected="@{callsViewModel.currentCallData.isRecording}"
android:visibility="@{controlsViewModel.fullScreenMode || controlsViewModel.pipMode ? View.GONE : View.VISIBLE}"
android:layout_height="40dp"
android:layout_width="40dp"
android:background="@drawable/button_call_recording_background"
android:src="@drawable/icon_call_record"
android:contentDescription="@string/content_description_toggle_recording"
android:padding="7dp"
android:layout_margin="10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:onClick="@{() -> callsViewModel.currentCallData.togglePause()}"
android:selected="@{callsViewModel.currentCallData.isPaused}"
android:enabled="@{callsViewModel.currentCallData.isPaused || callsViewModel.currentCallData.canBePaused}"
android:visibility="@{controlsViewModel.fullScreenMode || controlsViewModel.pipMode ? View.GONE : View.VISIBLE}"
android:layout_height="40dp"
android:layout_width="40dp"
android:background="@drawable/button_toggle_background"
android:src="@drawable/icon_pause"
android:contentDescription="@string/content_description_pause_call"
android:padding="5dp"
android:layout_margin="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:onTouch="@{controlsViewModel.previewTouchListener}"
android:visibility="@{controlsViewModel.isVideoEnabled &amp;&amp; !callsViewModel.currentCallData.isRemotelyPaused ? View.VISIBLE : View.GONE}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="25dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="@id/primary_buttons">
<org.linphone.activities.voip.views.RoundCornersTextureView
android:id="@+id/local_preview_video_surface"
android:layout_size="@{controlsViewModel.pipMode ? @dimen/video_preview_pip_max_size : @dimen/video_preview_max_size}"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintHeight_max="200dp"
app:layout_constraintWidth_max="200dp"
app:alignTopRight="true"
app:displayMode="black_bars"
bind:ignore="MissingConstraints" />
<ImageView
android:onClick="@{() -> controlsViewModel.switchCamera()}"
android:visibility="@{controlsViewModel.isSwitchCameraAvailable &amp;&amp; !controlsViewModel.pipMode ? View.VISIBLE : View.GONE, default=gone}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:padding="10dp"
android:src="@drawable/icon_call_camera_switch"
android:contentDescription="@string/content_description_switch_camera"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>