diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/CallParticipantsState.java b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/CallParticipantsState.java index 4911de49fe..f3b68e8342 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/CallParticipantsState.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/CallParticipantsState.java @@ -34,7 +34,8 @@ public final class CallParticipantsState { WebRtcLocalRenderState.GONE, false, false, - false); + false, + 0); private final WebRtcViewModel.State callState; private final WebRtcViewModel.GroupCallState groupCallState; @@ -45,6 +46,7 @@ public final class CallParticipantsState { private final boolean isInPipMode; private final boolean showVideoForOutgoing; private final boolean isViewingFocusedParticipant; + private final long remoteDevicesCount; public CallParticipantsState(@NonNull WebRtcViewModel.State callState, @NonNull WebRtcViewModel.GroupCallState groupCallState, @@ -54,7 +56,8 @@ public final class CallParticipantsState { @NonNull WebRtcLocalRenderState localRenderState, boolean isInPipMode, boolean showVideoForOutgoing, - boolean isViewingFocusedParticipant) + boolean isViewingFocusedParticipant, + long remoteDevicesCount) { this.callState = callState; this.groupCallState = groupCallState; @@ -65,6 +68,7 @@ public final class CallParticipantsState { this.isInPipMode = isInPipMode; this.showVideoForOutgoing = showVideoForOutgoing; this.isViewingFocusedParticipant = isViewingFocusedParticipant; + this.remoteDevicesCount = remoteDevicesCount; } public @NonNull WebRtcViewModel.State getCallState() { @@ -154,6 +158,10 @@ public final class CallParticipantsState { return Stream.of(getAllRemoteParticipants()).anyMatch(p -> p.getVideoSink().needsNewRequestingSize()); } + public long getRemoteDevicesCount() { + return remoteDevicesCount; + } + public static @NonNull CallParticipantsState update(@NonNull CallParticipantsState oldState, @NonNull WebRtcViewModel webRtcViewModel, boolean enableVideo) @@ -186,7 +194,8 @@ public final class CallParticipantsState { localRenderState, oldState.isInPipMode, newShowVideoForOutgoing, - oldState.isViewingFocusedParticipant); + oldState.isViewingFocusedParticipant, + webRtcViewModel.getRemoteDevicesCount()); } public static @NonNull CallParticipantsState update(@NonNull CallParticipantsState oldState, boolean isInPip) { @@ -208,7 +217,8 @@ public final class CallParticipantsState { localRenderState, isInPip, oldState.showVideoForOutgoing, - oldState.isViewingFocusedParticipant); + oldState.isViewingFocusedParticipant, + oldState.remoteDevicesCount); } public static @NonNull CallParticipantsState update(@NonNull CallParticipantsState oldState, @NonNull SelectedPage selectedPage) { @@ -230,7 +240,8 @@ public final class CallParticipantsState { localRenderState, oldState.isInPipMode, oldState.showVideoForOutgoing, - selectedPage == SelectedPage.FOCUSED); + selectedPage == SelectedPage.FOCUSED, + oldState.remoteDevicesCount); } private static @NonNull WebRtcLocalRenderState determineLocalRenderMode(@NonNull CallParticipant localParticipant, diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallView.java b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallView.java index 96d609a8c6..9e476b2486 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallView.java @@ -96,6 +96,7 @@ public class WebRtcCallView extends FrameLayout { private MaterialButton startCall; private TextView participantCount; private Stub groupCallSpeakerHint; + private Stub groupCallFullStub; private int pagerBottomMarginDp; private boolean controlsVisible = true; @@ -152,6 +153,7 @@ public class WebRtcCallView extends FrameLayout { toolbar = findViewById(R.id.call_screen_toolbar); startCall = findViewById(R.id.call_screen_start_call_start_call); groupCallSpeakerHint = new Stub<>(findViewById(R.id.call_screen_group_call_speaker_hint)); + groupCallFullStub = new Stub<>(findViewById(R.id.group_call_call_full_view)); View topGradient = findViewById(R.id.call_screen_header_gradient); View decline = findViewById(R.id.call_screen_decline_call); @@ -269,7 +271,7 @@ public class WebRtcCallView extends FrameLayout { if (state.getGroupCallState().isNotIdle() && participantCount != null) { boolean includeSelf = state.getGroupCallState() == WebRtcViewModel.GroupCallState.CONNECTED_AND_JOINED; - participantCount.setText(String.valueOf(state.getAllRemoteParticipants().size() + (includeSelf ? 1 : 0))); + participantCount.setText(String.valueOf(state.getRemoteDevicesCount() + (includeSelf ? 1 : 0))); } pagerAdapter.submitList(pages); @@ -421,7 +423,14 @@ public class WebRtcCallView extends FrameLayout { visibleViewSet.add(startCallControls); startCall.setText(webRtcControls.getStartCallButtonText()); - startCall.setEnabled(true); + startCall.setEnabled(webRtcControls.isStartCallEnabled()); + } + + if (webRtcControls.displayGroupCallFull()) { + groupCallFullStub.get().setVisibility(View.VISIBLE); + ((TextView) groupCallFullStub.get().findViewById(R.id.group_call_call_full_message)).setText(webRtcControls.getGroupCallFullMessage(getContext())); + } else if (groupCallFullStub.resolved()) { + groupCallFullStub.get().setVisibility(View.GONE); } MenuItem item = toolbar.getMenu().findItem(R.id.menu_group_call_participants_list); diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallViewModel.java index 249e7ad044..dec7e5fa9d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallViewModel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallViewModel.java @@ -5,6 +5,7 @@ import android.os.Looper; import androidx.annotation.MainThread; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.Transformations; @@ -163,7 +164,9 @@ public class WebRtcCallViewModel extends ViewModel { localParticipant.isMoreThanOneCameraAvailable(), webRtcViewModel.isBluetoothAvailable(), Util.hasItems(webRtcViewModel.getRemoteParticipants()), - repository.getAudioOutput()); + repository.getAudioOutput(), + webRtcViewModel.getRemoteDevicesCount(), + webRtcViewModel.getParticipantLimit()); if (webRtcViewModel.getState() == WebRtcViewModel.State.CALL_CONNECTED && callConnectedTime == -1) { callConnectedTime = webRtcViewModel.getCallConnectedTime(); @@ -206,7 +209,9 @@ public class WebRtcCallViewModel extends ViewModel { boolean isMoreThanOneCameraAvailable, boolean isBluetoothAvailable, boolean hasAtLeastOneRemote, - @NonNull WebRtcAudioOutput audioOutput) + @NonNull WebRtcAudioOutput audioOutput, + long remoteDevicesCount, + @Nullable Long participantLimit) { final WebRtcControls.CallState callState; @@ -242,7 +247,8 @@ public class WebRtcCallViewModel extends ViewModel { break; case CONNECTING: case RECONNECTING: - groupCallState = WebRtcControls.GroupCallState.CONNECTING; + groupCallState = (participantLimit == null || remoteDevicesCount < participantLimit) ? WebRtcControls.GroupCallState.CONNECTING + : WebRtcControls.GroupCallState.FULL; break; case CONNECTED: case CONNECTED_AND_JOINING: @@ -262,7 +268,8 @@ public class WebRtcCallViewModel extends ViewModel { hasAtLeastOneRemote, callState, groupCallState, - audioOutput)); + audioOutput, + participantLimit)); } private @NonNull WebRtcControls getRealWebRtcControls(boolean isInPipMode, @NonNull WebRtcControls controls) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcControls.java b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcControls.java index 88d03bd69e..2fc4bc0fba 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcControls.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcControls.java @@ -1,6 +1,9 @@ package org.thoughtcrime.securesms.components.webrtc; +import android.content.Context; + import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.StringRes; import org.thoughtcrime.securesms.R; @@ -8,7 +11,7 @@ import org.thoughtcrime.securesms.R; public final class WebRtcControls { public static final WebRtcControls NONE = new WebRtcControls(); - public static final WebRtcControls PIP = new WebRtcControls(false, false, false, false, true, false, CallState.NONE, GroupCallState.NONE, WebRtcAudioOutput.HANDSET); + public static final WebRtcControls PIP = new WebRtcControls(false, false, false, false, true, false, CallState.NONE, GroupCallState.NONE, WebRtcAudioOutput.HANDSET, null); private final boolean isRemoteVideoEnabled; private final boolean isLocalVideoEnabled; @@ -19,9 +22,10 @@ public final class WebRtcControls { private final CallState callState; private final GroupCallState groupCallState; private final WebRtcAudioOutput audioOutput; + private final Long participantLimit; private WebRtcControls() { - this(false, false, false, false, false, false, CallState.NONE, GroupCallState.NONE, WebRtcAudioOutput.HANDSET); + this(false, false, false, false, false, false, CallState.NONE, GroupCallState.NONE, WebRtcAudioOutput.HANDSET, null); } WebRtcControls(boolean isLocalVideoEnabled, @@ -32,7 +36,8 @@ public final class WebRtcControls { boolean hasAtLeastOneRemote, @NonNull CallState callState, @NonNull GroupCallState groupCallState, - @NonNull WebRtcAudioOutput audioOutput) + @NonNull WebRtcAudioOutput audioOutput, + @Nullable Long participantLimit) { this.isLocalVideoEnabled = isLocalVideoEnabled; this.isRemoteVideoEnabled = isRemoteVideoEnabled; @@ -43,6 +48,7 @@ public final class WebRtcControls { this.callState = callState; this.groupCallState = groupCallState; this.audioOutput = audioOutput; + this.participantLimit = participantLimit; } boolean displayStartCallControls() { @@ -50,12 +56,31 @@ public final class WebRtcControls { } @StringRes int getStartCallButtonText() { - if (isGroupCall() && hasAtLeastOneRemote) { - return R.string.WebRtcCallView__join_call; + if (isGroupCall()) { + if (groupCallState == GroupCallState.FULL) { + return R.string.WebRtcCallView__call_is_full; + } else if (hasAtLeastOneRemote) { + return R.string.WebRtcCallView__join_call; + } } return R.string.WebRtcCallView__start_call; } + boolean isStartCallEnabled() { + return groupCallState != GroupCallState.FULL; + } + + boolean displayGroupCallFull() { + return groupCallState == GroupCallState.FULL; + } + + @NonNull String getGroupCallFullMessage(@NonNull Context context) { + if (participantLimit != null) { + return context.getString(R.string.WebRtcCallView__the_maximum_number_of_d_participants_has_been_Reached_for_this_call, participantLimit); + } + return ""; + } + boolean displayGroupMembersButton() { return groupCallState.isAtLeast(GroupCallState.CONNECTING); } @@ -158,6 +183,7 @@ public final class WebRtcControls { DISCONNECTED, RECONNECTING, CONNECTING, + FULL, CONNECTED; boolean isAtLeast(@SuppressWarnings("SameParameterValue") @NonNull GroupCallState other) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/participantslist/CallParticipantsListDialog.java b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/participantslist/CallParticipantsListDialog.java index 2995f1a4ed..1bc0286728 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/participantslist/CallParticipantsListDialog.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/participantslist/CallParticipantsListDialog.java @@ -90,7 +90,7 @@ public class CallParticipantsListDialog extends BottomSheetDialogFragment { boolean includeSelf = callParticipantsState.getGroupCallState() == WebRtcViewModel.GroupCallState.CONNECTED_AND_JOINED; - items.add(new CallParticipantsListHeader(callParticipantsState.getAllRemoteParticipants().size() + (includeSelf ? 1 : 0))); + items.add(new CallParticipantsListHeader((int) callParticipantsState.getRemoteDevicesCount() + (includeSelf ? 1 : 0))); if (includeSelf) { items.add(new CallParticipantViewState(callParticipantsState.getLocalParticipant())); diff --git a/app/src/main/java/org/thoughtcrime/securesms/events/WebRtcViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/events/WebRtcViewModel.java index d72c342a9a..7d8232aaa9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/events/WebRtcViewModel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/events/WebRtcViewModel.java @@ -8,7 +8,7 @@ import com.annimon.stream.Stream; import org.thoughtcrime.securesms.components.webrtc.BroadcastVideoSink; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.RecipientId; -import org.thoughtcrime.securesms.ringrtc.CameraState; +import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState; import java.util.List; import java.util.Set; @@ -94,29 +94,24 @@ public class WebRtcViewModel { private final CallParticipant localParticipant; private final List remoteParticipants; private final Set identityChangedRecipients; + private final long remoteDevicesCount; + private final Long participantLimit; - public WebRtcViewModel(@NonNull State state, - @NonNull GroupCallState groupState, - @NonNull Recipient recipient, - @NonNull CameraState localCameraState, - @Nullable BroadcastVideoSink localSink, - boolean isBluetoothAvailable, - boolean isMicrophoneEnabled, - boolean isRemoteVideoOffer, - long callConnectedTime, - @NonNull List remoteParticipants, - @NonNull Set identityChangedRecipients) - { - this.state = state; - this.groupState = groupState; - this.recipient = recipient; - this.isBluetoothAvailable = isBluetoothAvailable; - this.isRemoteVideoOffer = isRemoteVideoOffer; - this.callConnectedTime = callConnectedTime; - this.remoteParticipants = remoteParticipants; - this.identityChangedRecipients = identityChangedRecipients; - - localParticipant = CallParticipant.createLocal(localCameraState, localSink != null ? localSink : new BroadcastVideoSink(null), isMicrophoneEnabled); + public WebRtcViewModel(@NonNull WebRtcServiceState state) { + this.state = state.getCallInfoState().getCallState(); + this.groupState = state.getCallInfoState().getGroupCallState(); + this.recipient = state.getCallInfoState().getCallRecipient(); + this.isRemoteVideoOffer = state.getCallSetupState().isRemoteVideoOffer(); + this.isBluetoothAvailable = state.getLocalDeviceState().isBluetoothAvailable(); + this.remoteParticipants = state.getCallInfoState().getRemoteCallParticipants(); + this.identityChangedRecipients = state.getCallInfoState().getIdentityChangedRecipients(); + this.callConnectedTime = state.getCallInfoState().getCallConnectedTime(); + this.remoteDevicesCount = state.getCallInfoState().getRemoteDevicesCount(); + this.participantLimit = state.getCallInfoState().getParticipantLimit(); + this.localParticipant = CallParticipant.createLocal(state.getLocalDeviceState().getCameraState(), + state.getVideoState().getLocalSink() != null ? state.getVideoState().getLocalSink() + : new BroadcastVideoSink(null), + state.getLocalDeviceState().isMicrophoneEnabled()); } public @NonNull State getState() { @@ -159,6 +154,14 @@ public class WebRtcViewModel { return identityChangedRecipients; } + public long getRemoteDevicesCount() { + return remoteDevicesCount; + } + + public @Nullable Long getParticipantLimit() { + return participantLimit; + } + @Override public @NonNull String toString() { return "WebRtcViewModel{" + @@ -170,6 +173,8 @@ public class WebRtcViewModel { ", localParticipant=" + localParticipant + ", remoteParticipants=" + remoteParticipants + ", identityChangedRecipients=" + identityChangedRecipients + + ", remoteDevicesCount=" + remoteDevicesCount + + ", participantLimit=" + participantLimit + '}'; } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.java b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.java index 7f11ff3064..9c8e43e384 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.java @@ -430,17 +430,7 @@ public class WebRtcCallService extends Service implements CallManager.Observer, } public void sendMessage(@NonNull WebRtcServiceState state) { - EventBus.getDefault().postSticky(new WebRtcViewModel(state.getCallInfoState().getCallState(), - state.getCallInfoState().getGroupCallState(), - state.getCallInfoState().getCallRecipient(), - state.getLocalDeviceState().getCameraState(), - state.getVideoState().getLocalSink(), - state.getLocalDeviceState().isBluetoothAvailable(), - state.getLocalDeviceState().isMicrophoneEnabled(), - state.getCallSetupState().isRemoteVideoOffer(), - state.getCallInfoState().getCallConnectedTime(), - state.getCallInfoState().getRemoteCallParticipants(), - state.getCallInfoState().getIdentityChangedRecipients())); + EventBus.getDefault().postSticky(new WebRtcViewModel(state)); } private @NonNull ListenableFutureTask sendMessage(@NonNull final RemotePeer remotePeer, diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java index 72e1ac604a..68bab739ac 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupActionProcessor.java @@ -62,12 +62,17 @@ public class GroupActionProcessor extends DeviceAwareActionProcessor { GroupCall groupCall = currentState.getCallInfoState().requireGroupCall(); Map participants = currentState.getCallInfoState().getRemoteCallParticipantsMap(); + LongSparseArray remoteDevices = groupCall.getRemoteDeviceStates(); + + if (remoteDevices == null) { + Log.w(tag, "Unable to update remote devices with null list."); + return currentState; + } + WebRtcServiceStateBuilder.CallInfoStateBuilder builder = currentState.builder() .changeCallInfoState() .clearParticipantMap(); - LongSparseArray remoteDevices = groupCall.getRemoteDeviceStates(); - for (int i = 0; i < remoteDevices.size(); i++) { GroupCall.RemoteDeviceState device = remoteDevices.get(remoteDevices.keyAt(i)); Recipient recipient = Recipient.externalPush(context, device.getUserId(), null, false); @@ -96,6 +101,8 @@ public class GroupActionProcessor extends DeviceAwareActionProcessor { device.getAddedTime())); } + builder.remoteDevicesCount(remoteDevices.size()); + return builder.build(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupPreJoinActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupPreJoinActionProcessor.java index 9eb364e6a1..2382df7223 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupPreJoinActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/GroupPreJoinActionProcessor.java @@ -112,7 +112,9 @@ public class GroupPreJoinActionProcessor extends GroupActionProcessor { .toList(); WebRtcServiceStateBuilder.CallInfoStateBuilder builder = currentState.builder() - .changeCallInfoState(); + .changeCallInfoState() + .remoteDevicesCount(peekInfo.getDeviceCount()) + .participantLimit(peekInfo.getMaxDevices()); for (Recipient recipient : callParticipants) { builder.putParticipant(recipient, CallParticipant.createRemote(new CallParticipantId(recipient), recipient, null, new BroadcastVideoSink(null), true, true, 0, false, 0)); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/state/CallInfoState.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/state/CallInfoState.java index 2a84a543db..8eaf5455b4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/state/CallInfoState.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/state/CallInfoState.java @@ -35,6 +35,8 @@ public class CallInfoState { GroupCall groupCall; WebRtcViewModel.GroupCallState groupState; Set identityChangedRecipients; + long remoteDevicesCount; + Long participantLimit; public CallInfoState() { this(WebRtcViewModel.State.IDLE, @@ -45,7 +47,9 @@ public class CallInfoState { null, null, WebRtcViewModel.GroupCallState.IDLE, - Collections.emptySet()); + Collections.emptySet(), + 0L, + null); } public CallInfoState(@NonNull CallInfoState toCopy) { @@ -57,7 +61,9 @@ public class CallInfoState { toCopy.activePeer, toCopy.groupCall, toCopy.groupState, - toCopy.identityChangedRecipients); + toCopy.identityChangedRecipients, + toCopy.remoteDevicesCount, + toCopy.participantLimit); } public CallInfoState(@NonNull WebRtcViewModel.State callState, @@ -68,7 +74,9 @@ public class CallInfoState { @Nullable RemotePeer activePeer, @Nullable GroupCall groupCall, @NonNull WebRtcViewModel.GroupCallState groupState, - @NonNull Set identityChangedRecipients) + @NonNull Set identityChangedRecipients, + long remoteDevicesCount, + @Nullable Long participantLimit) { this.callState = callState; this.callRecipient = callRecipient; @@ -79,6 +87,8 @@ public class CallInfoState { this.groupCall = groupCall; this.groupState = groupState; this.identityChangedRecipients = new HashSet<>(identityChangedRecipients); + this.remoteDevicesCount = remoteDevicesCount; + this.participantLimit = participantLimit; } public @NonNull Recipient getCallRecipient() { @@ -136,4 +146,12 @@ public class CallInfoState { public @NonNull Set getIdentityChangedRecipients() { return identityChangedRecipients; } + + public long getRemoteDevicesCount() { + return remoteDevicesCount; + } + + public @Nullable Long getParticipantLimit() { + return participantLimit; + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/state/WebRtcServiceStateBuilder.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/state/WebRtcServiceStateBuilder.java index 3110548740..fa550c5021 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/state/WebRtcServiceStateBuilder.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/state/WebRtcServiceStateBuilder.java @@ -256,5 +256,15 @@ public class WebRtcServiceStateBuilder { toBuild.identityChangedRecipients.removeAll(ids); return this; } + + public @NonNull CallInfoStateBuilder remoteDevicesCount(long remoteDevicesCount) { + toBuild.remoteDevicesCount = remoteDevicesCount; + return this; + } + + public @NonNull CallInfoStateBuilder participantLimit(@Nullable Long participantLimit) { + toBuild.participantLimit = participantLimit; + return this; + } } } diff --git a/app/src/main/res/layout/group_call_call_full.xml b/app/src/main/res/layout/group_call_call_full.xml new file mode 100644 index 0000000000..b72189026e --- /dev/null +++ b/app/src/main/res/layout/group_call_call_full.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/app/src/main/res/layout/webrtc_call_view.xml b/app/src/main/res/layout/webrtc_call_view.xml index 683f3bd07a..a659f1513f 100644 --- a/app/src/main/res/layout/webrtc_call_view.xml +++ b/app/src/main/res/layout/webrtc_call_view.xml @@ -26,6 +26,12 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> + + Signal video call… Start Call Join Call + Call is full + The maximum number of %1$d participants has been reached for this call. Try again later. \"%1$s\" Group Call View participants Your video is off