Skip to content

Commit

Permalink
Add support for signal.me links.
Browse files Browse the repository at this point in the history
  • Loading branch information
greyson-signal committed Jul 28, 2021
1 parent 138b7ea commit 3cc2cd0
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 0 deletions.
10 changes: 10 additions & 0 deletions app/src/main/AndroidManifest.xml
Expand Up @@ -275,6 +275,16 @@
<data android:scheme="sgnl"
android:host="signal.tube" />
</intent-filter>

<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https"
android:host="signal.me" />
<data android:scheme="sgnl"
android:host="signal.me" />
</intent-filter>
</activity>

<activity android:name=".conversation.ConversationActivity"
Expand Down
Expand Up @@ -49,6 +49,7 @@ protected void onCreate(Bundle savedInstanceState, boolean ready) {

handleGroupLinkInIntent(getIntent());
handleProxyInIntent(getIntent());
handleSignalMeIntent(getIntent());

CachedInflater.from(this).clear();
}
Expand All @@ -65,6 +66,7 @@ protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
handleGroupLinkInIntent(intent);
handleProxyInIntent(intent);
handleSignalMeIntent(intent);
}

@Override
Expand Down Expand Up @@ -115,6 +117,13 @@ private void handleProxyInIntent(Intent intent) {
}
}

private void handleSignalMeIntent(Intent intent) {
Uri data = intent.getData();
if (data != null) {
CommunicationActions.handlePotentialSignalMeUrl(this, data.toString());
}
}

@Override
public @NonNull VoiceNoteMediaController getVoiceNoteMediaController() {
return mediaController;
Expand Down
Expand Up @@ -24,6 +24,7 @@
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.WebRtcCallActivity;
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
import org.thoughtcrime.securesms.conversation.ConversationIntents;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
Expand All @@ -37,6 +38,9 @@
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;

import java.io.IOException;

public class CommunicationActions {

Expand Down Expand Up @@ -225,6 +229,40 @@ public static boolean handlePotentialProxyLinkUrl(@NonNull FragmentActivity acti
}
}

/**
* If the url is a proxy link it will handle it.

This comment has been minimized.

Copy link
@AsamK

AsamK Jul 29, 2021

Contributor

@greyson-signal copy-pasted comment ;)

* Otherwise returns false, indicating was not a proxy link.
*/
public static boolean handlePotentialSignalMeUrl(@NonNull FragmentActivity activity, @NonNull String potentialUrl) {
String e164 = SignalMeUtil.parseE164FromLink(activity, potentialUrl);

if (e164 != null) {
SimpleProgressDialog.DismissibleDialog dialog = SimpleProgressDialog.showDelayed(activity, 500, 500);

SimpleTask.run(() -> {
Recipient recipient = Recipient.external(activity, e164);

if (!recipient.isRegistered() || !recipient.hasUuid()) {
try {
DirectoryHelper.refreshDirectoryFor(activity, recipient, false);
recipient = Recipient.resolved(recipient.getId());
} catch (IOException e) {
Log.w(TAG, "[handlePotentialMeUrl] Failed to refresh directory for new contact.");
}
}

return recipient;
}, recipient -> {
dialog.dismiss();
startConversation(activity, recipient, null);
});

return true;
} else {
return false;
}
}

private static void startInsecureCallInternal(@NonNull Activity activity, @NonNull Recipient recipient) {
try {
Intent dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + recipient.requireSmsAddress()));
Expand Down
@@ -0,0 +1,43 @@
package org.thoughtcrime.securesms.util;

import android.content.Context;
import android.telephony.PhoneNumberUtils;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.google.i18n.phonenumbers.PhoneNumberUtil;

import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter;

import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

class SignalMeUtil {
private static final String HOST = "signal.me";
private static final Pattern HOST_PATTERN = Pattern.compile("^(https|sgnl)://" + HOST + "/#p/(\\+[0-9]+)$");

/**
* If this is a valid signal.me link and has a valid e164, it will return the e164. Otherwise, it will return null.
*/
public static @Nullable String parseE164FromLink(@NonNull Context context, @Nullable String link) {
if (Util.isEmpty(link)) {
return null;
}

Matcher matcher = HOST_PATTERN.matcher(link);

if (matcher.matches()) {
String e164 = matcher.group(2);

if (PhoneNumberUtil.getInstance().isPossibleNumber(e164, Locale.getDefault().getCountry())) {
return PhoneNumberFormatter.get(context).format(e164);
} else {
return null;
}
} else {
return null;
}
}
}
@@ -0,0 +1,50 @@
package org.thoughtcrime.securesms.util;

import android.app.Application;

import androidx.test.core.app.ApplicationProvider;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.ParameterizedRobolectricTestRunner;
import org.robolectric.annotation.Config;

import java.util.Arrays;
import java.util.Collection;

import static junit.framework.TestCase.assertEquals;

@RunWith(ParameterizedRobolectricTestRunner.class)
@Config(manifest = Config.NONE, application = Application.class)
public class SignalMeUtilText_parseE164FromLink {

private final String input;
private final String output;

@ParameterizedRobolectricTestRunner.Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{
{ "https://signal.me/#p/+15555555555", "+15555555555" },
{ "https://signal.me/#p/5555555555", null },
{ "https://signal.me", null },
{ "https://signal.me/#p/", null },
{ "signal.me/#p/+15555555555", null },
{ "sgnl://signal.me/#p/+15555555555", "+15555555555" },
{ "sgnl://signal.me/#p/5555555555", null },
{ "sgnl://signal.me", null },
{ "sgnl://signal.me/#p/", null },
{ "", null },
{ null, null }
});
}

public SignalMeUtilText_parseE164FromLink(String input, String output) {
this.input = input;
this.output = output;
}

@Test
public void parse() {
assertEquals(output, SignalMeUtil.parseE164FromLink(ApplicationProvider.getApplicationContext(), input));
}
}

0 comments on commit 3cc2cd0

Please sign in to comment.