diff --git a/res/values/strings.xml b/res/values/strings.xml
index cf7c7cf0eb..849768a2b4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1155,6 +1155,9 @@
Disable Signal\'s built-in emoji support
Video calling beta
Support for next-generation video and voice calls when enabled by both parties. This feature is in beta.
+ Relay all calls through the Signal server to avoid revealing your IP address to your contact. Enabling will reduce call quality.
+ Always relay calls
+
diff --git a/res/xml/preferences_advanced.xml b/res/xml/preferences_advanced.xml
index 6bd81a1ca2..14ae8e11f9 100644
--- a/res/xml/preferences_advanced.xml
+++ b/res/xml/preferences_advanced.xml
@@ -25,6 +25,12 @@
android:title="@string/preferences_advanced__video_calling_beta"
android:summary="@string/preferences_advanced__enable_support_for_next_generation_video_and_voice_calls"/>
+
+
diff --git a/res/xml/preferences_app_protection.xml b/res/xml/preferences_app_protection.xml
index 91a3928471..1cde219123 100644
--- a/res/xml/preferences_app_protection.xml
+++ b/res/xml/preferences_app_protection.xml
@@ -33,7 +33,7 @@
android:key="pref_blocking_identity_changes"
android:title="@string/preferences_app_protection__safety_numbers_approval"
android:summary="@string/preferences_app_protecting__require_approval_of_new_safety_numbers_when_they_change"/>
-
+
diff --git a/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java b/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java
index 222b1e83b5..098b9bc68e 100644
--- a/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java
+++ b/src/org/thoughtcrime/securesms/contacts/ContactAccessor.java
@@ -61,6 +61,23 @@ public class ContactAccessor {
return instance;
}
+ public boolean isSystemContact(Context context, String number) {
+ Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
+ String[] projection = new String[]{PhoneLookup.DISPLAY_NAME, PhoneLookup.LOOKUP_KEY,
+ PhoneLookup._ID, PhoneLookup.NUMBER};
+ Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
+
+ try {
+ if (cursor != null && cursor.moveToFirst()) {
+ return true;
+ }
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+
+ return false;
+ }
+
public Collection getContactsWithPush(Context context) {
final ContentResolver resolver = context.getContentResolver();
final String[] inProjection = new String[]{PhoneLookup._ID, PhoneLookup.DISPLAY_NAME};
diff --git a/src/org/thoughtcrime/securesms/service/WebRtcCallService.java b/src/org/thoughtcrime/securesms/service/WebRtcCallService.java
index c204705e20..7afcd7f990 100644
--- a/src/org/thoughtcrime/securesms/service/WebRtcCallService.java
+++ b/src/org/thoughtcrime/securesms/service/WebRtcCallService.java
@@ -29,6 +29,7 @@ import org.thoughtcrime.redphone.util.AudioUtils;
import org.thoughtcrime.redphone.util.UncaughtExceptionHandlerManager;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.WebRtcCallActivity;
+import org.thoughtcrime.securesms.contacts.ContactAccessor;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.dependencies.SignalCommunicationModule.SignalMessageSenderFactory;
@@ -40,6 +41,7 @@ import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.FutureTaskListener;
import org.thoughtcrime.securesms.util.ListenableFutureTask;
import org.thoughtcrime.securesms.util.ServiceUtil;
+import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.webrtc.CallNotificationManager;
import org.thoughtcrime.securesms.webrtc.PeerConnectionFactoryOptions;
@@ -279,7 +281,10 @@ public class WebRtcCallService extends Service implements InjectableType, PeerCo
@Override
public void onSuccessContinue(List result) {
try {
- WebRtcCallService.this.peerConnection = new PeerConnectionWrapper(WebRtcCallService.this, peerConnectionFactory, WebRtcCallService.this, localRenderer, result);
+ boolean isSystemContact = ContactAccessor.getInstance().isSystemContact(WebRtcCallService.this, recipient.getNumber());
+ boolean isAlwaysTurn = TextSecurePreferences.isTurnOnly(WebRtcCallService.this);
+
+ WebRtcCallService.this.peerConnection = new PeerConnectionWrapper(WebRtcCallService.this, peerConnectionFactory, WebRtcCallService.this, localRenderer, result, !isSystemContact || isAlwaysTurn);
WebRtcCallService.this.peerConnection.setRemoteDescription(new SessionDescription(SessionDescription.Type.OFFER, offer));
WebRtcCallService.this.lockManager.updatePhoneState(LockManager.PhoneState.PROCESSING);
@@ -330,7 +335,9 @@ public class WebRtcCallService extends Service implements InjectableType, PeerCo
@Override
public void onSuccessContinue(List result) {
try {
- WebRtcCallService.this.peerConnection = new PeerConnectionWrapper(WebRtcCallService.this, peerConnectionFactory, WebRtcCallService.this, localRenderer, result);
+ boolean isAlwaysTurn = TextSecurePreferences.isTurnOnly(WebRtcCallService.this);
+
+ WebRtcCallService.this.peerConnection = new PeerConnectionWrapper(WebRtcCallService.this, peerConnectionFactory, WebRtcCallService.this, localRenderer, result, isAlwaysTurn);
WebRtcCallService.this.dataChannel = WebRtcCallService.this.peerConnection.createDataChannel(DATA_CHANNEL_NAME);
WebRtcCallService.this.dataChannel.registerObserver(WebRtcCallService.this);
diff --git a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
index 26c3092e8b..da99e21003 100644
--- a/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
+++ b/src/org/thoughtcrime/securesms/util/TextSecurePreferences.java
@@ -99,6 +99,11 @@ public class TextSecurePreferences {
public static final String SYSTEM_EMOJI_PREF = "pref_system_emoji";
private static final String MULTI_DEVICE_PROVISIONED_PREF = "pref_multi_device";
public static final String DIRECT_CAPTURE_CAMERA_ID = "pref_direct_capture_camera_id";
+ private static final String ALWAYS_RELAY_CALLS_PREF = "pref_turn_only";
+
+ public static boolean isTurnOnly(Context context) {
+ return getBooleanPreference(context, ALWAYS_RELAY_CALLS_PREF, false);
+ }
public static boolean isWebrtcCallingEnabled(Context context) {
return getBooleanPreference(context, WEBRTC_CALLING_PREF, false);
diff --git a/src/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.java b/src/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.java
index 5fc66e8f02..8bf5741c90 100644
--- a/src/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.java
+++ b/src/org/thoughtcrime/securesms/webrtc/PeerConnectionWrapper.java
@@ -47,7 +47,8 @@ public class PeerConnectionWrapper {
@NonNull PeerConnectionFactory factory,
@NonNull PeerConnection.Observer observer,
@NonNull VideoRenderer.Callbacks localRenderer,
- @NonNull List turnServers)
+ @NonNull List turnServers,
+ boolean hideIp)
{
List iceServers = new LinkedList<>();
iceServers.add(STUN_SERVER);
@@ -60,6 +61,10 @@ public class PeerConnectionWrapper {
configuration.bundlePolicy = PeerConnection.BundlePolicy.MAXBUNDLE;
configuration.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.REQUIRE;
+ if (hideIp) {
+ configuration.iceTransportsType = PeerConnection.IceTransportsType.RELAY;
+ }
+
constraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
audioConstraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));