From bdc6c8c65ac950e256b8cfd9576084b0dadd6e9b Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Mon, 7 Dec 2020 10:05:35 -0500 Subject: [PATCH] Fix a few minor group call UI issues. --- .../components/webrtc/BroadcastVideoSink.java | 4 +-- .../webrtc/CallParticipantView.java | 28 +++++++++++-------- ...WebRtcCallParticipantsRecyclerAdapter.java | 1 + .../securesms/events/CallParticipant.java | 27 ++++++++++++------ .../BeginCallActionProcessorDelegate.java | 6 ++-- .../service/webrtc/GroupActionProcessor.java | 3 +- .../webrtc/GroupPreJoinActionProcessor.java | 2 +- .../securesms/util/AvatarUtil.java | 22 ++++++--------- .../main/res/layout/call_participant_item.xml | 24 ++++++++++++---- .../webrtc/CallParticipantListUpdateTest.java | 2 +- 10 files changed, 73 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/BroadcastVideoSink.java b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/BroadcastVideoSink.java index d75bb7ffb1..7cb881a52d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/BroadcastVideoSink.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/BroadcastVideoSink.java @@ -59,8 +59,8 @@ public class BroadcastVideoSink implements VideoSink { } public @NonNull RequestedSize getMaxRequestingSize() { - int width = 0; - int height = 0; + int width = 1; + int height = 1; synchronized (requestingSizes) { for (Point size : requestingSizes.values()) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/CallParticipantView.java b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/CallParticipantView.java index 6b0b3e030f..cec5c6b982 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/CallParticipantView.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/CallParticipantView.java @@ -33,6 +33,7 @@ import org.thoughtcrime.securesms.util.ViewUtil; import org.webrtc.RendererCommon; import java.util.Objects; +import java.util.concurrent.TimeUnit; /** * Encapsulates views needed to show a call participant including their @@ -42,12 +43,14 @@ public class CallParticipantView extends ConstraintLayout { private static final FallbackPhotoProvider FALLBACK_PHOTO_PROVIDER = new FallbackPhotoProvider(); - private static final int SMALL_AVATAR = ViewUtil.dpToPx(96); - private static final int LARGE_AVATAR = ViewUtil.dpToPx(112); + private static final long DELAY_SHOWING_MISSING_MEDIA_KEYS = TimeUnit.SECONDS.toMillis(5); + private static final int SMALL_AVATAR = ViewUtil.dpToPx(96); + private static final int LARGE_AVATAR = ViewUtil.dpToPx(112); private RecipientId recipientId; private boolean infoMode; + private AppCompatImageView backgroundAvatar; private AvatarImageView avatar; private TextureViewRenderer renderer; private ImageView pipAvatar; @@ -74,14 +77,15 @@ public class CallParticipantView extends ConstraintLayout { @Override protected void onFinishInflate() { super.onFinishInflate(); - avatar = findViewById(R.id.call_participant_item_avatar); - pipAvatar = findViewById(R.id.call_participant_item_pip_avatar); - renderer = findViewById(R.id.call_participant_renderer); - audioMuted = findViewById(R.id.call_participant_mic_muted); - infoOverlay = findViewById(R.id.call_participant_info_overlay); - infoIcon = findViewById(R.id.call_participant_info_icon); - infoMessage = findViewById(R.id.call_participant_info_message); - infoMoreInfo = findViewById(R.id.call_participant_info_more_info); + backgroundAvatar = findViewById(R.id.call_participant_background_avatar); + avatar = findViewById(R.id.call_participant_item_avatar); + pipAvatar = findViewById(R.id.call_participant_item_pip_avatar); + renderer = findViewById(R.id.call_participant_renderer); + audioMuted = findViewById(R.id.call_participant_mic_muted); + infoOverlay = findViewById(R.id.call_participant_info_overlay); + infoIcon = findViewById(R.id.call_participant_info_icon); + infoMessage = findViewById(R.id.call_participant_info_message); + infoMoreInfo = findViewById(R.id.call_participant_info_more_info); avatar.setFallbackPhotoProvider(FALLBACK_PHOTO_PROVIDER); useLargeAvatar(); @@ -98,7 +102,7 @@ public class CallParticipantView extends ConstraintLayout { void setCallParticipant(@NonNull CallParticipant participant) { boolean participantChanged = recipientId == null || !recipientId.equals(participant.getRecipient().getId()); recipientId = participant.getRecipient().getId(); - infoMode = participant.getRecipient().isBlocked() || !participant.isMediaKeysReceived(); + infoMode = participant.getRecipient().isBlocked() || (!participant.isMediaKeysReceived() && (System.currentTimeMillis() - participant.getAddedToCallTime()) > DELAY_SHOWING_MISSING_MEDIA_KEYS); if (infoMode) { renderer.setVisibility(View.GONE); @@ -139,7 +143,7 @@ public class CallParticipantView extends ConstraintLayout { if (participantChanged || !Objects.equals(contactPhoto, participant.getRecipient().getContactPhoto())) { avatar.setAvatarUsingProfile(participant.getRecipient()); - AvatarUtil.loadBlurredIconIntoViewBackground(participant.getRecipient(), this, true); + AvatarUtil.loadBlurredIconIntoImageView(participant.getRecipient(), backgroundAvatar); setPipAvatar(participant.getRecipient()); contactPhoto = participant.getRecipient().getContactPhoto(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallParticipantsRecyclerAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallParticipantsRecyclerAdapter.java index 8ba176d0e9..56df4ec763 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallParticipantsRecyclerAdapter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallParticipantsRecyclerAdapter.java @@ -60,6 +60,7 @@ class WebRtcCallParticipantsRecyclerAdapter extends ListAdapter 0, microphoneEnabled, 0, - true); + true, + 0); } public static @NonNull CallParticipant createRemote(@NonNull CallParticipantId callParticipantId, @@ -46,9 +48,10 @@ public final class CallParticipant { boolean audioEnabled, boolean videoEnabled, long lastSpoke, - boolean mediaKeysReceived) + boolean mediaKeysReceived, + long addedToCallTime) { - return new CallParticipant(callParticipantId, recipient, identityKey, renderer, CameraState.UNKNOWN, videoEnabled, audioEnabled, lastSpoke, mediaKeysReceived); + return new CallParticipant(callParticipantId, recipient, identityKey, renderer, CameraState.UNKNOWN, videoEnabled, audioEnabled, lastSpoke, mediaKeysReceived, addedToCallTime); } private CallParticipant(@NonNull CallParticipantId callParticipantId, @@ -59,7 +62,8 @@ public final class CallParticipant { boolean videoEnabled, boolean microphoneEnabled, long lastSpoke, - boolean mediaKeysReceived) + boolean mediaKeysReceived, + long addedToCallTime) { this.callParticipantId = callParticipantId; this.recipient = recipient; @@ -70,14 +74,15 @@ public final class CallParticipant { this.microphoneEnabled = microphoneEnabled; this.lastSpoke = lastSpoke; this.mediaKeysReceived = mediaKeysReceived; + this.addedToCallTime = addedToCallTime; } public @NonNull CallParticipant withIdentityKey(@NonNull IdentityKey identityKey) { - return new CallParticipant(callParticipantId, recipient, identityKey, videoSink, cameraState, videoEnabled, microphoneEnabled, lastSpoke, mediaKeysReceived); + return new CallParticipant(callParticipantId, recipient, identityKey, videoSink, cameraState, videoEnabled, microphoneEnabled, lastSpoke, mediaKeysReceived, addedToCallTime); } public @NonNull CallParticipant withVideoEnabled(boolean videoEnabled) { - return new CallParticipant(callParticipantId, recipient, identityKey, videoSink, cameraState, videoEnabled, microphoneEnabled, lastSpoke, mediaKeysReceived); + return new CallParticipant(callParticipantId, recipient, identityKey, videoSink, cameraState, videoEnabled, microphoneEnabled, lastSpoke, mediaKeysReceived, addedToCallTime); } public @NonNull CallParticipantId getCallParticipantId() { @@ -127,6 +132,10 @@ public final class CallParticipant { return mediaKeysReceived; } + public long getAddedToCallTime() { + return addedToCallTime; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -137,6 +146,7 @@ public final class CallParticipant { microphoneEnabled == that.microphoneEnabled && lastSpoke == that.lastSpoke && mediaKeysReceived == that.mediaKeysReceived && + addedToCallTime == that.addedToCallTime && cameraState.equals(that.cameraState) && recipient.equals(that.recipient) && Objects.equals(identityKey, that.identityKey) && @@ -145,7 +155,7 @@ public final class CallParticipant { @Override public int hashCode() { - return Objects.hash(callParticipantId, cameraState, recipient, identityKey, videoSink, videoEnabled, microphoneEnabled, lastSpoke, mediaKeysReceived); + return Objects.hash(callParticipantId, cameraState, recipient, identityKey, videoSink, videoEnabled, microphoneEnabled, lastSpoke, mediaKeysReceived, addedToCallTime); } @Override @@ -159,6 +169,7 @@ public final class CallParticipant { ", microphoneEnabled=" + microphoneEnabled + ", lastSpoke=" + lastSpoke + ", mediaKeysReceived=" + mediaKeysReceived + + ", addedToCallTime=" + addedToCallTime + '}'; } } 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 87a886a1aa..21aad0140b 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 @@ -49,7 +49,8 @@ public class BeginCallActionProcessorDelegate extends WebRtcActionProcessor { true, false, 0, - true + true, + 0 )) .build(); @@ -91,7 +92,8 @@ public class BeginCallActionProcessorDelegate extends WebRtcActionProcessor { true, false, 0, - true + true, + 0 )) .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 5eacda04b4..72e1ac604a 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 @@ -92,7 +92,8 @@ public class GroupActionProcessor extends DeviceAwareActionProcessor { Boolean.FALSE.equals(device.getAudioMuted()), Boolean.FALSE.equals(device.getVideoMuted()), device.getSpeakerTime(), - device.getMediaKeysReceived())); + device.getMediaKeysReceived(), + device.getAddedTime())); } 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 ee80dbbd46..9eb364e6a1 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 @@ -115,7 +115,7 @@ public class GroupPreJoinActionProcessor extends GroupActionProcessor { .changeCallInfoState(); for (Recipient recipient : callParticipants) { - builder.putParticipant(recipient, CallParticipant.createRemote(new CallParticipantId(recipient), recipient, null, new BroadcastVideoSink(null), true, true, 0, false)); + builder.putParticipant(recipient, CallParticipant.createRemote(new CallParticipantId(recipient), recipient, null, new BroadcastVideoSink(null), true, true, 0, false, 0)); } return builder.build(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/AvatarUtil.java b/app/src/main/java/org/thoughtcrime/securesms/util/AvatarUtil.java index 12be8680f4..e5881e80f5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/AvatarUtil.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/AvatarUtil.java @@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.util; import android.content.Context; import android.graphics.Bitmap; +import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.text.TextUtils; @@ -12,15 +13,14 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.annotation.WorkerThread; +import androidx.appcompat.widget.AppCompatImageView; import androidx.core.content.ContextCompat; import androidx.core.graphics.drawable.IconCompat; import com.bumptech.glide.load.engine.DiskCacheStrategy; -import com.bumptech.glide.load.resource.bitmap.CenterCrop; import com.bumptech.glide.request.target.CustomViewTarget; import com.bumptech.glide.request.transition.Transition; -import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.color.MaterialColor; import org.thoughtcrime.securesms.contacts.avatars.ContactColors; @@ -36,23 +36,18 @@ import java.util.concurrent.ExecutionException; public final class AvatarUtil { - private static final String TAG = Log.tag(AvatarUtil.class); - private AvatarUtil() { } - public static void loadBlurredIconIntoViewBackground(@NonNull Recipient recipient, @NonNull View target) { - loadBlurredIconIntoViewBackground(recipient, target, false); - } - - public static void loadBlurredIconIntoViewBackground(@NonNull Recipient recipient, @NonNull View target, boolean useSelfProfileAvatar) { + public static void loadBlurredIconIntoImageView(@NonNull Recipient recipient, @NonNull AppCompatImageView target) { Context context = target.getContext(); ContactPhoto photo; - if (recipient.isSelf() && useSelfProfileAvatar) { + if (recipient.isSelf()) { photo = new ProfileContactPhoto(Recipient.self(), Recipient.self().getProfileAvatar()); } else if (recipient.getContactPhoto() == null) { + target.setImageDrawable(null); target.setBackgroundColor(ContextCompat.getColor(target.getContext(), R.color.black)); return; } else { @@ -61,21 +56,22 @@ public final class AvatarUtil { GlideApp.with(target) .load(photo) - .transform(new CenterCrop(), new BlurTransformation(context, 0.25f, BlurTransformation.MAX_RADIUS)) + .transform(new BlurTransformation(context, 0.25f, BlurTransformation.MAX_RADIUS)) .into(new CustomViewTarget(target) { @Override public void onLoadFailed(@Nullable Drawable errorDrawable) { + target.setImageDrawable(null); target.setBackgroundColor(ContextCompat.getColor(target.getContext(), R.color.black)); } @Override public void onResourceReady(@NonNull Drawable resource, @Nullable Transition transition) { - target.setBackground(resource); + target.setImageDrawable(resource); } @Override protected void onResourceCleared(@Nullable Drawable placeholder) { - target.setBackground(placeholder); + target.setImageDrawable(placeholder); } }); } diff --git a/app/src/main/res/layout/call_participant_item.xml b/app/src/main/res/layout/call_participant_item.xml index 04c44e3fde..792d9e47bc 100644 --- a/app/src/main/res/layout/call_participant_item.xml +++ b/app/src/main/res/layout/call_participant_item.xml @@ -7,6 +7,17 @@ tools:layout_height="match_parent" tools:layout_width="match_parent"> + +