Add animations to call screen.
parent
0c73ddc08b
commit
e05f137bd8
|
@ -7,6 +7,7 @@ import org.thoughtcrime.securesms.events.CallParticipant;
|
||||||
import org.thoughtcrime.securesms.events.WebRtcViewModel;
|
import org.thoughtcrime.securesms.events.WebRtcViewModel;
|
||||||
import org.thoughtcrime.securesms.ringrtc.CameraState;
|
import org.thoughtcrime.securesms.ringrtc.CameraState;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -17,7 +18,9 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public final class CallParticipantsState {
|
public final class CallParticipantsState {
|
||||||
|
|
||||||
public static final CallParticipantsState STARTING_STATE = new CallParticipantsState(WebRtcViewModel.State.CALL_DISCONNECTED,
|
private static final int SMALL_GROUP_MAX = 6;
|
||||||
|
|
||||||
|
public static final CallParticipantsState STARTING_STATE = new CallParticipantsState(WebRtcViewModel.State.CALL_DISCONNECTED,
|
||||||
Collections.emptyList(),
|
Collections.emptyList(),
|
||||||
CallParticipant.createLocal(CameraState.UNKNOWN, new BroadcastVideoSink(null), false),
|
CallParticipant.createLocal(CameraState.UNKNOWN, new BroadcastVideoSink(null), false),
|
||||||
null,
|
null,
|
||||||
|
@ -55,21 +58,29 @@ public final class CallParticipantsState {
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull List<CallParticipant> getGridParticipants() {
|
public @NonNull List<CallParticipant> getGridParticipants() {
|
||||||
if (getAllRemoteParticipants().size() > 6) {
|
if (getAllRemoteParticipants().size() > SMALL_GROUP_MAX) {
|
||||||
return getAllRemoteParticipants().subList(0, 6);
|
return getAllRemoteParticipants().subList(0, SMALL_GROUP_MAX);
|
||||||
} else {
|
} else {
|
||||||
return getAllRemoteParticipants();
|
return getAllRemoteParticipants();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull List<CallParticipant> getListParticipants() {
|
public @NonNull List<CallParticipant> getListParticipants() {
|
||||||
|
List<CallParticipant> listParticipants = new ArrayList<>();
|
||||||
|
|
||||||
if (isViewingFocusedParticipant && getAllRemoteParticipants().size() > 1) {
|
if (isViewingFocusedParticipant && getAllRemoteParticipants().size() > 1) {
|
||||||
return getAllRemoteParticipants().subList(1, getAllRemoteParticipants().size());
|
listParticipants.addAll(getAllRemoteParticipants().subList(1, getAllRemoteParticipants().size()));
|
||||||
} else if (getAllRemoteParticipants().size() > 6) {
|
} else if (getAllRemoteParticipants().size() > SMALL_GROUP_MAX) {
|
||||||
return getAllRemoteParticipants().subList(6, getAllRemoteParticipants().size());
|
listParticipants.addAll(getAllRemoteParticipants().subList(SMALL_GROUP_MAX, getAllRemoteParticipants().size()));
|
||||||
} else {
|
} else {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listParticipants.add(CallParticipant.EMPTY);
|
||||||
|
|
||||||
|
Collections.reverse(listParticipants);
|
||||||
|
|
||||||
|
return listParticipants;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull List<CallParticipant> getAllRemoteParticipants() {
|
public @NonNull List<CallParticipant> getAllRemoteParticipants() {
|
||||||
|
@ -88,6 +99,10 @@ public final class CallParticipantsState {
|
||||||
return localRenderState;
|
return localRenderState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLargeVideoGroup() {
|
||||||
|
return getAllRemoteParticipants().size() > SMALL_GROUP_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isInPipMode() {
|
public boolean isInPipMode() {
|
||||||
return isInPipMode;
|
return isInPipMode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import android.view.VelocityTracker;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewConfiguration;
|
import android.view.ViewConfiguration;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||||
import android.view.animation.Interpolator;
|
import android.view.animation.Interpolator;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
@ -16,7 +17,6 @@ import androidx.core.view.GestureDetectorCompat;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.animation.AnimationCompleteListener;
|
import org.thoughtcrime.securesms.animation.AnimationCompleteListener;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
|
||||||
import org.thoughtcrime.securesms.util.views.TouchInterceptingFrameLayout;
|
import org.thoughtcrime.securesms.util.views.TouchInterceptingFrameLayout;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -26,11 +26,14 @@ import java.util.Queue;
|
||||||
|
|
||||||
public class PictureInPictureGestureHelper extends GestureDetector.SimpleOnGestureListener {
|
public class PictureInPictureGestureHelper extends GestureDetector.SimpleOnGestureListener {
|
||||||
|
|
||||||
private static final float DECELERATION_RATE = 0.99f;
|
private static final float DECELERATION_RATE = 0.99f;
|
||||||
|
private static final Interpolator FLING_INTERPOLATOR = new ViscousFluidInterpolator();
|
||||||
|
private static final Interpolator ADJUST_INTERPOLATOR = new AccelerateDecelerateInterpolator();
|
||||||
|
|
||||||
private final ViewGroup parent;
|
private final ViewGroup parent;
|
||||||
private final View child;
|
private final View child;
|
||||||
private final int framePadding;
|
private final int framePadding;
|
||||||
|
private final Queue<Runnable> runAfterFling;
|
||||||
|
|
||||||
private int pipWidth;
|
private int pipWidth;
|
||||||
private int pipHeight;
|
private int pipHeight;
|
||||||
|
@ -46,7 +49,7 @@ public class PictureInPictureGestureHelper extends GestureDetector.SimpleOnGestu
|
||||||
private VelocityTracker velocityTracker;
|
private VelocityTracker velocityTracker;
|
||||||
private int maximumFlingVelocity;
|
private int maximumFlingVelocity;
|
||||||
private boolean isLockedToBottomEnd;
|
private boolean isLockedToBottomEnd;
|
||||||
private Queue<Runnable> runAfterFling;
|
private Interpolator interpolator;
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
public static PictureInPictureGestureHelper applyTo(@NonNull View child) {
|
public static PictureInPictureGestureHelper applyTo(@NonNull View child) {
|
||||||
|
@ -101,6 +104,7 @@ public class PictureInPictureGestureHelper extends GestureDetector.SimpleOnGestu
|
||||||
this.pipHeight = child.getResources().getDimensionPixelSize(R.dimen.picture_in_picture_gesture_helper_pip_height);
|
this.pipHeight = child.getResources().getDimensionPixelSize(R.dimen.picture_in_picture_gesture_helper_pip_height);
|
||||||
this.maximumFlingVelocity = ViewConfiguration.get(child.getContext()).getScaledMaximumFlingVelocity();
|
this.maximumFlingVelocity = ViewConfiguration.get(child.getContext()).getScaledMaximumFlingVelocity();
|
||||||
this.runAfterFling = new LinkedList<>();
|
this.runAfterFling = new LinkedList<>();
|
||||||
|
this.interpolator = ADJUST_INTERPOLATOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearVerticalBoundaries() {
|
public void clearVerticalBoundaries() {
|
||||||
|
@ -130,8 +134,12 @@ public class PictureInPictureGestureHelper extends GestureDetector.SimpleOnGestu
|
||||||
pipHeight = child.getMeasuredHeight();
|
pipHeight = child.getMeasuredHeight();
|
||||||
|
|
||||||
if (isAnimating) {
|
if (isAnimating) {
|
||||||
|
interpolator = ADJUST_INTERPOLATOR;
|
||||||
|
|
||||||
fling();
|
fling();
|
||||||
} else if (!isDragging) {
|
} else if (!isDragging) {
|
||||||
|
interpolator = ADJUST_INTERPOLATOR;
|
||||||
|
|
||||||
onFling(null, null, 0, 0);
|
onFling(null, null, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,6 +168,7 @@ public class PictureInPictureGestureHelper extends GestureDetector.SimpleOnGestu
|
||||||
isDragging = true;
|
isDragging = true;
|
||||||
pipWidth = child.getMeasuredWidth();
|
pipWidth = child.getMeasuredWidth();
|
||||||
pipHeight = child.getMeasuredHeight();
|
pipHeight = child.getMeasuredHeight();
|
||||||
|
interpolator = FLING_INTERPOLATOR;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -216,7 +225,7 @@ public class PictureInPictureGestureHelper extends GestureDetector.SimpleOnGestu
|
||||||
.translationX(getTranslationXForPoint(nearestCornerPosition))
|
.translationX(getTranslationXForPoint(nearestCornerPosition))
|
||||||
.translationY(getTranslationYForPoint(nearestCornerPosition))
|
.translationY(getTranslationYForPoint(nearestCornerPosition))
|
||||||
.setDuration(250)
|
.setDuration(250)
|
||||||
.setInterpolator(new ViscousFluidInterpolator())
|
.setInterpolator(interpolator)
|
||||||
.setListener(new AnimationCompleteListener() {
|
.setListener(new AnimationCompleteListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationEnd(Animator animation) {
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
|
|
@ -14,13 +14,20 @@ import org.thoughtcrime.securesms.events.CallParticipant;
|
||||||
|
|
||||||
class WebRtcCallParticipantsRecyclerAdapter extends ListAdapter<CallParticipant, WebRtcCallParticipantsRecyclerAdapter.ViewHolder> {
|
class WebRtcCallParticipantsRecyclerAdapter extends ListAdapter<CallParticipant, WebRtcCallParticipantsRecyclerAdapter.ViewHolder> {
|
||||||
|
|
||||||
|
private static final int PARTICIPANT = 0;
|
||||||
|
private static final int EMPTY = 1;
|
||||||
|
|
||||||
protected WebRtcCallParticipantsRecyclerAdapter() {
|
protected WebRtcCallParticipantsRecyclerAdapter() {
|
||||||
super(new DiffCallback());
|
super(new DiffCallback());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
public @NonNull ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.webrtc_call_participant_recycler_item, parent, false));
|
if (viewType == PARTICIPANT) {
|
||||||
|
return new ParticipantViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.webrtc_call_participant_recycler_item, parent, false));
|
||||||
|
} else {
|
||||||
|
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.webrtc_call_participant_recycler_empty_item, parent, false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -28,15 +35,29 @@ class WebRtcCallParticipantsRecyclerAdapter extends ListAdapter<CallParticipant,
|
||||||
holder.bind(getItem(position));
|
holder.bind(getItem(position));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
return getItem(position) == CallParticipant.EMPTY ? EMPTY : PARTICIPANT;
|
||||||
|
}
|
||||||
|
|
||||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
ViewHolder(@NonNull View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bind(@NonNull CallParticipant callParticipant) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ParticipantViewHolder extends ViewHolder {
|
||||||
|
|
||||||
private final CallParticipantView callParticipantView;
|
private final CallParticipantView callParticipantView;
|
||||||
|
|
||||||
ViewHolder(@NonNull View itemView) {
|
ParticipantViewHolder(@NonNull View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
callParticipantView = itemView.findViewById(R.id.call_participant);
|
callParticipantView = itemView.findViewById(R.id.call_participant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
void bind(@NonNull CallParticipant callParticipant) {
|
void bind(@NonNull CallParticipant callParticipant) {
|
||||||
callParticipantView.setCallParticipant(callParticipant);
|
callParticipantView.setCallParticipant(callParticipant);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,10 @@ import androidx.constraintlayout.widget.Guideline;
|
||||||
import androidx.core.util.Consumer;
|
import androidx.core.util.Consumer;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import androidx.transition.AutoTransition;
|
import androidx.transition.AutoTransition;
|
||||||
|
import androidx.transition.ChangeBounds;
|
||||||
import androidx.transition.Transition;
|
import androidx.transition.Transition;
|
||||||
import androidx.transition.TransitionManager;
|
import androidx.transition.TransitionManager;
|
||||||
|
import androidx.transition.TransitionSet;
|
||||||
import androidx.viewpager2.widget.MarginPageTransformer;
|
import androidx.viewpager2.widget.MarginPageTransformer;
|
||||||
import androidx.viewpager2.widget.ViewPager2;
|
import androidx.viewpager2.widget.ViewPager2;
|
||||||
|
|
||||||
|
@ -51,6 +53,7 @@ public class WebRtcCallView extends FrameLayout {
|
||||||
|
|
||||||
public static final int FADE_OUT_DELAY = 5000;
|
public static final int FADE_OUT_DELAY = 5000;
|
||||||
public static final int PIP_RESIZE_DURATION = 300;
|
public static final int PIP_RESIZE_DURATION = 300;
|
||||||
|
public static final int CONTROLS_HEIGHT = 98;
|
||||||
|
|
||||||
private WebRtcAudioOutputToggleButton audioToggle;
|
private WebRtcAudioOutputToggleButton audioToggle;
|
||||||
private AccessibleToggleButton videoToggle;
|
private AccessibleToggleButton videoToggle;
|
||||||
|
@ -62,6 +65,7 @@ public class WebRtcCallView extends FrameLayout {
|
||||||
private TextView recipientName;
|
private TextView recipientName;
|
||||||
private TextView status;
|
private TextView status;
|
||||||
private ConstraintLayout parent;
|
private ConstraintLayout parent;
|
||||||
|
private ConstraintLayout participantsParent;
|
||||||
private ControlsListener controlsListener;
|
private ControlsListener controlsListener;
|
||||||
private RecipientId recipientId;
|
private RecipientId recipientId;
|
||||||
private ImageView answer;
|
private ImageView answer;
|
||||||
|
@ -75,6 +79,8 @@ public class WebRtcCallView extends FrameLayout {
|
||||||
private ViewPager2 callParticipantsPager;
|
private ViewPager2 callParticipantsPager;
|
||||||
private RecyclerView callParticipantsRecycler;
|
private RecyclerView callParticipantsRecycler;
|
||||||
private Toolbar toolbar;
|
private Toolbar toolbar;
|
||||||
|
private int pagerBottomMarginDp;
|
||||||
|
private boolean controlsVisible = true;
|
||||||
|
|
||||||
private WebRtcCallParticipantsPagerAdapter pagerAdapter;
|
private WebRtcCallParticipantsPagerAdapter pagerAdapter;
|
||||||
private WebRtcCallParticipantsRecyclerAdapter recyclerAdapter;
|
private WebRtcCallParticipantsRecyclerAdapter recyclerAdapter;
|
||||||
|
@ -114,6 +120,7 @@ public class WebRtcCallView extends FrameLayout {
|
||||||
recipientName = findViewById(R.id.call_screen_recipient_name);
|
recipientName = findViewById(R.id.call_screen_recipient_name);
|
||||||
status = findViewById(R.id.call_screen_status);
|
status = findViewById(R.id.call_screen_status);
|
||||||
parent = findViewById(R.id.call_screen);
|
parent = findViewById(R.id.call_screen);
|
||||||
|
participantsParent = findViewById(R.id.call_screen_participants_parent);
|
||||||
answer = findViewById(R.id.call_screen_answer_call);
|
answer = findViewById(R.id.call_screen_answer_call);
|
||||||
cameraDirectionToggle = findViewById(R.id.call_screen_camera_direction_toggle);
|
cameraDirectionToggle = findViewById(R.id.call_screen_camera_direction_toggle);
|
||||||
hangup = findViewById(R.id.call_screen_end_call);
|
hangup = findViewById(R.id.call_screen_end_call);
|
||||||
|
@ -229,6 +236,12 @@ public class WebRtcCallView extends FrameLayout {
|
||||||
pagerAdapter.submitList(pages);
|
pagerAdapter.submitList(pages);
|
||||||
recyclerAdapter.submitList(state.getListParticipants());
|
recyclerAdapter.submitList(state.getListParticipants());
|
||||||
updateLocalCallParticipant(state.getLocalRenderState(), state.getLocalParticipant());
|
updateLocalCallParticipant(state.getLocalRenderState(), state.getLocalParticipant());
|
||||||
|
|
||||||
|
if (state.isLargeVideoGroup()) {
|
||||||
|
layoutParticipantsForLargeCount();
|
||||||
|
} else {
|
||||||
|
layoutParticipantsForSmallCount();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateLocalCallParticipant(@NonNull WebRtcLocalRenderState state, @NonNull CallParticipant localCallParticipant) {
|
public void updateLocalCallParticipant(@NonNull WebRtcLocalRenderState state, @NonNull CallParticipant localCallParticipant) {
|
||||||
|
@ -371,6 +384,12 @@ public class WebRtcCallView extends FrameLayout {
|
||||||
updateButtonStateForLargeButtons();
|
updateButtonStateForLargeButtons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (webRtcControls.displayRemoteVideoRecycler()) {
|
||||||
|
callParticipantsRecycler.setVisibility(View.VISIBLE);
|
||||||
|
} else {
|
||||||
|
callParticipantsRecycler.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
if (webRtcControls.isFadeOutEnabled()) {
|
if (webRtcControls.isFadeOutEnabled()) {
|
||||||
if (!controls.isFadeOutEnabled()) {
|
if (!controls.isFadeOutEnabled()) {
|
||||||
scheduleFadeOut();
|
scheduleFadeOut();
|
||||||
|
@ -443,9 +462,44 @@ public class WebRtcCallView extends FrameLayout {
|
||||||
scheduleFadeOut();
|
scheduleFadeOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fadeControls(int visibility) {
|
private void layoutParticipantsForSmallCount() {
|
||||||
|
pagerBottomMarginDp = 0;
|
||||||
|
|
||||||
|
layoutParticipants();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void layoutParticipantsForLargeCount() {
|
||||||
|
pagerBottomMarginDp = 104;
|
||||||
|
|
||||||
|
layoutParticipants();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int withControlsHeight(int margin) {
|
||||||
|
if (margin == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return controlsVisible ? margin + CONTROLS_HEIGHT : margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void layoutParticipants() {
|
||||||
Transition transition = new AutoTransition().setDuration(TRANSITION_DURATION_MILLIS);
|
Transition transition = new AutoTransition().setDuration(TRANSITION_DURATION_MILLIS);
|
||||||
|
|
||||||
|
TransitionManager.beginDelayedTransition(participantsParent, transition);
|
||||||
|
|
||||||
|
ConstraintSet constraintSet = new ConstraintSet();
|
||||||
|
constraintSet.clone(participantsParent);
|
||||||
|
|
||||||
|
constraintSet.setMargin(R.id.call_screen_participants_pager, ConstraintSet.BOTTOM, ViewUtil.dpToPx(withControlsHeight(pagerBottomMarginDp)));
|
||||||
|
constraintSet.applyTo(participantsParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fadeControls(int visibility) {
|
||||||
|
controlsVisible = visibility == VISIBLE;
|
||||||
|
|
||||||
|
Transition transition = new AutoTransition().setOrdering(TransitionSet.ORDERING_TOGETHER)
|
||||||
|
.setDuration(TRANSITION_DURATION_MILLIS);
|
||||||
|
|
||||||
TransitionManager.beginDelayedTransition(parent, transition);
|
TransitionManager.beginDelayedTransition(parent, transition);
|
||||||
|
|
||||||
ConstraintSet constraintSet = new ConstraintSet();
|
ConstraintSet constraintSet = new ConstraintSet();
|
||||||
|
@ -456,6 +510,8 @@ public class WebRtcCallView extends FrameLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
constraintSet.applyTo(parent);
|
constraintSet.applyTo(parent);
|
||||||
|
|
||||||
|
layoutParticipants();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fadeInNewUiState(@NonNull Set<View> previouslyVisibleViewSet, boolean useSmallMargins) {
|
private void fadeInNewUiState(@NonNull Set<View> previouslyVisibleViewSet, boolean useSmallMargins) {
|
||||||
|
|
|
@ -147,6 +147,18 @@ public class WebRtcCallViewModel extends ViewModel {
|
||||||
callState = WebRtcControls.CallState.INCOMING;
|
callState = WebRtcControls.CallState.INCOMING;
|
||||||
answerWithVideoAvailable = isRemoteVideoOffer;
|
answerWithVideoAvailable = isRemoteVideoOffer;
|
||||||
break;
|
break;
|
||||||
|
case CALL_OUTGOING:
|
||||||
|
case CALL_RINGING:
|
||||||
|
callState = WebRtcControls.CallState.OUTGOING;
|
||||||
|
break;
|
||||||
|
case CALL_ACCEPTED_ELSEWHERE:
|
||||||
|
case CALL_DECLINED_ELSEWHERE:
|
||||||
|
case CALL_ONGOING_ELSEWHERE:
|
||||||
|
case CALL_NEEDS_PERMISSION:
|
||||||
|
case CALL_BUSY:
|
||||||
|
case CALL_DISCONNECTED:
|
||||||
|
callState = WebRtcControls.CallState.ENDING;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
callState = WebRtcControls.CallState.ONGOING;
|
callState = WebRtcControls.CallState.ONGOING;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,23 +41,27 @@ public final class WebRtcControls {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean displayEndCall() {
|
boolean displayEndCall() {
|
||||||
return isOngoing();
|
return isAtLeastOutgoing();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean displayMuteAudio() {
|
boolean displayMuteAudio() {
|
||||||
return isOngoing();
|
return isAtLeastOutgoing();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean displayVideoToggle() {
|
boolean displayVideoToggle() {
|
||||||
return isOngoing();
|
return isAtLeastOutgoing();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean displayAudioToggle() {
|
boolean displayAudioToggle() {
|
||||||
return isOngoing() && (!isLocalVideoEnabled || isBluetoothAvailable);
|
return isAtLeastOutgoing() && (!isLocalVideoEnabled || isBluetoothAvailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean displayCameraToggle() {
|
boolean displayCameraToggle() {
|
||||||
return isOngoing() && isLocalVideoEnabled && isMoreThanOneCameraAvailable;
|
return isAtLeastOutgoing() && isLocalVideoEnabled && isMoreThanOneCameraAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean displayRemoteVideoRecycler() {
|
||||||
|
return isOngoing();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean displayAnswerWithAudio() {
|
boolean displayAnswerWithAudio() {
|
||||||
|
@ -77,15 +81,15 @@ public final class WebRtcControls {
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isFadeOutEnabled() {
|
boolean isFadeOutEnabled() {
|
||||||
return isOngoing() && isRemoteVideoEnabled;
|
return isAtLeastOutgoing() && isRemoteVideoEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean displaySmallOngoingCallButtons() {
|
boolean displaySmallOngoingCallButtons() {
|
||||||
return isOngoing() && displayAudioToggle() && displayCameraToggle();
|
return isAtLeastOutgoing() && displayAudioToggle() && displayCameraToggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean displayLargeOngoingCallButtons() {
|
boolean displayLargeOngoingCallButtons() {
|
||||||
return isOngoing() && !(displayAudioToggle() && displayCameraToggle());
|
return isAtLeastOutgoing() && !(displayAudioToggle() && displayCameraToggle());
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean displayTopViews() {
|
boolean displayTopViews() {
|
||||||
|
@ -104,9 +108,19 @@ public final class WebRtcControls {
|
||||||
return callState == CallState.INCOMING;
|
return callState == CallState.INCOMING;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isAtLeastOutgoing() {
|
||||||
|
return callState.isAtLeast(CallState.OUTGOING);
|
||||||
|
}
|
||||||
|
|
||||||
public enum CallState {
|
public enum CallState {
|
||||||
NONE,
|
NONE,
|
||||||
INCOMING,
|
INCOMING,
|
||||||
ONGOING
|
OUTGOING,
|
||||||
|
ONGOING,
|
||||||
|
ENDING;
|
||||||
|
|
||||||
|
boolean isAtLeast(@NonNull CallState other) {
|
||||||
|
return compareTo(other) >= 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@ import java.util.Objects;
|
||||||
|
|
||||||
public class CallParticipant {
|
public class CallParticipant {
|
||||||
|
|
||||||
|
public static final CallParticipant EMPTY = createRemote(Recipient.UNKNOWN, null, new BroadcastVideoSink(null), false);
|
||||||
|
|
||||||
private final @NonNull CameraState cameraState;
|
private final @NonNull CameraState cameraState;
|
||||||
private final @NonNull Recipient recipient;
|
private final @NonNull Recipient recipient;
|
||||||
private final @Nullable IdentityKey identityKey;
|
private final @Nullable IdentityKey identityKey;
|
||||||
|
|
|
@ -78,6 +78,7 @@ import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserExce
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Space xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="72dp"
|
||||||
|
android:layout_height="72dp"
|
||||||
|
tools:background="@color/red"
|
||||||
|
tools:visibility="visible" />
|
|
@ -11,6 +11,7 @@
|
||||||
android:background="@color/transparent_black_40" />
|
android:background="@color/transparent_black_40" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/call_screen_participants_parent"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
@ -24,19 +25,6 @@
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
android:orientation="vertical" />
|
android:orientation="vertical" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/call_screen_participants_recycler"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="72dp"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:reverseLayout="true"
|
|
||||||
tools:listitem="@layout/webrtc_call_participant_recycler_item" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
@ -93,6 +81,20 @@
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/call_screen_participants_recycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="72dp"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/call_screen_video_toggle"
|
||||||
|
app:reverseLayout="true"
|
||||||
|
tools:listitem="@layout/webrtc_call_participant_recycler_item" />
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.util.views.TouchInterceptingFrameLayout
|
<org.thoughtcrime.securesms.util.views.TouchInterceptingFrameLayout
|
||||||
android:id="@+id/call_screen_pip_area"
|
android:id="@+id/call_screen_pip_area"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|
|
@ -148,7 +148,7 @@
|
||||||
|
|
||||||
<dimen name="debug_log_text_size">12sp</dimen>
|
<dimen name="debug_log_text_size">12sp</dimen>
|
||||||
|
|
||||||
<dimen name="picture_in_picture_gesture_helper_frame_padding">12dp</dimen>
|
<dimen name="picture_in_picture_gesture_helper_frame_padding">16dp</dimen>
|
||||||
<dimen name="picture_in_picture_gesture_helper_pip_width">90dp</dimen>
|
<dimen name="picture_in_picture_gesture_helper_pip_width">90dp</dimen>
|
||||||
<dimen name="picture_in_picture_gesture_helper_pip_height">160dp</dimen>
|
<dimen name="picture_in_picture_gesture_helper_pip_height">160dp</dimen>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue