Fix a few minor group call UI issues.

This commit is contained in:
Cody Henthorne 2020-12-07 10:05:35 -05:00 committed by GitHub
parent 2dcc7d284f
commit bdc6c8c65a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 73 additions and 46 deletions

View file

@ -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()) {

View file

@ -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 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,6 +77,7 @@ public class CallParticipantView extends ConstraintLayout {
@Override
protected void onFinishInflate() {
super.onFinishInflate();
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);
@ -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();
}

View file

@ -60,6 +60,7 @@ class WebRtcCallParticipantsRecyclerAdapter extends ListAdapter<CallParticipant,
@Override
void bind(@NonNull CallParticipant callParticipant) {
callParticipantView.setCallParticipant(callParticipant);
callParticipantView.setRenderInPip(true);
}
}

View file

@ -12,7 +12,7 @@ import java.util.Objects;
public final class CallParticipant {
public static final CallParticipant EMPTY = createRemote(new CallParticipantId(Recipient.UNKNOWN), Recipient.UNKNOWN, null, new BroadcastVideoSink(null), false, false, 0, true);
public static final CallParticipant EMPTY = createRemote(new CallParticipantId(Recipient.UNKNOWN), Recipient.UNKNOWN, null, new BroadcastVideoSink(null), false, false, 0, true, 0);
private final @NonNull CallParticipantId callParticipantId;
private final @NonNull CameraState cameraState;
@ -23,6 +23,7 @@ public final class CallParticipant {
private final boolean microphoneEnabled;
private final long lastSpoke;
private final boolean mediaKeysReceived;
private final long addedToCallTime;
public static @NonNull CallParticipant createLocal(@NonNull CameraState cameraState,
@NonNull BroadcastVideoSink renderer,
@ -36,7 +37,8 @@ public final class CallParticipant {
cameraState.isEnabled() && cameraState.getCameraCount() > 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 +
'}';
}
}

View file

@ -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();
}

View file

@ -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();

View file

@ -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();

View file

@ -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<View, Drawable>(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<? super Drawable> transition) {
target.setBackground(resource);
target.setImageDrawable(resource);
}
@Override
protected void onResourceCleared(@Nullable Drawable placeholder) {
target.setBackground(placeholder);
target.setImageDrawable(placeholder);
}
});
}

View file

@ -7,6 +7,17 @@
tools:layout_height="match_parent"
tools:layout_width="match_parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/call_participant_background_avatar"
android:layout_width="0dp"
android:layout_height="0dp"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@tools:sample/backgrounds/scenic" />
<org.thoughtcrime.securesms.components.AvatarImageView
android:id="@+id/call_participant_item_avatar"
android:layout_width="112dp"
@ -51,17 +62,16 @@
<LinearLayout
android:id="@+id/call_participant_info_overlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@color/transparent_black_40"
android:gravity="center"
android:orientation="vertical"
android:padding="16dp"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible">
<androidx.appcompat.widget.AppCompatImageView
@ -75,7 +85,9 @@
android:id="@+id/call_participant_info_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="12dp"
android:gravity="center_horizontal"
android:lines="3"

View file

@ -172,7 +172,7 @@ public class CallParticipantListUpdateTest {
private static CallParticipant createParticipant(long recipientId, long deMuxId) {
Recipient recipient = new Recipient(RecipientId.from(recipientId), mock(RecipientDetails.class), true);
return CallParticipant.createRemote(new CallParticipantId(deMuxId, recipient.getId()), recipient, null, new BroadcastVideoSink(null), false, false, -1, false);
return CallParticipant.createRemote(new CallParticipantId(deMuxId, recipient.getId()), recipient, null, new BroadcastVideoSink(null), false, false, -1, false, 0);
}
}