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 5e8d4132ed76e30f8d662975873a50685c7099d3..6b6648f9eb8e3ca70d7c0fa3c701014a578da987 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 @@ -13,7 +13,9 @@ import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.AppCompatImageView; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.content.ContextCompat; +import androidx.core.view.ViewKt; import androidx.core.widget.ImageViewCompat; +import androidx.transition.TransitionManager; import com.bumptech.glide.load.engine.DiskCacheStrategy; @@ -226,6 +228,17 @@ public class CallParticipantView extends ConstraintLayout { changeAvatarParams(SMALL_AVATAR); } + void setBottomInset(int bottomInset) { + int desiredMargin = getResources().getDimensionPixelSize(R.dimen.webrtc_audio_indicator_margin) + bottomInset; + if (ViewKt.getMarginBottom(audioIndicator) == desiredMargin) { + return; + } + + TransitionManager.beginDelayedTransition(this); + + ViewUtil.setBottomMargin(audioIndicator, desiredMargin); + } + void releaseRenderer() { renderer.release(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/CallParticipantsLayout.java b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/CallParticipantsLayout.java index 5f9e3f4e0e540c6b74cfdf7df2bda1ca9c29d8e9..0c3928c74564a9e44704fe69be41a1e252148668 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/CallParticipantsLayout.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/CallParticipantsLayout.java @@ -34,6 +34,7 @@ public class CallParticipantsLayout extends FlexboxLayout { private boolean shouldRenderInPip; private boolean isPortrait; private boolean isIncomingRing; + private int navBarBottomInset; private LayoutStrategy layoutStrategy; public CallParticipantsLayout(@NonNull Context context) { @@ -53,6 +54,7 @@ public class CallParticipantsLayout extends FlexboxLayout { boolean shouldRenderInPip, boolean isPortrait, boolean isIncomingRing, + int navBarBottomInset, @NonNull LayoutStrategy layoutStrategy) { this.callParticipants = callParticipants; @@ -60,6 +62,7 @@ public class CallParticipantsLayout extends FlexboxLayout { this.shouldRenderInPip = shouldRenderInPip; this.isPortrait = isPortrait; this.isIncomingRing = isIncomingRing; + this.navBarBottomInset = navBarBottomInset; this.layoutStrategy = layoutStrategy; setFlexDirection(layoutStrategy.getFlexDirection()); @@ -123,9 +126,11 @@ public class CallParticipantsLayout extends FlexboxLayout { if (count > 1) { view.setPadding(MULTIPLE_PARTICIPANT_SPACING, MULTIPLE_PARTICIPANT_SPACING, MULTIPLE_PARTICIPANT_SPACING, MULTIPLE_PARTICIPANT_SPACING); cardView.setRadius(CORNER_RADIUS); + callParticipantView.setBottomInset(0); } else { view.setPadding(0, 0, 0, 0); cardView.setRadius(0); + callParticipantView.setBottomInset(navBarBottomInset); } if (isIncomingRing) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallParticipantsPage.java b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallParticipantsPage.java index e4741dd8c20fcb5150eeba90370d26f2969da6f2..eba951c4b9e182c023ecdd995dbb1dbb9f12773a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallParticipantsPage.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallParticipantsPage.java @@ -17,15 +17,17 @@ class WebRtcCallParticipantsPage { private final boolean isPortrait; private final boolean isLandscapeEnabled; private final boolean isIncomingRing; + private final int navBarBottomInset; static WebRtcCallParticipantsPage forMultipleParticipants(@NonNull List<CallParticipant> callParticipants, @NonNull CallParticipant focusedParticipant, boolean isRenderInPip, boolean isPortrait, boolean isLandscapeEnabled, - boolean isIncomingRing) + boolean isIncomingRing, + int navBarBottomInset) { - return new WebRtcCallParticipantsPage(callParticipants, focusedParticipant, false, isRenderInPip, isPortrait, isLandscapeEnabled, isIncomingRing); + return new WebRtcCallParticipantsPage(callParticipants, focusedParticipant, false, isRenderInPip, isPortrait, isLandscapeEnabled, isIncomingRing, navBarBottomInset); } static WebRtcCallParticipantsPage forSingleParticipant(@NonNull CallParticipant singleParticipant, @@ -33,7 +35,7 @@ class WebRtcCallParticipantsPage { boolean isPortrait, boolean isLandscapeEnabled) { - return new WebRtcCallParticipantsPage(Collections.singletonList(singleParticipant), singleParticipant, true, isRenderInPip, isPortrait, isLandscapeEnabled, false); + return new WebRtcCallParticipantsPage(Collections.singletonList(singleParticipant), singleParticipant, true, isRenderInPip, isPortrait, isLandscapeEnabled, false, 0); } private WebRtcCallParticipantsPage(@NonNull List<CallParticipant> callParticipants, @@ -42,7 +44,8 @@ class WebRtcCallParticipantsPage { boolean isRenderInPip, boolean isPortrait, boolean isLandscapeEnabled, - boolean isIncomingRing) + boolean isIncomingRing, + int navBarBottomInset) { this.callParticipants = callParticipants; this.focusedParticipant = focusedParticipant; @@ -51,6 +54,7 @@ class WebRtcCallParticipantsPage { this.isPortrait = isPortrait; this.isLandscapeEnabled = isLandscapeEnabled; this.isIncomingRing = isIncomingRing; + this.navBarBottomInset = navBarBottomInset; } public @NonNull List<CallParticipant> getCallParticipants() { @@ -77,6 +81,10 @@ class WebRtcCallParticipantsPage { return isIncomingRing; } + public int getNavBarBottomInset() { + return navBarBottomInset; + } + public @NonNull CallParticipantsLayout.LayoutStrategy getLayoutStrategy() { return CallParticipantsLayoutStrategies.getStrategy(isPortrait, isLandscapeEnabled); } @@ -92,11 +100,12 @@ class WebRtcCallParticipantsPage { isLandscapeEnabled == that.isLandscapeEnabled && isIncomingRing == that.isIncomingRing && callParticipants.equals(that.callParticipants) && - focusedParticipant.equals(that.focusedParticipant); + focusedParticipant.equals(that.focusedParticipant) && + navBarBottomInset == that.navBarBottomInset; } @Override public int hashCode() { - return Objects.hash(callParticipants, focusedParticipant, isSpeaker, isRenderInPip, isPortrait, isLandscapeEnabled, isIncomingRing); + return Objects.hash(callParticipants, focusedParticipant, isSpeaker, isRenderInPip, isPortrait, isLandscapeEnabled, isIncomingRing, navBarBottomInset); } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallParticipantsPagerAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallParticipantsPagerAdapter.java index de45c1dc718692c9c99760fbedf19385a7f94efc..93b941af24823a9fd7e67967888ba4c5ecd53b01 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallParticipantsPagerAdapter.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/webrtc/WebRtcCallParticipantsPagerAdapter.java @@ -86,7 +86,7 @@ class WebRtcCallParticipantsPagerAdapter extends ListAdapter<WebRtcCallParticipa @Override void bind(WebRtcCallParticipantsPage page) { - callParticipantsLayout.update(page.getCallParticipants(), page.getFocusedParticipant(), page.isRenderInPip(), page.isPortrait(), page.isIncomingRing(), page.getLayoutStrategy()); + callParticipantsLayout.update(page.getCallParticipants(), page.getFocusedParticipant(), page.isRenderInPip(), page.isPortrait(), page.isIncomingRing(), page.getNavBarBottomInset(), page.getLayoutStrategy()); } } 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 c2d2fc97f9d151d4b040583e624063ea1344b3b7..8f2a49a8058fb0b8f14888176bade67c9d2a61b4 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 @@ -8,6 +8,7 @@ import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; +import android.view.WindowInsets; import android.view.animation.Animation; import android.widget.FrameLayout; import android.widget.ImageView; @@ -21,6 +22,7 @@ import androidx.constraintlayout.widget.ConstraintSet; import androidx.constraintlayout.widget.Guideline; import androidx.core.util.Consumer; import androidx.core.view.ViewKt; +import androidx.core.view.WindowInsetsCompat; import androidx.recyclerview.widget.DefaultItemAnimator; import androidx.recyclerview.widget.RecyclerView; import androidx.transition.AutoTransition; @@ -122,6 +124,7 @@ public class WebRtcCallView extends ConstraintLayout { private ConstraintSet largeHeaderConstraints; private ConstraintSet smallHeaderConstraints; private Guideline statusBarGuideline; + private int navBarBottomInset; private View fullScreenShade; private WebRtcCallParticipantsPagerAdapter pagerAdapter; @@ -142,6 +145,8 @@ public class WebRtcCallView extends ConstraintLayout { if (isAttachedToWindow() && controls.isFadeOutEnabled()) fadeOutControls(); }; + private CallParticipantsViewState lastState; + public WebRtcCallView(@NonNull Context context) { this(context, null); } @@ -333,6 +338,19 @@ public class WebRtcCallView extends ConstraintLayout { return true; } + @Override + public WindowInsets onApplyWindowInsets(WindowInsets insets) { + if (android.os.Build.VERSION.SDK_INT >= 20) { + navBarBottomInset = WindowInsetsCompat.toWindowInsetsCompat(insets).getInsets(WindowInsetsCompat.Type.navigationBars()).bottom; + + if (lastState != null) { + updateCallParticipants(lastState); + } + } + + return super.onApplyWindowInsets(insets); + } + @Override public void onWindowSystemUiVisibilityChanged(int visible) { if ((visible & SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) { @@ -371,13 +389,15 @@ public class WebRtcCallView extends ConstraintLayout { } public void updateCallParticipants(@NonNull CallParticipantsViewState callParticipantsViewState) { + lastState = callParticipantsViewState; + CallParticipantsState state = callParticipantsViewState.getCallParticipantsState(); boolean isPortrait = callParticipantsViewState.isPortrait(); boolean isLandscapeEnabled = callParticipantsViewState.isLandscapeEnabled(); List<WebRtcCallParticipantsPage> pages = new ArrayList<>(2); if (!state.getGridParticipants().isEmpty()) { - pages.add(WebRtcCallParticipantsPage.forMultipleParticipants(state.getGridParticipants(), state.getFocusedParticipant(), state.isInPipMode(), isPortrait, isLandscapeEnabled, state.isIncomingRing())); + pages.add(WebRtcCallParticipantsPage.forMultipleParticipants(state.getGridParticipants(), state.getFocusedParticipant(), state.isInPipMode(), isPortrait, isLandscapeEnabled, state.isIncomingRing(), navBarBottomInset)); } if (state.getFocusedParticipant() != CallParticipant.EMPTY && state.getAllRemoteParticipants().size() > 1) { diff --git a/app/src/main/res/layout/call_participant_item.xml b/app/src/main/res/layout/call_participant_item.xml index 10d7977f68806ec1c363fe6bffa816cd51e04f6e..48dfa8cc3189e31512eb9b9fae25c8b31847d2d9 100644 --- a/app/src/main/res/layout/call_participant_item.xml +++ b/app/src/main/res/layout/call_participant_item.xml @@ -87,8 +87,8 @@ android:id="@+id/call_participant_audio_indicator" android:layout_width="20dp" android:layout_height="20dp" - android:layout_marginStart="14dp" - android:layout_marginBottom="14dp" + android:layout_marginStart="@dimen/webrtc_audio_indicator_margin" + android:layout_marginBottom="@dimen/webrtc_audio_indicator_margin" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" /> diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index d709eb2da6f51f60d886d2981d9d43a6b14d25ee..47665dcf72d80ba673ba7693cc7981f20774cf38 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -213,7 +213,9 @@ <dimen name="verify_identity_vertical_margin">16dp</dimen> <dimen name="signal_context_menu_corner_radius">18dp</dimen> + <dimen name="webrtc_button_size">48dp</dimen> + <dimen name="webrtc_audio_indicator_margin">14dp</dimen> <dimen name="segmentedprogressbar_default_segment_margin">8dp</dimen> <dimen name="segmentedprogressbar_default_corner_radius">0dp</dimen>