Handle blocked users in group calls.
This commit is contained in:
parent
01f143667f
commit
050fad3114
13 changed files with 183 additions and 33 deletions
|
@ -116,7 +116,7 @@
|
|||
<meta-data android:name="firebase_messaging_auto_init_enabled" android:value="false" />
|
||||
|
||||
<activity android:name=".WebRtcCallActivity"
|
||||
android:theme="@style/TextSecure.LightTheme.WebRTCCall"
|
||||
android:theme="@style/TextSecure.DarkTheme.WebRTCCall"
|
||||
android:excludeFromRecents="true"
|
||||
android:screenOrientation="portrait"
|
||||
android:supportsPictureInPicture="true"
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.thoughtcrime.securesms;
|
|||
|
||||
import android.Manifest;
|
||||
import android.app.PictureInPictureParams;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
|
@ -32,6 +33,7 @@ import android.view.WindowManager;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
||||
|
@ -77,6 +79,12 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
|
|||
private WebRtcCallViewModel viewModel;
|
||||
private boolean enableVideoIfAvailable;
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(@NonNull Context newBase) {
|
||||
getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);
|
||||
super.attachBaseContext(newBase);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
Log.i(TAG, "onCreate()");
|
||||
|
|
|
@ -4,16 +4,22 @@ import android.content.Context;
|
|||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
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.core.content.ContextCompat;
|
||||
import androidx.core.widget.ImageViewCompat;
|
||||
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
|
||||
|
@ -39,12 +45,18 @@ public class CallParticipantView extends ConstraintLayout {
|
|||
private static final int SMALL_AVATAR = ViewUtil.dpToPx(96);
|
||||
private static final int LARGE_AVATAR = ViewUtil.dpToPx(112);
|
||||
|
||||
private RecipientId recipientId;
|
||||
private RecipientId recipientId;
|
||||
private boolean infoMode;
|
||||
|
||||
private AvatarImageView avatar;
|
||||
private TextureViewRenderer renderer;
|
||||
private ImageView pipAvatar;
|
||||
private ContactPhoto contactPhoto;
|
||||
private View audioMuted;
|
||||
private View infoOverlay;
|
||||
private EmojiTextView infoMessage;
|
||||
private Button infoMoreInfo;
|
||||
private AppCompatImageView infoIcon;
|
||||
|
||||
public CallParticipantView(@NonNull Context context) {
|
||||
super(context);
|
||||
|
@ -62,10 +74,14 @@ public class CallParticipantView extends ConstraintLayout {
|
|||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
avatar = findViewById(R.id.call_participant_item_avatar);
|
||||
pipAvatar = findViewById(R.id.call_participant_item_pip_avatar);
|
||||
renderer = findViewById(R.id.call_participant_renderer);
|
||||
audioMuted = findViewById(R.id.call_participant_mic_muted);
|
||||
avatar = findViewById(R.id.call_participant_item_avatar);
|
||||
pipAvatar = findViewById(R.id.call_participant_item_pip_avatar);
|
||||
renderer = findViewById(R.id.call_participant_renderer);
|
||||
audioMuted = findViewById(R.id.call_participant_mic_muted);
|
||||
infoOverlay = findViewById(R.id.call_participant_info_overlay);
|
||||
infoIcon = findViewById(R.id.call_participant_info_icon);
|
||||
infoMessage = findViewById(R.id.call_participant_info_message);
|
||||
infoMoreInfo = findViewById(R.id.call_participant_info_more_info);
|
||||
|
||||
avatar.setFallbackPhotoProvider(FALLBACK_PHOTO_PROVIDER);
|
||||
useLargeAvatar();
|
||||
|
@ -82,16 +98,43 @@ 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();
|
||||
|
||||
renderer.setVisibility(participant.isVideoEnabled() ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (participant.isVideoEnabled()) {
|
||||
if (participant.getVideoSink().getEglBase() != null) {
|
||||
renderer.init(participant.getVideoSink().getEglBase());
|
||||
}
|
||||
renderer.attachBroadcastVideoSink(participant.getVideoSink());
|
||||
} else {
|
||||
if (infoMode) {
|
||||
renderer.setVisibility(View.GONE);
|
||||
renderer.attachBroadcastVideoSink(null);
|
||||
audioMuted.setVisibility(View.GONE);
|
||||
avatar.setVisibility(View.GONE);
|
||||
pipAvatar.setVisibility(View.GONE);
|
||||
|
||||
infoOverlay.setVisibility(View.VISIBLE);
|
||||
|
||||
ImageViewCompat.setImageTintList(infoIcon, ContextCompat.getColorStateList(getContext(), R.color.core_white));
|
||||
|
||||
if (participant.getRecipient().isBlocked()) {
|
||||
infoIcon.setImageResource(R.drawable.ic_block_tinted_24);
|
||||
infoMessage.setText(getContext().getString(R.string.CallParticipantView__s_is_blocked, participant.getRecipient().getShortDisplayName(getContext())));
|
||||
infoMoreInfo.setOnClickListener(v -> showBlockedDialog(participant.getRecipient()));
|
||||
} else {
|
||||
infoIcon.setImageResource(R.drawable.ic_error_solid_24);
|
||||
infoMessage.setText(getContext().getString(R.string.CallParticipantView__cant_receive_audio_video_from_s, participant.getRecipient().getShortDisplayName(getContext())));
|
||||
infoMoreInfo.setOnClickListener(v -> showNoMediaKeysDialog(participant.getRecipient()));
|
||||
}
|
||||
} else {
|
||||
infoOverlay.setVisibility(View.GONE);
|
||||
|
||||
renderer.setVisibility(participant.isVideoEnabled() ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (participant.isVideoEnabled()) {
|
||||
if (participant.getVideoSink().getEglBase() != null) {
|
||||
renderer.init(participant.getVideoSink().getEglBase());
|
||||
}
|
||||
renderer.attachBroadcastVideoSink(participant.getVideoSink());
|
||||
} else {
|
||||
renderer.attachBroadcastVideoSink(null);
|
||||
}
|
||||
|
||||
audioMuted.setVisibility(participant.isMicrophoneEnabled() ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
if (participantChanged || !Objects.equals(contactPhoto, participant.getRecipient().getContactPhoto())) {
|
||||
|
@ -100,11 +143,15 @@ public class CallParticipantView extends ConstraintLayout {
|
|||
setPipAvatar(participant.getRecipient());
|
||||
contactPhoto = participant.getRecipient().getContactPhoto();
|
||||
}
|
||||
|
||||
audioMuted.setVisibility(participant.isMicrophoneEnabled() ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
void setRenderInPip(boolean shouldRenderInPip) {
|
||||
if (infoMode) {
|
||||
infoMessage.setVisibility(shouldRenderInPip ? View.GONE : View.VISIBLE);
|
||||
infoMoreInfo.setVisibility(shouldRenderInPip ? View.GONE : View.VISIBLE);
|
||||
return;
|
||||
}
|
||||
|
||||
avatar.setVisibility(shouldRenderInPip ? View.GONE : View.VISIBLE);
|
||||
pipAvatar.setVisibility(shouldRenderInPip ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
@ -146,6 +193,22 @@ public class CallParticipantView extends ConstraintLayout {
|
|||
pipAvatar.setBackgroundColor(recipient.getColor().toActionBarColor(getContext()));
|
||||
}
|
||||
|
||||
private void showBlockedDialog(@NonNull Recipient recipient) {
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setTitle(getContext().getString(R.string.CallParticipantView__s_is_blocked, recipient.getShortDisplayName(getContext())))
|
||||
.setMessage(R.string.CallParticipantView__you_wont_receive_their_audio_or_video)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void showNoMediaKeysDialog(@NonNull Recipient recipient) {
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setTitle(getContext().getString(R.string.CallParticipantView__cant_receive_audio_and_video_from_s, recipient.getShortDisplayName(getContext())))
|
||||
.setMessage(R.string.CallParticipantView__this_may_be_Because_they_have_not_verified_your_safety_number_change)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private static final class FallbackPhotoProvider extends Recipient.FallbackPhotoProvider {
|
||||
@Override
|
||||
public @NonNull FallbackContactPhoto getPhotoForLocalNumber() {
|
||||
|
|
|
@ -10,9 +10,9 @@ import org.whispersystems.libsignal.IdentityKey;
|
|||
|
||||
import java.util.Objects;
|
||||
|
||||
public class CallParticipant {
|
||||
public final class CallParticipant {
|
||||
|
||||
public static final CallParticipant EMPTY = createRemote(Recipient.UNKNOWN, null, new BroadcastVideoSink(null), false, false, 0);
|
||||
public static final CallParticipant EMPTY = createRemote(Recipient.UNKNOWN, null, new BroadcastVideoSink(null), false, false, 0, true);
|
||||
|
||||
private final @NonNull CameraState cameraState;
|
||||
private final @NonNull Recipient recipient;
|
||||
|
@ -21,6 +21,7 @@ public class CallParticipant {
|
|||
private final boolean videoEnabled;
|
||||
private final boolean microphoneEnabled;
|
||||
private final long lastSpoke;
|
||||
private final boolean mediaKeysReceived;
|
||||
|
||||
public static @NonNull CallParticipant createLocal(@NonNull CameraState cameraState,
|
||||
@NonNull BroadcastVideoSink renderer,
|
||||
|
@ -32,7 +33,8 @@ public class CallParticipant {
|
|||
cameraState,
|
||||
cameraState.isEnabled() && cameraState.getCameraCount() > 0,
|
||||
microphoneEnabled,
|
||||
0);
|
||||
0,
|
||||
true);
|
||||
}
|
||||
|
||||
public static @NonNull CallParticipant createRemote(@NonNull Recipient recipient,
|
||||
|
@ -40,9 +42,10 @@ public class CallParticipant {
|
|||
@NonNull BroadcastVideoSink renderer,
|
||||
boolean audioEnabled,
|
||||
boolean videoEnabled,
|
||||
long lastSpoke)
|
||||
long lastSpoke,
|
||||
boolean mediaKeysReceived)
|
||||
{
|
||||
return new CallParticipant(recipient, identityKey, renderer, CameraState.UNKNOWN, videoEnabled, audioEnabled, lastSpoke);
|
||||
return new CallParticipant(recipient, identityKey, renderer, CameraState.UNKNOWN, videoEnabled, audioEnabled, lastSpoke, mediaKeysReceived);
|
||||
}
|
||||
|
||||
private CallParticipant(@NonNull Recipient recipient,
|
||||
|
@ -51,7 +54,8 @@ public class CallParticipant {
|
|||
@NonNull CameraState cameraState,
|
||||
boolean videoEnabled,
|
||||
boolean microphoneEnabled,
|
||||
long lastSpoke)
|
||||
long lastSpoke,
|
||||
boolean mediaKeysReceived)
|
||||
{
|
||||
this.recipient = recipient;
|
||||
this.identityKey = identityKey;
|
||||
|
@ -60,14 +64,15 @@ public class CallParticipant {
|
|||
this.videoEnabled = videoEnabled;
|
||||
this.microphoneEnabled = microphoneEnabled;
|
||||
this.lastSpoke = lastSpoke;
|
||||
this.mediaKeysReceived = mediaKeysReceived;
|
||||
}
|
||||
|
||||
public @NonNull CallParticipant withIdentityKey(@NonNull IdentityKey identityKey) {
|
||||
return new CallParticipant(recipient, identityKey, videoSink, cameraState, videoEnabled, microphoneEnabled, lastSpoke);
|
||||
return new CallParticipant(recipient, identityKey, videoSink, cameraState, videoEnabled, microphoneEnabled, lastSpoke, mediaKeysReceived);
|
||||
}
|
||||
|
||||
public @NonNull CallParticipant withVideoEnabled(boolean videoEnabled) {
|
||||
return new CallParticipant(recipient, identityKey, videoSink, cameraState, videoEnabled, microphoneEnabled, lastSpoke);
|
||||
return new CallParticipant(recipient, identityKey, videoSink, cameraState, videoEnabled, microphoneEnabled, lastSpoke, mediaKeysReceived);
|
||||
}
|
||||
|
||||
public @NonNull Recipient getRecipient() {
|
||||
|
@ -109,6 +114,10 @@ public class CallParticipant {
|
|||
return lastSpoke;
|
||||
}
|
||||
|
||||
public boolean isMediaKeysReceived() {
|
||||
return mediaKeysReceived;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
@ -117,6 +126,7 @@ public class CallParticipant {
|
|||
return videoEnabled == that.videoEnabled &&
|
||||
microphoneEnabled == that.microphoneEnabled &&
|
||||
lastSpoke == that.lastSpoke &&
|
||||
mediaKeysReceived == that.mediaKeysReceived &&
|
||||
cameraState.equals(that.cameraState) &&
|
||||
recipient.equals(that.recipient) &&
|
||||
Objects.equals(identityKey, that.identityKey) &&
|
||||
|
@ -125,7 +135,7 @@ public class CallParticipant {
|
|||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(cameraState, recipient, identityKey, videoSink, videoEnabled, microphoneEnabled, lastSpoke);
|
||||
return Objects.hash(cameraState, recipient, identityKey, videoSink, videoEnabled, microphoneEnabled, lastSpoke, mediaKeysReceived);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -137,6 +147,8 @@ public class CallParticipant {
|
|||
", videoSink=" + (videoSink.getEglBase() == null ? "not initialized" : "initialized") +
|
||||
", videoEnabled=" + videoEnabled +
|
||||
", microphoneEnabled=" + microphoneEnabled +
|
||||
", lastSpoke=" + lastSpoke +
|
||||
", mediaKeysReceived=" + mediaKeysReceived +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ public class GroupCallUpdateSendJob extends BaseJob {
|
|||
|
||||
List<RecipientId> recipients = Stream.of(RecipientUtil.getEligibleForSending(conversationRecipient.getParticipants()))
|
||||
.filterNot(Recipient::isSelf)
|
||||
.filterNot(Recipient::isBlocked)
|
||||
.map(Recipient::getId)
|
||||
.toList();
|
||||
|
||||
|
|
|
@ -444,6 +444,10 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
|
|||
{
|
||||
Callable<Boolean> callable = () -> {
|
||||
Recipient recipient = remotePeer.getRecipient();
|
||||
if (recipient.isBlocked()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
messageSender.sendCallMessage(RecipientUtil.toSignalServiceAddress(WebRtcCallService.this, recipient),
|
||||
UnidentifiedAccessUtil.getAccessFor(WebRtcCallService.this, recipient),
|
||||
callMessage);
|
||||
|
|
|
@ -46,7 +46,8 @@ public class BeginCallActionProcessorDelegate extends WebRtcActionProcessor {
|
|||
new BroadcastVideoSink(currentState.getVideoState().getEglBase()),
|
||||
true,
|
||||
false,
|
||||
0
|
||||
0,
|
||||
true
|
||||
))
|
||||
.build();
|
||||
|
||||
|
@ -86,7 +87,8 @@ public class BeginCallActionProcessorDelegate extends WebRtcActionProcessor {
|
|||
new BroadcastVideoSink(currentState.getVideoState().getEglBase()),
|
||||
true,
|
||||
false,
|
||||
0
|
||||
0,
|
||||
true
|
||||
))
|
||||
.build();
|
||||
}
|
||||
|
|
|
@ -70,7 +70,8 @@ public class GroupActionProcessor extends DeviceAwareActionProcessor {
|
|||
videoSink,
|
||||
Boolean.FALSE.equals(device.getAudioMuted()),
|
||||
Boolean.FALSE.equals(device.getVideoMuted()),
|
||||
device.getSpeakerTime()));
|
||||
device.getSpeakerTime(),
|
||||
device.getMediaKeysReceived()));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
|
|
|
@ -114,7 +114,7 @@ public class GroupPreJoinActionProcessor extends GroupActionProcessor {
|
|||
.changeCallInfoState();
|
||||
|
||||
for (Recipient recipient : callParticipants) {
|
||||
builder.putParticipant(recipient, CallParticipant.createRemote(recipient, null, new BroadcastVideoSink(null), true, true, 0));
|
||||
builder.putParticipant(recipient, CallParticipant.createRemote(recipient, null, new BroadcastVideoSink(null), true, true, 0, false));
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
|
|
9
app/src/main/res/drawable/ic_error_solid_24.xml
Normal file
9
app/src/main/res/drawable/ic_error_solid_24.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,1A11,11 0,1 0,23 12,11 11,0 0,0 12,1ZM13.25,6 L12.75,13.5h-1.5L10.75,6ZM12,18a1.5,1.5 0,1 1,1.5 -1.5A1.5,1.5 0,0 1,12 18Z"/>
|
||||
</vector>
|
|
@ -44,9 +44,51 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
app:srcCompat="@drawable/ic_mic_off_solid_18"
|
||||
app:tint="@color/core_white"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:srcCompat="@drawable/ic_mic_off_solid_18"
|
||||
app:tint="@color/core_white" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/call_participant_info_overlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
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"
|
||||
tools:visibility="visible">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/call_participant_info_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:drawableTint="@color/core_white"
|
||||
tools:srcCompat="@drawable/ic_block_tinted_24" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/call_participant_info_message"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:lines="3"
|
||||
android:textColor="@color/core_white"
|
||||
tools:text="J. Jonah Jameson is blocked." />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/call_participant_info_more_info"
|
||||
style="@style/Signal.Widget.Button.Small.Primary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/CallParticipantView__more_info" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</org.thoughtcrime.securesms.components.webrtc.CallParticipantView>
|
||||
|
|
|
@ -1436,6 +1436,14 @@
|
|||
<item quantity="other">In this call · %1$d people</item>
|
||||
</plurals>
|
||||
|
||||
<!-- CallParticipantView -->
|
||||
<string name="CallParticipantView__s_is_blocked">%1$s is blocked</string>
|
||||
<string name="CallParticipantView__more_info">More Info</string>
|
||||
<string name="CallParticipantView__you_wont_receive_their_audio_or_video">You won\'t receive their audio or video and they won\'t receive yours.</string>
|
||||
<string name="CallParticipantView__cant_receive_audio_video_from_s">Can\'t receive audio & video from %1$s</string>
|
||||
<string name="CallParticipantView__cant_receive_audio_and_video_from_s">Can\'t receive audio and video from %1$s</string>
|
||||
<string name="CallParticipantView__this_may_be_Because_they_have_not_verified_your_safety_number_change">This may be because they have not verified your safety number change, there\'s a problem with their device, or they have blocked you.</string>
|
||||
|
||||
<!-- RegistrationActivity -->
|
||||
<string name="RegistrationActivity_select_your_country">Select your country</string>
|
||||
<string name="RegistrationActivity_you_must_specify_your_country_code">You must specify your
|
||||
|
|
|
@ -266,7 +266,7 @@
|
|||
<item name="android:collapseIcon" tools:ignore="NewApi">@drawable/ic_arrow_left_conversation_24</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.LightTheme.WebRTCCall">
|
||||
<style name="TextSecure.DarkTheme.WebRTCCall">
|
||||
<item name="android:statusBarColor" tools:ignore="NewApi">@color/core_ultramarine</item>
|
||||
<item name="android:windowActionBar">false</item>
|
||||
<item name="android:windowTranslucentStatus">true</item>
|
||||
|
|
Loading…
Add table
Reference in a new issue