diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index fc7482e89f..b8e54ad9f8 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -116,7 +116,7 @@
showBlockedDialog(participant.getRecipient()));
+ } else {
+ infoIcon.setImageResource(R.drawable.ic_error_solid_24);
+ infoMessage.setText(getContext().getString(R.string.CallParticipantView__cant_receive_audio_video_from_s, participant.getRecipient().getShortDisplayName(getContext())));
+ infoMoreInfo.setOnClickListener(v -> showNoMediaKeysDialog(participant.getRecipient()));
+ }
+ } else {
+ infoOverlay.setVisibility(View.GONE);
+
+ renderer.setVisibility(participant.isVideoEnabled() ? View.VISIBLE : View.GONE);
+
+ if (participant.isVideoEnabled()) {
+ if (participant.getVideoSink().getEglBase() != null) {
+ renderer.init(participant.getVideoSink().getEglBase());
+ }
+ renderer.attachBroadcastVideoSink(participant.getVideoSink());
+ } else {
+ renderer.attachBroadcastVideoSink(null);
+ }
+
+ audioMuted.setVisibility(participant.isMicrophoneEnabled() ? View.GONE : View.VISIBLE);
}
if (participantChanged || !Objects.equals(contactPhoto, participant.getRecipient().getContactPhoto())) {
@@ -100,11 +143,15 @@ public class CallParticipantView extends ConstraintLayout {
setPipAvatar(participant.getRecipient());
contactPhoto = participant.getRecipient().getContactPhoto();
}
-
- audioMuted.setVisibility(participant.isMicrophoneEnabled() ? View.GONE : View.VISIBLE);
}
void setRenderInPip(boolean shouldRenderInPip) {
+ if (infoMode) {
+ infoMessage.setVisibility(shouldRenderInPip ? View.GONE : View.VISIBLE);
+ infoMoreInfo.setVisibility(shouldRenderInPip ? View.GONE : View.VISIBLE);
+ return;
+ }
+
avatar.setVisibility(shouldRenderInPip ? View.GONE : View.VISIBLE);
pipAvatar.setVisibility(shouldRenderInPip ? View.VISIBLE : View.GONE);
}
@@ -146,6 +193,22 @@ public class CallParticipantView extends ConstraintLayout {
pipAvatar.setBackgroundColor(recipient.getColor().toActionBarColor(getContext()));
}
+ private void showBlockedDialog(@NonNull Recipient recipient) {
+ new AlertDialog.Builder(getContext())
+ .setTitle(getContext().getString(R.string.CallParticipantView__s_is_blocked, recipient.getShortDisplayName(getContext())))
+ .setMessage(R.string.CallParticipantView__you_wont_receive_their_audio_or_video)
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ }
+
+ private void showNoMediaKeysDialog(@NonNull Recipient recipient) {
+ new AlertDialog.Builder(getContext())
+ .setTitle(getContext().getString(R.string.CallParticipantView__cant_receive_audio_and_video_from_s, recipient.getShortDisplayName(getContext())))
+ .setMessage(R.string.CallParticipantView__this_may_be_Because_they_have_not_verified_your_safety_number_change)
+ .setPositiveButton(android.R.string.ok, null)
+ .show();
+ }
+
private static final class FallbackPhotoProvider extends Recipient.FallbackPhotoProvider {
@Override
public @NonNull FallbackContactPhoto getPhotoForLocalNumber() {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/events/CallParticipant.java b/app/src/main/java/org/thoughtcrime/securesms/events/CallParticipant.java
index 2bc5860a1a..fcd8d16dec 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/events/CallParticipant.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/events/CallParticipant.java
@@ -10,9 +10,9 @@ import org.whispersystems.libsignal.IdentityKey;
import java.util.Objects;
-public class CallParticipant {
+public final class CallParticipant {
- public static final CallParticipant EMPTY = createRemote(Recipient.UNKNOWN, null, new BroadcastVideoSink(null), false, false, 0);
+ public static final CallParticipant EMPTY = createRemote(Recipient.UNKNOWN, null, new BroadcastVideoSink(null), false, false, 0, true);
private final @NonNull CameraState cameraState;
private final @NonNull Recipient recipient;
@@ -21,6 +21,7 @@ public class CallParticipant {
private final boolean videoEnabled;
private final boolean microphoneEnabled;
private final long lastSpoke;
+ private final boolean mediaKeysReceived;
public static @NonNull CallParticipant createLocal(@NonNull CameraState cameraState,
@NonNull BroadcastVideoSink renderer,
@@ -32,7 +33,8 @@ public class CallParticipant {
cameraState,
cameraState.isEnabled() && cameraState.getCameraCount() > 0,
microphoneEnabled,
- 0);
+ 0,
+ true);
}
public static @NonNull CallParticipant createRemote(@NonNull Recipient recipient,
@@ -40,9 +42,10 @@ public class CallParticipant {
@NonNull BroadcastVideoSink renderer,
boolean audioEnabled,
boolean videoEnabled,
- long lastSpoke)
+ long lastSpoke,
+ boolean mediaKeysReceived)
{
- return new CallParticipant(recipient, identityKey, renderer, CameraState.UNKNOWN, videoEnabled, audioEnabled, lastSpoke);
+ return new CallParticipant(recipient, identityKey, renderer, CameraState.UNKNOWN, videoEnabled, audioEnabled, lastSpoke, mediaKeysReceived);
}
private CallParticipant(@NonNull Recipient recipient,
@@ -51,7 +54,8 @@ public class CallParticipant {
@NonNull CameraState cameraState,
boolean videoEnabled,
boolean microphoneEnabled,
- long lastSpoke)
+ long lastSpoke,
+ boolean mediaKeysReceived)
{
this.recipient = recipient;
this.identityKey = identityKey;
@@ -60,14 +64,15 @@ public class CallParticipant {
this.videoEnabled = videoEnabled;
this.microphoneEnabled = microphoneEnabled;
this.lastSpoke = lastSpoke;
+ this.mediaKeysReceived = mediaKeysReceived;
}
public @NonNull CallParticipant withIdentityKey(@NonNull IdentityKey identityKey) {
- return new CallParticipant(recipient, identityKey, videoSink, cameraState, videoEnabled, microphoneEnabled, lastSpoke);
+ return new CallParticipant(recipient, identityKey, videoSink, cameraState, videoEnabled, microphoneEnabled, lastSpoke, mediaKeysReceived);
}
public @NonNull CallParticipant withVideoEnabled(boolean videoEnabled) {
- return new CallParticipant(recipient, identityKey, videoSink, cameraState, videoEnabled, microphoneEnabled, lastSpoke);
+ return new CallParticipant(recipient, identityKey, videoSink, cameraState, videoEnabled, microphoneEnabled, lastSpoke, mediaKeysReceived);
}
public @NonNull Recipient getRecipient() {
@@ -109,6 +114,10 @@ public class CallParticipant {
return lastSpoke;
}
+ public boolean isMediaKeysReceived() {
+ return mediaKeysReceived;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -117,6 +126,7 @@ public class CallParticipant {
return videoEnabled == that.videoEnabled &&
microphoneEnabled == that.microphoneEnabled &&
lastSpoke == that.lastSpoke &&
+ mediaKeysReceived == that.mediaKeysReceived &&
cameraState.equals(that.cameraState) &&
recipient.equals(that.recipient) &&
Objects.equals(identityKey, that.identityKey) &&
@@ -125,7 +135,7 @@ public class CallParticipant {
@Override
public int hashCode() {
- return Objects.hash(cameraState, recipient, identityKey, videoSink, videoEnabled, microphoneEnabled, lastSpoke);
+ return Objects.hash(cameraState, recipient, identityKey, videoSink, videoEnabled, microphoneEnabled, lastSpoke, mediaKeysReceived);
}
@Override
@@ -137,6 +147,8 @@ public class CallParticipant {
", videoSink=" + (videoSink.getEglBase() == null ? "not initialized" : "initialized") +
", videoEnabled=" + videoEnabled +
", microphoneEnabled=" + microphoneEnabled +
+ ", lastSpoke=" + lastSpoke +
+ ", mediaKeysReceived=" + mediaKeysReceived +
'}';
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupCallUpdateSendJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupCallUpdateSendJob.java
index cf775668b9..e89f443c44 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupCallUpdateSendJob.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/GroupCallUpdateSendJob.java
@@ -58,6 +58,7 @@ public class GroupCallUpdateSendJob extends BaseJob {
List recipients = Stream.of(RecipientUtil.getEligibleForSending(conversationRecipient.getParticipants()))
.filterNot(Recipient::isSelf)
+ .filterNot(Recipient::isBlocked)
.map(Recipient::getId)
.toList();
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 72110b93e0..4aa73bff29 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.java
@@ -444,6 +444,10 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
{
Callable callable = () -> {
Recipient recipient = remotePeer.getRecipient();
+ if (recipient.isBlocked()) {
+ return true;
+ }
+
messageSender.sendCallMessage(RecipientUtil.toSignalServiceAddress(WebRtcCallService.this, recipient),
UnidentifiedAccessUtil.getAccessFor(WebRtcCallService.this, recipient),
callMessage);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/BeginCallActionProcessorDelegate.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/BeginCallActionProcessorDelegate.java
index 43db0bb7ee..0ca5f79ca5 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/BeginCallActionProcessorDelegate.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/BeginCallActionProcessorDelegate.java
@@ -46,7 +46,8 @@ public class BeginCallActionProcessorDelegate extends WebRtcActionProcessor {
new BroadcastVideoSink(currentState.getVideoState().getEglBase()),
true,
false,
- 0
+ 0,
+ true
))
.build();
@@ -86,7 +87,8 @@ public class BeginCallActionProcessorDelegate extends WebRtcActionProcessor {
new BroadcastVideoSink(currentState.getVideoState().getEglBase()),
true,
false,
- 0
+ 0,
+ true
))
.build();
}
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 ae5b15c740..febbcd1712 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
@@ -70,7 +70,8 @@ public class GroupActionProcessor extends DeviceAwareActionProcessor {
videoSink,
Boolean.FALSE.equals(device.getAudioMuted()),
Boolean.FALSE.equals(device.getVideoMuted()),
- device.getSpeakerTime()));
+ device.getSpeakerTime(),
+ device.getMediaKeysReceived()));
}
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 09ac2e0b75..c4e4f86d91 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
@@ -114,7 +114,7 @@ public class GroupPreJoinActionProcessor extends GroupActionProcessor {
.changeCallInfoState();
for (Recipient recipient : callParticipants) {
- builder.putParticipant(recipient, CallParticipant.createRemote(recipient, null, new BroadcastVideoSink(null), true, true, 0));
+ builder.putParticipant(recipient, CallParticipant.createRemote(recipient, null, new BroadcastVideoSink(null), true, true, 0, false));
}
return builder.build();
diff --git a/app/src/main/res/drawable/ic_error_solid_24.xml b/app/src/main/res/drawable/ic_error_solid_24.xml
new file mode 100644
index 0000000000..f8654bf1e5
--- /dev/null
+++ b/app/src/main/res/drawable/ic_error_solid_24.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/call_participant_item.xml b/app/src/main/res/layout/call_participant_item.xml
index 334ff885a4..04c44e3fde 100644
--- a/app/src/main/res/layout/call_participant_item.xml
+++ b/app/src/main/res/layout/call_participant_item.xml
@@ -44,9 +44,51 @@
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginBottom="12dp"
- app:srcCompat="@drawable/ic_mic_off_solid_18"
- app:tint="@color/core_white"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toStartOf="parent"/>
+ app:layout_constraintStart_toStartOf="parent"
+ app:srcCompat="@drawable/ic_mic_off_solid_18"
+ app:tint="@color/core_white" />
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a04cf16378..d59519ee7a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1436,6 +1436,14 @@
- In this call ยท %1$d people
+
+ %1$s is blocked
+ More Info
+ You won\'t receive their audio or video and they won\'t receive yours.
+ Can\'t receive audio & video from %1$s
+ Can\'t receive audio and video from %1$s
+ This may be because they have not verified your safety number change, there\'s a problem with their device, or they have blocked you.
+
Select your country
You must specify your
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 96a077dd04..2c60ca3594 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -266,7 +266,7 @@
- @drawable/ic_arrow_left_conversation_24
-