BrowserHelper.java

 1package com.cheogram.android;
 2
 3import android.content.Intent;
 4import android.Manifest;
 5import android.annotation.SuppressLint;
 6import android.content.Context;
 7import android.content.pm.PackageManager;
 8import android.content.pm.ResolveInfo;
 9import android.database.Cursor;
10import android.net.Uri;
11import android.os.Build;
12import android.content.ActivityNotFoundException;
13import java.util.HashSet;
14import java.util.List;
15import java.util.Set;
16import androidx.browser.customtabs.CustomTabsIntent;
17
18import eu.siacs.conversations.ui.XmppActivity;
19
20public class BrowserHelper {
21	static boolean launchNativeApi30(Context context, Uri uri) {
22		Intent nativeAppIntent = new Intent(Intent.ACTION_VIEW, uri)
23				.addCategory(Intent.CATEGORY_BROWSABLE)
24				.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
25						Intent.FLAG_ACTIVITY_REQUIRE_NON_BROWSER);
26		try {
27			context.startActivity(nativeAppIntent);
28			return true;
29		} catch (ActivityNotFoundException ex) {
30			return false;
31		}
32	}
33
34	private static Set<String> extractPackageNames(List<ResolveInfo> infos) {
35		Set<String> names = new HashSet<>();
36		for (ResolveInfo resolveInfo : infos) {
37			String packageName = resolveInfo.activityInfo.packageName;
38			names.add(packageName);
39		}
40		return names;
41	}
42
43	private static boolean launchNativeBeforeApi30(Context context, Uri uri) {
44		PackageManager pm = context.getPackageManager();
45
46		// Get all Apps that resolve a generic url
47		Intent browserActivityIntent = new Intent()
48				.setAction(Intent.ACTION_VIEW)
49				.addCategory(Intent.CATEGORY_BROWSABLE)
50				.setData(Uri.fromParts("http", "", null));
51		Set<String> genericResolvedList = extractPackageNames(
52				pm.queryIntentActivities(browserActivityIntent, 0));
53
54		// Get all apps that resolve the specific Url
55		Intent specializedActivityIntent = new Intent(Intent.ACTION_VIEW, uri)
56				.addCategory(Intent.CATEGORY_BROWSABLE);
57		Set<String> resolvedSpecializedList = extractPackageNames(
58				pm.queryIntentActivities(specializedActivityIntent, 0));
59
60		// Keep only the Urls that resolve the specific, but not the generic
61		// urls.
62		resolvedSpecializedList.removeAll(genericResolvedList);
63
64		// If the list is empty, no native app handlers were found.
65		if (resolvedSpecializedList.isEmpty()) {
66			return false;
67		}
68
69		// We found native handlers. Launch the Intent.
70		specializedActivityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
71		context.startActivity(specializedActivityIntent);
72		return true;
73	}
74
75	public static void launchUri(Context context, Uri uri) {
76		boolean launched = Build.VERSION.SDK_INT >= 30 ?
77				launchNativeApi30(context, uri) :
78				launchNativeBeforeApi30(context, uri);
79
80		if (!launched) {
81			var builder = new CustomTabsIntent.Builder().setShowTitle(true);
82			if (context instanceof XmppActivity) {
83				builder = builder.setColorScheme(((XmppActivity) context).isDark() ? CustomTabsIntent.COLOR_SCHEME_DARK : CustomTabsIntent.COLOR_SCHEME_LIGHT);
84			}
85			builder.build().launchUrl(context, uri);
86		}
87	}
88}