From 2154f962f5612a5d7e55a3af2248193d3d145a61 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Wed, 22 May 2024 08:42:10 -0500 Subject: [PATCH] Custom tabs, thanks qy! --- build.gradle | 1 + .../com/cheogram/android/BrowserHelper.java | 88 +++++++++++++++++++ .../conversations/ui/text/FixedURLSpan.java | 16 +++- 3 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 src/cheogram/java/com/cheogram/android/BrowserHelper.java diff --git a/build.gradle b/build.gradle index fa09d66de75f33c9191fd99e3c9ff55f8458c3b5..885b5057838c7602fc4bd170c5ca867cda5c208a 100644 --- a/build.gradle +++ b/build.gradle @@ -107,6 +107,7 @@ dependencies { implementation 'io.github.nishkarsh:android-permissions:2.1.6' implementation 'androidx.recyclerview:recyclerview:1.1.0' implementation 'androidx.documentfile:documentfile:1.0.1' + implementation 'androidx.browser:browser:1.8.0' implementation 'com.github.martin-stone:hsv-alpha-color-picker-android:3.1.0' implementation 'com.github.ipld:java-cid:v1.3.1' //implementation 'com.splitwise:tokenautocomplete:3.0.2' diff --git a/src/cheogram/java/com/cheogram/android/BrowserHelper.java b/src/cheogram/java/com/cheogram/android/BrowserHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..bbcfc4cb2dfc200563b11a9c63d3b48fca7382f3 --- /dev/null +++ b/src/cheogram/java/com/cheogram/android/BrowserHelper.java @@ -0,0 +1,88 @@ +package com.cheogram.android; + +import android.content.Intent; +import android.Manifest; +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.content.ActivityNotFoundException; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import androidx.browser.customtabs.CustomTabsIntent; + +import eu.siacs.conversations.ui.XmppActivity; + +public class BrowserHelper { + static boolean launchNativeApi30(Context context, Uri uri) { + Intent nativeAppIntent = new Intent(Intent.ACTION_VIEW, uri) + .addCategory(Intent.CATEGORY_BROWSABLE) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | + Intent.FLAG_ACTIVITY_REQUIRE_NON_BROWSER); + try { + context.startActivity(nativeAppIntent); + return true; + } catch (ActivityNotFoundException ex) { + return false; + } + } + + private static Set extractPackageNames(List infos) { + Set names = new HashSet<>(); + for (ResolveInfo resolveInfo : infos) { + String packageName = resolveInfo.activityInfo.packageName; + names.add(packageName); + } + return names; + } + + private static boolean launchNativeBeforeApi30(Context context, Uri uri) { + PackageManager pm = context.getPackageManager(); + + // Get all Apps that resolve a generic url + Intent browserActivityIntent = new Intent() + .setAction(Intent.ACTION_VIEW) + .addCategory(Intent.CATEGORY_BROWSABLE) + .setData(Uri.fromParts("http", "", null)); + Set genericResolvedList = extractPackageNames( + pm.queryIntentActivities(browserActivityIntent, 0)); + + // Get all apps that resolve the specific Url + Intent specializedActivityIntent = new Intent(Intent.ACTION_VIEW, uri) + .addCategory(Intent.CATEGORY_BROWSABLE); + Set resolvedSpecializedList = extractPackageNames( + pm.queryIntentActivities(specializedActivityIntent, 0)); + + // Keep only the Urls that resolve the specific, but not the generic + // urls. + resolvedSpecializedList.removeAll(genericResolvedList); + + // If the list is empty, no native app handlers were found. + if (resolvedSpecializedList.isEmpty()) { + return false; + } + + // We found native handlers. Launch the Intent. + specializedActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(specializedActivityIntent); + return true; + } + + public static void launchUri(Context context, Uri uri) { + boolean launched = Build.VERSION.SDK_INT >= 30 ? + launchNativeApi30(context, uri) : + launchNativeBeforeApi30(context, uri); + + if (!launched) { + var builder = new CustomTabsIntent.Builder().setShowTitle(true); + if (context instanceof XmppActivity) { + builder = builder.setColorScheme(((XmppActivity) context).isDark() ? CustomTabsIntent.COLOR_SCHEME_DARK : CustomTabsIntent.COLOR_SCHEME_LIGHT); + } + builder.build().launchUrl(context, uri); + } + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/text/FixedURLSpan.java b/src/main/java/eu/siacs/conversations/ui/text/FixedURLSpan.java index 6a9f69a3e5a638e7177e91ce1911a26af45e0fe5..fab4ad92ac2f9bd8bb9ab6434b267d259cdf227f 100644 --- a/src/main/java/eu/siacs/conversations/ui/text/FixedURLSpan.java +++ b/src/main/java/eu/siacs/conversations/ui/text/FixedURLSpan.java @@ -42,6 +42,8 @@ import android.view.SoundEffectConstants; import android.view.View; import android.widget.Toast; +import com.cheogram.android.BrowserHelper; + import java.util.Arrays; import eu.siacs.conversations.R; @@ -95,11 +97,17 @@ public class FixedURLSpan extends URLSpan { } } + if (uri.getScheme().equals("http") || uri.getScheme().equals("https")) { + widget.playSoundEffect(SoundEffectConstants.CLICK); + BrowserHelper.launchUri(context, uri); + return; + } + final Intent intent = new Intent(Intent.ACTION_VIEW, uri); - if ("geo".equalsIgnoreCase(uri.getScheme())) { - intent.setClass(context, ShowLocationActivity.class); - } else { - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); + if ("geo".equalsIgnoreCase(uri.getScheme())) { + intent.setClass(context, ShowLocationActivity.class); + } else { + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); } try { context.startActivity(intent);