rewrite fedilinks to https when no app handles web+ap

Daniel Gultsch created

Change summary

src/main/java/de/gultsch/common/MiniUri.java                   | 13 +
src/main/java/eu/siacs/conversations/ui/text/FixedURLSpan.java | 37 +++
2 files changed, 44 insertions(+), 6 deletions(-)

Detailed changes

src/main/java/de/gultsch/common/MiniUri.java 🔗

@@ -1,5 +1,6 @@
 package de.gultsch.common;
 
+import android.net.Uri;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Splitter;
 import com.google.common.base.Strings;
@@ -7,6 +8,7 @@ import com.google.common.collect.ImmutableMap;
 import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
 import java.util.Collections;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import org.checkerframework.checker.nullness.qual.NonNull;
@@ -33,6 +35,7 @@ public class MiniUri {
         }
         this.scheme = schemeAndRest.get(0);
         final var rest = schemeAndRest.get(1);
+        // TODO add fragment parser
         final var authorityPathAndQuery = Splitter.on('?').limit(2).splitToList(rest);
         final var authorityPath = authorityPathAndQuery.get(0);
         System.out.println("authorityPath " + authorityPath);
@@ -106,10 +109,20 @@ public class MiniUri {
                 : '/' + this.path;
     }
 
+    public List<String> getPathSegments() {
+        return Strings.isNullOrEmpty(this.path)
+                ? Collections.emptyList()
+                : Splitter.on('/').splitToList(this.path);
+    }
+
     public String getRaw() {
         return this.raw;
     }
 
+    public Uri asUri() {
+        return Uri.parse(this.raw);
+    }
+
     public Map<String, String> getParameter() {
         return this.parameter;
     }

src/main/java/eu/siacs/conversations/ui/text/FixedURLSpan.java 🔗

@@ -37,9 +37,13 @@ import android.net.Uri;
 import android.text.Editable;
 import android.text.Spanned;
 import android.text.style.URLSpan;
+import android.util.Log;
 import android.view.SoundEffectConstants;
 import android.view.View;
 import android.widget.Toast;
+import com.google.common.base.Joiner;
+import de.gultsch.common.MiniUri;
+import eu.siacs.conversations.Config;
 import eu.siacs.conversations.R;
 import eu.siacs.conversations.ui.ConversationsActivity;
 import eu.siacs.conversations.ui.ShowLocationActivity;
@@ -67,26 +71,47 @@ public class FixedURLSpan extends URLSpan {
 
     @Override
     public void onClick(final View widget) {
-        final Uri uri = Uri.parse(getURL());
+        final var uri = new MiniUri(getURL());
         final Context context = widget.getContext();
         final boolean candidateToProcessDirectly =
                 "xmpp".equals(uri.getScheme())
                         || ("https".equals(uri.getScheme())
-                                && "conversations.im".equals(uri.getHost())
+                                && "conversations.im".equals(uri.getAuthority())
                                 && uri.getPathSegments().size() > 1
                                 && Arrays.asList("j", "i").contains(uri.getPathSegments().get(0)));
-        if (candidateToProcessDirectly && context instanceof ConversationsActivity) {
-            if (((ConversationsActivity) context).onXmppUriClicked(uri)) {
+        if (candidateToProcessDirectly
+                && context instanceof ConversationsActivity conversationsActivity) {
+            if (conversationsActivity.onXmppUriClicked(uri.asUri())) {
+                Log.d(Config.LOGTAG, "handled xmpp uri internally");
                 widget.playSoundEffect(SoundEffectConstants.CLICK);
                 return;
             }
         }
-        final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
-        if ("geo".equalsIgnoreCase(uri.getScheme())) {
+        final Intent intent = new Intent(Intent.ACTION_VIEW, uri.asUri());
+        if ("web+ap".equals(uri.getScheme())) {
+            if (intent.resolveActivity(context.getPackageManager()) == null) {
+                Log.d(Config.LOGTAG, "no app found to handle web+ap");
+                final var webApAsHttps =
+                        Uri.parse(
+                                String.format(
+                                        "https://%s/%s",
+                                        uri.getAuthority(),
+                                        Joiner.on('/').join(uri.getPathSegments())));
+                final var viewHttpsIntent = new Intent(Intent.ACTION_VIEW, webApAsHttps);
+                startActivity(widget, viewHttpsIntent);
+                return;
+            }
+        }
+        if ("geo".equals(uri.getScheme())) {
             intent.setClass(context, ShowLocationActivity.class);
         } else {
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
         }
+        startActivity(widget, intent);
+    }
+
+    private void startActivity(final View widget, final Intent intent) {
+        final var context = widget.getContext();
         try {
             context.startActivity(intent);
             widget.playSoundEffect(SoundEffectConstants.CLICK);