Add support for signal.me links.
This commit is contained in:
parent
138b7ea796
commit
3cc2cd0b17
5 changed files with 150 additions and 0 deletions
|
@ -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"
|
||||
|
|
|
@ -49,6 +49,7 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot
|
|||
|
||||
handleGroupLinkInIntent(getIntent());
|
||||
handleProxyInIntent(getIntent());
|
||||
handleSignalMeIntent(getIntent());
|
||||
|
||||
CachedInflater.from(this).clear();
|
||||
}
|
||||
|
@ -65,6 +66,7 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot
|
|||
super.onNewIntent(intent);
|
||||
handleGroupLinkInIntent(intent);
|
||||
handleProxyInIntent(intent);
|
||||
handleSignalMeIntent(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -115,6 +117,13 @@ public class MainActivity extends PassphraseRequiredActivity implements VoiceNot
|
|||
}
|
||||
}
|
||||
|
||||
private void handleSignalMeIntent(Intent intent) {
|
||||
Uri data = intent.getData();
|
||||
if (data != null) {
|
||||
CommunicationActions.handlePotentialSignalMeUrl(this, data.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull VoiceNoteMediaController getVoiceNoteMediaController() {
|
||||
return mediaController;
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.signal.core.util.concurrent.SignalExecutors;
|
|||
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;
|
||||
|
@ -37,6 +38,9 @@ import org.thoughtcrime.securesms.proxy.ProxyBottomSheetFragment;
|
|||
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 {
|
||||
|
||||
|
@ -225,6 +229,40 @@ public class CommunicationActions {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the url is a proxy link it will handle it.
|
||||
* 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()));
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue