mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-22 03:58:48 +00:00
Update audio indicator for new designs.
This commit is contained in:
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.components.webrtc
|
||||
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
@@ -10,6 +11,7 @@ import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.animation.DecelerateInterpolator
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import org.signal.core.util.DimensionUnit
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.events.CallParticipant
|
||||
@@ -31,9 +33,9 @@ class AudioIndicatorView(context: Context, attrs: AttributeSet) : FrameLayout(co
|
||||
}
|
||||
|
||||
private val barRect = RectF()
|
||||
private val barWidth = DimensionUnit.DP.toPixels(4f)
|
||||
private val barWidth = DimensionUnit.DP.toPixels(3f)
|
||||
private val barRadius = DimensionUnit.DP.toPixels(32f)
|
||||
private val barPadding = DimensionUnit.DP.toPixels(4f)
|
||||
private val barPadding = DimensionUnit.DP.toPixels(3f)
|
||||
private var middleBarAnimation: ValueAnimator? = null
|
||||
private var sideBarAnimation: ValueAnimator? = null
|
||||
|
||||
@@ -43,6 +45,9 @@ class AudioIndicatorView(context: Context, attrs: AttributeSet) : FrameLayout(co
|
||||
init {
|
||||
inflate(context, R.layout.audio_indicator_view, this)
|
||||
setWillNotDraw(false)
|
||||
|
||||
setBackgroundResource(R.drawable.circle_tintable)
|
||||
backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(context, R.color.transparent_black_70))
|
||||
}
|
||||
|
||||
private val micMuted: View = findViewById(R.id.mic_muted)
|
||||
@@ -55,11 +60,11 @@ class AudioIndicatorView(context: Context, attrs: AttributeSet) : FrameLayout(co
|
||||
|
||||
if (showAudioLevel) {
|
||||
val scaleFactor = when (level!!) {
|
||||
CallParticipant.AudioLevel.LOWEST -> 0.2f
|
||||
CallParticipant.AudioLevel.LOW -> 0.4f
|
||||
CallParticipant.AudioLevel.MEDIUM -> 0.6f
|
||||
CallParticipant.AudioLevel.HIGH -> 0.8f
|
||||
CallParticipant.AudioLevel.HIGHEST -> 1.0f
|
||||
CallParticipant.AudioLevel.LOWEST -> 0.1f
|
||||
CallParticipant.AudioLevel.LOW -> 0.3f
|
||||
CallParticipant.AudioLevel.MEDIUM -> 0.5f
|
||||
CallParticipant.AudioLevel.HIGH -> 0.65f
|
||||
CallParticipant.AudioLevel.HIGHEST -> 0.8f
|
||||
}
|
||||
|
||||
middleBarAnimation?.end()
|
||||
|
||||
@@ -9,12 +9,13 @@ import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.constraintlayout.widget.ConstraintSet;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.view.ViewKt;
|
||||
import androidx.core.widget.ImageViewCompat;
|
||||
import androidx.transition.Transition;
|
||||
import androidx.transition.TransitionManager;
|
||||
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
@@ -37,6 +38,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.AvatarUtil;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.webrtc.RendererCommon;
|
||||
import org.whispersystems.signalservice.api.util.Preconditions;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -57,6 +59,8 @@ public class CallParticipantView extends ConstraintLayout {
|
||||
private boolean infoMode;
|
||||
private Runnable missingMediaKeysUpdater;
|
||||
|
||||
private SelfPipMode selfPipMode = SelfPipMode.NOT_SELF_PIP;
|
||||
|
||||
private AppCompatImageView backgroundAvatar;
|
||||
private AvatarImageView avatar;
|
||||
private BadgeImageView badge;
|
||||
@@ -211,6 +215,85 @@ public class CallParticipantView extends ConstraintLayout {
|
||||
pipBadge.setVisibility(shouldRenderInPip ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust UI elements for the various self PIP positions. If called after a {@link TransitionManager#beginDelayedTransition(ViewGroup, Transition)},
|
||||
* the changes to the UI elements will animate.
|
||||
*/
|
||||
void setSelfPipMode(@NonNull SelfPipMode selfPipMode) {
|
||||
Preconditions.checkArgument(selfPipMode != SelfPipMode.NOT_SELF_PIP);
|
||||
|
||||
if (this.selfPipMode == selfPipMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.selfPipMode = selfPipMode;
|
||||
|
||||
ConstraintSet constraints = new ConstraintSet();
|
||||
constraints.clone(this);
|
||||
|
||||
switch (selfPipMode) {
|
||||
case NORMAL_SELF_PIP -> {
|
||||
constraints.connect(
|
||||
R.id.call_participant_audio_indicator,
|
||||
ConstraintSet.START,
|
||||
ConstraintSet.PARENT_ID,
|
||||
ConstraintSet.START,
|
||||
ViewUtil.dpToPx(6)
|
||||
);
|
||||
constraints.clear(
|
||||
R.id.call_participant_audio_indicator,
|
||||
ConstraintSet.END
|
||||
);
|
||||
constraints.setMargin(
|
||||
R.id.call_participant_audio_indicator,
|
||||
ConstraintSet.BOTTOM,
|
||||
ViewUtil.dpToPx(6)
|
||||
);
|
||||
}
|
||||
case EXPANDED_SELF_PIP -> {
|
||||
constraints.connect(
|
||||
R.id.call_participant_audio_indicator,
|
||||
ConstraintSet.START,
|
||||
ConstraintSet.PARENT_ID,
|
||||
ConstraintSet.START,
|
||||
ViewUtil.dpToPx(8)
|
||||
);
|
||||
constraints.clear(
|
||||
R.id.call_participant_audio_indicator,
|
||||
ConstraintSet.END
|
||||
);
|
||||
constraints.setMargin(
|
||||
R.id.call_participant_audio_indicator,
|
||||
ConstraintSet.BOTTOM,
|
||||
ViewUtil.dpToPx(8)
|
||||
);
|
||||
}
|
||||
case MINI_SELF_PIP -> {
|
||||
constraints.connect(
|
||||
R.id.call_participant_audio_indicator,
|
||||
ConstraintSet.START,
|
||||
ConstraintSet.PARENT_ID,
|
||||
ConstraintSet.START,
|
||||
0
|
||||
);
|
||||
constraints.connect(
|
||||
R.id.call_participant_audio_indicator,
|
||||
ConstraintSet.END,
|
||||
ConstraintSet.PARENT_ID,
|
||||
ConstraintSet.END,
|
||||
0
|
||||
);
|
||||
constraints.setMargin(
|
||||
R.id.call_participant_audio_indicator,
|
||||
ConstraintSet.BOTTOM,
|
||||
ViewUtil.dpToPx(6)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
constraints.applyTo(this);
|
||||
}
|
||||
|
||||
void hideAvatar() {
|
||||
avatar.setAlpha(0f);
|
||||
badge.setAlpha(0f);
|
||||
@@ -302,4 +385,11 @@ public class CallParticipantView extends ConstraintLayout {
|
||||
return photo;
|
||||
}
|
||||
}
|
||||
|
||||
public enum SelfPipMode {
|
||||
NOT_SELF_PIP,
|
||||
NORMAL_SELF_PIP,
|
||||
EXPANDED_SELF_PIP,
|
||||
MINI_SELF_PIP
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,14 @@ package org.thoughtcrime.securesms.components.webrtc;
|
||||
import android.graphics.Point;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Animation;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.transition.AutoTransition;
|
||||
import androidx.transition.Transition;
|
||||
import androidx.transition.TransitionListenerAdapter;
|
||||
import androidx.transition.TransitionManager;
|
||||
|
||||
import org.thoughtcrime.securesms.animation.ResizeAnimation;
|
||||
import org.thoughtcrime.securesms.mediasend.SimpleAnimationListener;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
/**
|
||||
@@ -22,7 +23,14 @@ final class PictureInPictureExpansionHelper {
|
||||
private static final int EXPANDED_PIP_WIDTH_DP = 170;
|
||||
private static final int EXPANDED_PIP_HEIGHT_DP = 300;
|
||||
|
||||
public static final int NORMAL_PIP_WIDTH_DP = 90;
|
||||
public static final int NORMAL_PIP_HEIGHT_DP = 160;
|
||||
|
||||
public static final int MINI_PIP_WIDTH_DP = 40;
|
||||
public static final int MINI_PIP_HEIGHT_DP = 72;
|
||||
|
||||
private final View selfPip;
|
||||
private final ViewGroup parent;
|
||||
private final Point expandedDimensions;
|
||||
|
||||
private State state = State.IS_SHRUNKEN;
|
||||
@@ -30,6 +38,7 @@ final class PictureInPictureExpansionHelper {
|
||||
|
||||
public PictureInPictureExpansionHelper(@NonNull View selfPip) {
|
||||
this.selfPip = selfPip;
|
||||
this.parent = (ViewGroup) selfPip.getParent();
|
||||
this.defaultDimensions = new Point(selfPip.getLayoutParams().width, selfPip.getLayoutParams().height);
|
||||
this.expandedDimensions = new Point(ViewUtil.dpToPx(EXPANDED_PIP_WIDTH_DP), ViewUtil.dpToPx(EXPANDED_PIP_HEIGHT_DP));
|
||||
}
|
||||
@@ -42,7 +51,11 @@ final class PictureInPictureExpansionHelper {
|
||||
return state == State.IS_SHRUNKEN || state == State.IS_SHRINKING;
|
||||
}
|
||||
|
||||
public void setDefaultSize(@NonNull Point dimensions, @NonNull Callback callback) {
|
||||
public boolean isMiniSize() {
|
||||
return defaultDimensions.x < ViewUtil.dpToPx(NORMAL_PIP_WIDTH_DP);
|
||||
}
|
||||
|
||||
public void startDefaultSizeTransition(@NonNull Point dimensions, @NonNull Callback callback) {
|
||||
if (defaultDimensions.equals(dimensions)) {
|
||||
return;
|
||||
}
|
||||
@@ -53,21 +66,15 @@ final class PictureInPictureExpansionHelper {
|
||||
return;
|
||||
}
|
||||
|
||||
ViewGroup.LayoutParams layoutParams = selfPip.getLayoutParams();
|
||||
if (layoutParams.width == defaultDimensions.x && layoutParams.height == defaultDimensions.y) {
|
||||
callback.onAnimationHasFinished();
|
||||
return;
|
||||
beginResizeSelfPipTransition(defaultDimensions, callback);
|
||||
}
|
||||
|
||||
resizeSelfPip(defaultDimensions, callback);
|
||||
}
|
||||
|
||||
public void expand() {
|
||||
public void beginExpandTransition() {
|
||||
if (isExpandedOrExpanding()) {
|
||||
return;
|
||||
}
|
||||
|
||||
resizeSelfPip(expandedDimensions, new Callback() {
|
||||
beginResizeSelfPipTransition(expandedDimensions, new Callback() {
|
||||
@Override
|
||||
public void onAnimationWillStart() {
|
||||
state = State.IS_EXPANDING;
|
||||
@@ -80,12 +87,12 @@ final class PictureInPictureExpansionHelper {
|
||||
});
|
||||
}
|
||||
|
||||
public void shrink() {
|
||||
public void beginShrinkTransition() {
|
||||
if (isShrunkenOrShrinking()) {
|
||||
return;
|
||||
}
|
||||
|
||||
resizeSelfPip(defaultDimensions, new Callback() {
|
||||
beginResizeSelfPipTransition(defaultDimensions, new Callback() {
|
||||
@Override
|
||||
public void onAnimationWillStart() {
|
||||
state = State.IS_SHRINKING;
|
||||
@@ -98,23 +105,30 @@ final class PictureInPictureExpansionHelper {
|
||||
});
|
||||
}
|
||||
|
||||
private void resizeSelfPip(@NonNull Point dimension, @NonNull Callback callback) {
|
||||
ResizeAnimation resizeAnimation = new ResizeAnimation(selfPip, dimension);
|
||||
resizeAnimation.setDuration(PIP_RESIZE_DURATION_MS);
|
||||
resizeAnimation.setAnimationListener(new SimpleAnimationListener() {
|
||||
private void beginResizeSelfPipTransition(@NonNull Point dimension, @NonNull Callback callback) {
|
||||
TransitionManager.endTransitions(parent);
|
||||
|
||||
Transition transition = new AutoTransition().setDuration(PIP_RESIZE_DURATION_MS);
|
||||
transition.addListener(new TransitionListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animation animation) {
|
||||
public void onTransitionStart(@NonNull Transition transition) {
|
||||
callback.onAnimationWillStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
public void onTransitionEnd(@NonNull Transition transition) {
|
||||
callback.onAnimationHasFinished();
|
||||
}
|
||||
});
|
||||
|
||||
selfPip.clearAnimation();
|
||||
selfPip.startAnimation(resizeAnimation);
|
||||
TransitionManager.beginDelayedTransition(parent, transition);
|
||||
|
||||
ViewGroup.LayoutParams params = selfPip.getLayoutParams();
|
||||
|
||||
params.width = dimension.x;
|
||||
params.height = dimension.y;
|
||||
|
||||
selfPip.setLayoutParams(params);
|
||||
}
|
||||
|
||||
enum State {
|
||||
|
||||
@@ -497,21 +497,22 @@ public class WebRtcCallView extends InsetAwareConstraintLayout {
|
||||
|
||||
videoToggle.setChecked(localCallParticipant.isVideoEnabled(), false);
|
||||
smallLocalRender.setRenderInPip(true);
|
||||
smallLocalRender.setCallParticipant(localCallParticipant);
|
||||
smallLocalRender.setMirror(localCallParticipant.getCameraDirection() == CameraState.Direction.FRONT);
|
||||
|
||||
if (state == WebRtcLocalRenderState.EXPANDED) {
|
||||
pictureInPictureExpansionHelper.expand();
|
||||
pictureInPictureExpansionHelper.beginExpandTransition();
|
||||
smallLocalRender.setSelfPipMode(CallParticipantView.SelfPipMode.EXPANDED_SELF_PIP);
|
||||
return;
|
||||
} else if ((state.isAnySmall() || state == WebRtcLocalRenderState.GONE) && pictureInPictureExpansionHelper.isExpandedOrExpanding()) {
|
||||
pictureInPictureExpansionHelper.shrink();
|
||||
pictureInPictureExpansionHelper.beginShrinkTransition();
|
||||
smallLocalRender.setSelfPipMode(pictureInPictureExpansionHelper.isMiniSize() ? CallParticipantView.SelfPipMode.MINI_SELF_PIP : CallParticipantView.SelfPipMode.NORMAL_SELF_PIP);
|
||||
|
||||
if (state != WebRtcLocalRenderState.GONE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
smallLocalRender.setCallParticipant(localCallParticipant);
|
||||
smallLocalRender.setMirror(localCallParticipant.getCameraDirection() == CameraState.Direction.FRONT);
|
||||
|
||||
switch (state) {
|
||||
case GONE:
|
||||
largeLocalRender.attachBroadcastVideoSink(null);
|
||||
@@ -806,26 +807,34 @@ public class WebRtcCallView extends InsetAwareConstraintLayout {
|
||||
private void animatePipToLargeRectangle(boolean isLandscape) {
|
||||
final Point dimens;
|
||||
if (isLandscape) {
|
||||
dimens = new Point(ViewUtil.dpToPx(160), ViewUtil.dpToPx(90));
|
||||
dimens = new Point(ViewUtil.dpToPx(PictureInPictureExpansionHelper.NORMAL_PIP_HEIGHT_DP),
|
||||
ViewUtil.dpToPx(PictureInPictureExpansionHelper.NORMAL_PIP_WIDTH_DP));
|
||||
} else {
|
||||
dimens = new Point(ViewUtil.dpToPx(90), ViewUtil.dpToPx(160));
|
||||
dimens = new Point(ViewUtil.dpToPx(PictureInPictureExpansionHelper.NORMAL_PIP_WIDTH_DP),
|
||||
ViewUtil.dpToPx(PictureInPictureExpansionHelper.NORMAL_PIP_HEIGHT_DP));
|
||||
}
|
||||
|
||||
pictureInPictureExpansionHelper.setDefaultSize(dimens, new PictureInPictureExpansionHelper.Callback() {
|
||||
pictureInPictureExpansionHelper.startDefaultSizeTransition(dimens, new PictureInPictureExpansionHelper.Callback() {
|
||||
@Override
|
||||
public void onAnimationHasFinished() {
|
||||
pictureInPictureGestureHelper.enableCorners();
|
||||
}
|
||||
});
|
||||
|
||||
smallLocalRender.setSelfPipMode(CallParticipantView.SelfPipMode.NORMAL_SELF_PIP);
|
||||
}
|
||||
|
||||
private void animatePipToSmallRectangle() {
|
||||
pictureInPictureExpansionHelper.setDefaultSize(new Point(ViewUtil.dpToPx(54), ViewUtil.dpToPx(72)), new PictureInPictureExpansionHelper.Callback() {
|
||||
pictureInPictureExpansionHelper.startDefaultSizeTransition(new Point(ViewUtil.dpToPx(PictureInPictureExpansionHelper.MINI_PIP_WIDTH_DP),
|
||||
ViewUtil.dpToPx(PictureInPictureExpansionHelper.MINI_PIP_HEIGHT_DP)),
|
||||
new PictureInPictureExpansionHelper.Callback() {
|
||||
@Override
|
||||
public void onAnimationHasFinished() {
|
||||
pictureInPictureGestureHelper.lockToBottomEnd();
|
||||
}
|
||||
});
|
||||
|
||||
smallLocalRender.setSelfPipMode(CallParticipantView.SelfPipMode.MINI_SELF_PIP);
|
||||
}
|
||||
|
||||
private void toggleControls() {
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="16dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="16">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M4.85 7.5V7.32l3.32 3.33H8c-1.74 0-3.15-1.41-3.15-3.15Z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M8 11.85c0.42 0 0.82-0.06 1.2-0.17l1.02 1.02c-0.49 0.2-1.02 0.35-1.57 0.41v0.99h2.1c0.36 0 0.65 0.3 0.65 0.65 0 0.36-0.3 0.65-0.65 0.65h-5.5c-0.36 0-0.65-0.3-0.65-0.65 0-0.36 0.3-0.65 0.65-0.65h2.1v-0.99c-2.81-0.32-5-2.7-5-5.61V6.75C2.35 6.39 2.65 6.1 3 6.1c0.36 0 0.65 0.3 0.65 0.65V7.5c0 2.4 1.95 4.35 4.35 4.35Z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M11.9 9.43l0.96 0.95c0.5-0.84 0.79-1.83 0.79-2.88V6.75c0-0.36-0.3-0.65-0.65-0.65-0.36 0-0.65 0.3-0.65 0.65V7.5c0 0.7-0.16 1.35-0.45 1.93Z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M5.07 2.6l5.91 5.91c0.11-0.32 0.17-0.66 0.17-1.01V3.75C11.15 2.01 9.74 0.6 8 0.6c-1.33 0-2.47 0.83-2.93 2Z"/>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M2.46 1.54c-0.25-0.25-0.67-0.25-0.92 0s-0.25 0.67 0 0.92l12 12c0.25 0.25 0.67 0.25 0.92 0s0.25-0.67 0-0.92l-12-12Z"/>
|
||||
</vector>
|
||||
@@ -5,8 +5,8 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/mic_muted"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="16dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="center"
|
||||
app:srcCompat="@drawable/ic_mic_off_solid_18"
|
||||
app:srcCompat="@drawable/symbol_mic_slash_fill_compact_16"
|
||||
app:tint="@color/core_white" />
|
||||
|
||||
@@ -86,8 +86,8 @@
|
||||
|
||||
<org.thoughtcrime.securesms.components.webrtc.AudioIndicatorView
|
||||
android:id="@+id/call_participant_audio_indicator"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_width="28dp"
|
||||
android:layout_height="28dp"
|
||||
android:layout_marginStart="@dimen/webrtc_audio_indicator_margin"
|
||||
android:layout_marginBottom="@dimen/webrtc_audio_indicator_margin"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Space xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<android.widget.Space xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:viewBindingIgnore="true"
|
||||
android:layout_width="54dp"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="72dp"
|
||||
tools:background="@color/red_500"
|
||||
tools:visibility="visible" />
|
||||
@@ -196,7 +196,7 @@
|
||||
<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="webrtc_audio_indicator_margin">8dp</dimen>
|
||||
|
||||
<dimen name="segmentedprogressbar_default_segment_margin">8dp</dimen>
|
||||
<dimen name="segmentedprogressbar_default_corner_radius">0dp</dimen>
|
||||
|
||||
Reference in New Issue
Block a user