mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-26 22:20:20 +00:00
Fix call buttons overflowing bottom sheet.
This commit is contained in:
@@ -136,10 +136,8 @@ public class WebRtcCallView extends InsetAwareConstraintLayout {
|
||||
private final Set<View> topViews = new HashSet<>();
|
||||
private final Set<View> visibleViewSet = new HashSet<>();
|
||||
private final Set<View> allTimeVisibleViews = new HashSet<>();
|
||||
private final Set<View> adjustableMarginsSet = new HashSet<>();
|
||||
private final Set<View> rotatableControls = new HashSet<>();
|
||||
|
||||
|
||||
private final ThrottledDebouncer throttledDebouncer = new ThrottledDebouncer(TRANSITION_DURATION_MILLIS);
|
||||
private WebRtcControls controls = WebRtcControls.NONE;
|
||||
|
||||
@@ -243,11 +241,6 @@ public class WebRtcCallView extends InsetAwareConstraintLayout {
|
||||
incomingCallViews.add(footerGradient);
|
||||
incomingCallViews.add(incomingRingStatus);
|
||||
|
||||
adjustableMarginsSet.add(micToggle);
|
||||
adjustableMarginsSet.add(cameraDirectionToggle);
|
||||
adjustableMarginsSet.add(videoToggle);
|
||||
adjustableMarginsSet.add(audioToggle);
|
||||
|
||||
audioToggle.setOnAudioOutputChangedListener(webRtcAudioDevice -> {
|
||||
runIfNonNull(controlsListener, listener ->
|
||||
{
|
||||
@@ -703,8 +696,6 @@ public class WebRtcCallView extends InsetAwareConstraintLayout {
|
||||
}
|
||||
|
||||
if (webRtcControls.displayAudioToggle()) {
|
||||
visibleViewSet.add(audioToggle);
|
||||
|
||||
audioToggle.setControlAvailability(webRtcControls.isEarpieceAvailableForAudioToggle(),
|
||||
webRtcControls.isBluetoothHeadsetAvailableForAudioToggle(),
|
||||
webRtcControls.isWiredHeadsetAvailableForAudioToggle());
|
||||
@@ -712,30 +703,9 @@ public class WebRtcCallView extends InsetAwareConstraintLayout {
|
||||
audioToggle.updateAudioOutputState(webRtcControls.getAudioOutput());
|
||||
}
|
||||
|
||||
if (webRtcControls.displayCameraToggle()) {
|
||||
visibleViewSet.add(cameraDirectionToggle);
|
||||
}
|
||||
|
||||
if (webRtcControls.displayEndCall()) {
|
||||
visibleViewSet.add(hangup);
|
||||
visibleViewSet.add(footerGradient);
|
||||
}
|
||||
|
||||
if (webRtcControls.displayOverflow()) {
|
||||
visibleViewSet.add(overflow);
|
||||
}
|
||||
|
||||
if (webRtcControls.displayMuteAudio()) {
|
||||
visibleViewSet.add(micToggle);
|
||||
}
|
||||
|
||||
if (webRtcControls.displayVideoToggle()) {
|
||||
visibleViewSet.add(videoToggle);
|
||||
}
|
||||
|
||||
if (webRtcControls.displaySmallOngoingCallButtons()) {
|
||||
if (webRtcControls.displaySmallCallButtons()) {
|
||||
updateButtonStateForSmallButtons();
|
||||
} else if (webRtcControls.displayLargeOngoingCallButtons()) {
|
||||
} else {
|
||||
updateButtonStateForLargeButtons();
|
||||
}
|
||||
|
||||
@@ -753,10 +723,6 @@ public class WebRtcCallView extends InsetAwareConstraintLayout {
|
||||
fullScreenShade.setVisibility(GONE);
|
||||
}
|
||||
|
||||
if (webRtcControls.displayRingToggle()) {
|
||||
visibleViewSet.add(ringToggle);
|
||||
}
|
||||
|
||||
if (webRtcControls.displayReactions()) {
|
||||
visibleViewSet.add(reactionViews);
|
||||
visibleViewSet.add(groupReactionsFeed);
|
||||
@@ -777,7 +743,7 @@ public class WebRtcCallView extends InsetAwareConstraintLayout {
|
||||
(!webRtcControls.showSmallHeader() && largeHeaderAvatar.getVisibility() == View.GONE) ||
|
||||
forceUpdate)
|
||||
{
|
||||
throttledDebouncer.publish(() -> fadeInNewUiState(webRtcControls.displaySmallOngoingCallButtons(), webRtcControls.showSmallHeader()));
|
||||
throttledDebouncer.publish(() -> fadeInNewUiState(webRtcControls.showSmallHeader()));
|
||||
}
|
||||
|
||||
onWindowSystemUiVisibilityChanged(getWindowSystemUiVisibility());
|
||||
@@ -871,20 +837,13 @@ public class WebRtcCallView extends InsetAwareConstraintLayout {
|
||||
constraintSet.applyTo(this);
|
||||
}
|
||||
|
||||
private void fadeInNewUiState(boolean useSmallMargins, boolean showSmallHeader) {
|
||||
private void fadeInNewUiState(boolean showSmallHeader) {
|
||||
for (View view : SetUtil.difference(allTimeVisibleViews, visibleViewSet)) {
|
||||
view.setVisibility(GONE);
|
||||
}
|
||||
|
||||
for (View view : visibleViewSet) {
|
||||
view.setVisibility(VISIBLE);
|
||||
|
||||
if (adjustableMarginsSet.contains(view)) {
|
||||
MarginLayoutParams params = (MarginLayoutParams) view.getLayoutParams();
|
||||
params.setMarginEnd(ViewUtil.dpToPx(useSmallMargins ? SMALL_ONGOING_CALL_BUTTON_MARGIN_DP
|
||||
: LARGE_ONGOING_CALL_BUTTON_MARGIN_DP));
|
||||
view.setLayoutParams(params);
|
||||
}
|
||||
}
|
||||
|
||||
if (showSmallHeader) {
|
||||
@@ -918,6 +877,7 @@ public class WebRtcCallView extends InsetAwareConstraintLayout {
|
||||
videoToggle.setBackgroundResource(R.drawable.webrtc_call_screen_video_toggle);
|
||||
audioToggle.setImageResource(R.drawable.webrtc_call_screen_speaker_toggle);
|
||||
ringToggle.setBackgroundResource(R.drawable.webrtc_call_screen_ring_toggle);
|
||||
overflow.setBackgroundResource(R.drawable.webrtc_call_screen_overflow_menu);
|
||||
}
|
||||
|
||||
private void updateButtonStateForSmallButtons() {
|
||||
@@ -928,6 +888,7 @@ public class WebRtcCallView extends InsetAwareConstraintLayout {
|
||||
videoToggle.setBackgroundResource(R.drawable.webrtc_call_screen_video_toggle_small);
|
||||
audioToggle.setImageResource(R.drawable.webrtc_call_screen_speaker_toggle_small);
|
||||
ringToggle.setBackgroundResource(R.drawable.webrtc_call_screen_ring_toggle_small);
|
||||
overflow.setBackgroundResource(R.drawable.webrtc_call_screen_overflow_menu_small);
|
||||
}
|
||||
|
||||
public void switchToSpeakerView() {
|
||||
|
||||
@@ -204,12 +204,8 @@ public final class WebRtcControls {
|
||||
return isAtLeastOutgoing() && isRemoteVideoEnabled && callState != CallState.RECONNECTING;
|
||||
}
|
||||
|
||||
public boolean displaySmallOngoingCallButtons() {
|
||||
return isAtLeastOutgoing() && displayAudioToggle() && displayCameraToggle();
|
||||
}
|
||||
|
||||
public boolean displayLargeOngoingCallButtons() {
|
||||
return isAtLeastOutgoing() && !(displayAudioToggle() && displayCameraToggle());
|
||||
public boolean displaySmallCallButtons() {
|
||||
return displayedButtonCount() >= 5;
|
||||
}
|
||||
|
||||
public boolean displayTopViews() {
|
||||
@@ -269,6 +265,16 @@ public final class WebRtcControls {
|
||||
return groupCallState != GroupCallState.NONE;
|
||||
}
|
||||
|
||||
private int displayedButtonCount() {
|
||||
return (displayAudioToggle() ? 1 : 0) +
|
||||
(displayCameraToggle() ? 1 : 0) +
|
||||
(displayVideoToggle() ? 1 : 0) +
|
||||
(displayMuteAudio() ? 1 : 0) +
|
||||
(displayRingToggle() ? 1 : 0) +
|
||||
(displayOverflow() ? 1 : 0) +
|
||||
(displayEndCall() ? 1 : 0);
|
||||
}
|
||||
|
||||
public enum CallState {
|
||||
NONE,
|
||||
ERROR,
|
||||
|
||||
@@ -9,14 +9,20 @@ import android.content.res.ColorStateList
|
||||
import android.os.Handler
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.annotation.Px
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.transition.AutoTransition
|
||||
import androidx.transition.TransitionManager
|
||||
import androidx.transition.TransitionSet
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehaviorHack
|
||||
@@ -52,6 +58,7 @@ class ControlsAndInfoController(
|
||||
private const val CONTROL_FADE_OUT_DONE = 0.23f
|
||||
private const val INFO_FADE_IN_START = CONTROL_FADE_OUT_DONE
|
||||
private const val INFO_FADE_IN_DONE = 0.8f
|
||||
private const val CONTROL_TRANSITION_DURATION = 250L
|
||||
|
||||
private val HIDE_CONTROL_DELAY = 5.seconds.inWholeMilliseconds
|
||||
}
|
||||
@@ -215,6 +222,14 @@ class ControlsAndInfoController(
|
||||
val previousState = controlState
|
||||
controlState = newControlState
|
||||
|
||||
showOrHideControlsOnUpdate(previousState)
|
||||
|
||||
if (controlState.controlVisibilitiesChanged(previousState)) {
|
||||
updateControlVisibilities()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showOrHideControlsOnUpdate(previousState: WebRtcControls) {
|
||||
if (controlState == WebRtcControls.PIP) {
|
||||
hide()
|
||||
return
|
||||
@@ -241,6 +256,32 @@ class ControlsAndInfoController(
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateControlVisibilities() {
|
||||
TransitionManager.endTransitions(callControls)
|
||||
TransitionManager.beginDelayedTransition(
|
||||
callControls,
|
||||
AutoTransition().apply {
|
||||
ordering = TransitionSet.ORDERING_TOGETHER
|
||||
duration = CONTROL_TRANSITION_DURATION
|
||||
}
|
||||
)
|
||||
|
||||
val constraints = ConstraintSet().apply {
|
||||
clone(callControls)
|
||||
val margin = if (controlState.displaySmallCallButtons()) 4.dp else 8.dp
|
||||
|
||||
setControlConstraints(R.id.call_screen_speaker_toggle, controlState.displayAudioToggle(), margin)
|
||||
setControlConstraints(R.id.call_screen_camera_direction_toggle, controlState.displayCameraToggle(), margin)
|
||||
setControlConstraints(R.id.call_screen_video_toggle, controlState.displayVideoToggle(), margin)
|
||||
setControlConstraints(R.id.call_screen_audio_mic_toggle, controlState.displayMuteAudio(), margin)
|
||||
setControlConstraints(R.id.call_screen_audio_ring_toggle, controlState.displayRingToggle(), margin)
|
||||
setControlConstraints(R.id.call_screen_overflow_button, controlState.displayOverflow(), margin)
|
||||
setControlConstraints(R.id.call_screen_end_call, controlState.displayEndCall(), margin)
|
||||
}
|
||||
|
||||
constraints.applyTo(callControls)
|
||||
}
|
||||
|
||||
private fun onScheduledHide() {
|
||||
if (behavior.state != BottomSheetBehavior.STATE_EXPANDED && !isDisposed) {
|
||||
hide()
|
||||
@@ -279,6 +320,22 @@ class ControlsAndInfoController(
|
||||
return disposables.isDisposed
|
||||
}
|
||||
|
||||
private fun ConstraintSet.setControlConstraints(@IdRes viewId: Int, visible: Boolean, @Px horizontalMargins: Int) {
|
||||
setVisibility(viewId, if (visible) View.VISIBLE else View.GONE)
|
||||
setMargin(viewId, ConstraintSet.START, horizontalMargins)
|
||||
setMargin(viewId, ConstraintSet.END, horizontalMargins)
|
||||
}
|
||||
|
||||
private fun WebRtcControls.controlVisibilitiesChanged(previousState: WebRtcControls): Boolean {
|
||||
return displayAudioToggle() != previousState.displayAudioToggle() ||
|
||||
displayCameraToggle() != previousState.displayCameraToggle() ||
|
||||
displayVideoToggle() != previousState.displayVideoToggle() ||
|
||||
displayMuteAudio() != previousState.displayMuteAudio() ||
|
||||
displayRingToggle() != previousState.displayRingToggle() ||
|
||||
displayOverflow() != previousState.displayOverflow() ||
|
||||
displayEndCall() != previousState.displayEndCall()
|
||||
}
|
||||
|
||||
interface BottomSheetVisibilityListener {
|
||||
fun onShown()
|
||||
fun onHidden()
|
||||
|
||||
@@ -36,15 +36,14 @@
|
||||
android:id="@+id/call_info_compose"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="38dp"
|
||||
android:orientation="vertical" />
|
||||
android:paddingTop="38dp" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/call_controls_constraint_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="48dp"
|
||||
android:layout_marginTop="38dp">
|
||||
android:layout_marginTop="38dp"
|
||||
android:paddingBottom="48dp">
|
||||
|
||||
<org.thoughtcrime.securesms.components.webrtc.WebRtcAudioOutputToggleButton
|
||||
android:id="@+id/call_screen_speaker_toggle"
|
||||
@@ -73,13 +72,11 @@
|
||||
android:clickable="false"
|
||||
android:contentDescription="@string/WebRtcCallView__toggle_camera_direction"
|
||||
android:scaleType="fitXY"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/call_screen_start_call_controls"
|
||||
app:layout_constraintEnd_toStartOf="@id/call_screen_video_toggle"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toEndOf="@id/call_screen_speaker_toggle"
|
||||
app:srcCompat="@drawable/webrtc_call_screen_camera_toggle"
|
||||
tools:visibility="visible" />
|
||||
app:srcCompat="@drawable/webrtc_call_screen_camera_toggle" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.AccessibleToggleButton
|
||||
android:id="@+id/call_screen_video_toggle"
|
||||
@@ -90,13 +87,11 @@
|
||||
android:background="@drawable/webrtc_call_screen_video_toggle"
|
||||
android:contentDescription="@string/WebRtcCallView__toggle_camera"
|
||||
android:stateListAnimator="@null"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/call_screen_start_call_controls"
|
||||
app:layout_constraintEnd_toStartOf="@id/call_screen_audio_mic_toggle"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toEndOf="@id/call_screen_camera_direction_toggle"
|
||||
tools:checked="true"
|
||||
tools:visibility="visible" />
|
||||
tools:checked="true" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.AccessibleToggleButton
|
||||
android:id="@+id/call_screen_audio_mic_toggle"
|
||||
@@ -107,12 +102,10 @@
|
||||
android:background="@drawable/webrtc_call_screen_mic_toggle"
|
||||
android:contentDescription="@string/WebRtcCallView__toggle_mute"
|
||||
android:stateListAnimator="@null"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toTopOf="@id/call_screen_start_call_controls"
|
||||
app:layout_constraintEnd_toStartOf="@id/call_screen_audio_ring_toggle"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toEndOf="@id/call_screen_video_toggle"
|
||||
tools:visibility="visible" />
|
||||
app:layout_constraintStart_toEndOf="@id/call_screen_video_toggle" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.AccessibleToggleButton
|
||||
android:id="@+id/call_screen_audio_ring_toggle"
|
||||
@@ -126,7 +119,8 @@
|
||||
app:layout_constraintBottom_toTopOf="@id/call_screen_start_call_controls"
|
||||
app:layout_constraintEnd_toStartOf="@id/call_screen_overflow_button"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toEndOf="@id/call_screen_audio_mic_toggle" />
|
||||
app:layout_constraintStart_toEndOf="@id/call_screen_audio_mic_toggle"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/call_screen_overflow_button"
|
||||
@@ -135,19 +129,17 @@
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="30dp"
|
||||
android:background="@drawable/webrtc_call_screen_overflow_menu"
|
||||
android:clickable="false"
|
||||
android:contentDescription="@string/WebRtcCallView__additional_actions"
|
||||
android:scaleType="fitXY"
|
||||
android:visibility="gone"
|
||||
android:background="@drawable/webrtc_call_screen_circle_checked"
|
||||
app:layout_constraintBottom_toTopOf="@id/call_screen_start_call_controls"
|
||||
app:layout_constraintEnd_toStartOf="@id/call_screen_end_call"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toEndOf="@id/call_screen_audio_ring_toggle"
|
||||
app:srcCompat="@drawable/symbol_more_24"
|
||||
tools:visibility="visible" />
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/call_screen_end_call"
|
||||
android:layout_width="@dimen/webrtc_button_size"
|
||||
|
||||
Reference in New Issue
Block a user