55import android .content .ActivityNotFoundException ;
66import android .content .ClipData ;
77import android .content .ClipboardManager ;
8+ import android .content .ComponentName ;
89import android .content .Context ;
910import android .content .Intent ;
10- import android .content .pm .PackageManager ;
11- import android .content .pm .ResolveInfo ;
1211import android .graphics .Bitmap ;
1312import android .net .Uri ;
1413import android .os .Build ;
2322
2423import org .schabi .newpipe .BuildConfig ;
2524import org .schabi .newpipe .R ;
25+ import org .schabi .newpipe .RouterActivity ;
2626import org .schabi .newpipe .extractor .Image ;
2727import org .schabi .newpipe .util .image .ImageStrategy ;
2828import org .schabi .newpipe .util .image .PicassoHelper ;
@@ -62,8 +62,9 @@ public static void installApp(@NonNull final Context context, final String packa
6262 }
6363
6464 /**
65- * Open the url with the system default browser. If no browser is set as default, falls back to
66- * {@link #openAppChooser(Context, Intent, boolean)}.
65+ * Open the url with the system default browser. If no browser is installed, falls back to
66+ * {@link #openAppChooser(Context, Intent, boolean)} (for displaying that no apps are available
67+ * to handle the action, or possible OEM-related edge cases).
6768 * <p>
6869 * This function selects the package to open based on which apps respond to the {@code http://}
6970 * schema alone, which should exclude special non-browser apps that are can handle the url (e.g.
@@ -77,44 +78,26 @@ public static void installApp(@NonNull final Context context, final String packa
7778 * @param url the url to browse
7879 **/
7980 public static void openUrlInBrowser (@ NonNull final Context context , final String url ) {
80- // Resolve using a generic http://, so we are sure to get a browser and not e.g. the yt app.
81+ // Target a generic http://, so we are sure to get a browser and not e.g. the yt app.
8182 // Note that this requires the `http` schema to be added to `<queries>` in the manifest.
82- final ResolveInfo defaultBrowserInfo ;
8383 final Intent browserIntent = new Intent (Intent .ACTION_VIEW , Uri .parse ("http://" ));
84- if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .TIRAMISU ) {
85- defaultBrowserInfo = context .getPackageManager ().resolveActivity (browserIntent ,
86- PackageManager .ResolveInfoFlags .of (PackageManager .MATCH_DEFAULT_ONLY ));
87- } else {
88- defaultBrowserInfo = context .getPackageManager ().resolveActivity (browserIntent ,
89- PackageManager .MATCH_DEFAULT_ONLY );
90- }
9184
9285 final Intent intent = new Intent (Intent .ACTION_VIEW , Uri .parse (url ))
9386 .setFlags (Intent .FLAG_ACTIVITY_NEW_TASK );
9487
95- if (defaultBrowserInfo == null ) {
96- // No app installed to open a web URL, but it may be handled by other apps so try
97- // opening a system chooser for the link in this case (it could be bypassed by the
98- // system if there is only one app which can open the link or a default app associated
99- // with the link domain on Android 12 and higher)
100- openAppChooser (context , intent , true );
101- return ;
102- }
103-
104- final String defaultBrowserPackage = defaultBrowserInfo .activityInfo .packageName ;
105-
106- if (defaultBrowserPackage .equals ("android" )) {
107- // No browser set as default (doesn't work on some devices)
88+ // See https://stackoverflow.com/a/58801285 and `setSelector` documentation
89+ intent .setSelector (browserIntent );
90+ try {
91+ context .startActivity (intent );
92+ } catch (final ActivityNotFoundException e ) {
93+ // No browser is available. This should, in the end, yield a nice AOSP error message
94+ // indicating that no app is available to handle this action.
95+ //
96+ // Note: there are some situations where modified OEM ROMs have apps that appear
97+ // to be browsers but are actually app choosers. If starting the Activity fails
98+ // related to this, opening the system app chooser is still the correct behavior.
99+ intent .setSelector (null );
108100 openAppChooser (context , intent , true );
109- } else {
110- try {
111- intent .setPackage (defaultBrowserPackage );
112- context .startActivity (intent );
113- } catch (final ActivityNotFoundException e ) {
114- // Not a browser but an app chooser because of OEMs changes
115- intent .setPackage (null );
116- openAppChooser (context , intent , true );
117- }
118101 }
119102 }
120103
@@ -190,6 +173,18 @@ private static void openAppChooser(@NonNull final Context context,
190173 chooserIntent .putExtra (Intent .EXTRA_TITLE , context .getString (R .string .open_with ));
191174 }
192175
176+ // Avoid opening in NewPipe
177+ // (Implementation note: if the URL is one for which NewPipe itself
178+ // is set as handler on Android >= 12, we actually remove the only eligible app
179+ // for this link, and browsers will not be offered to the user. For that, use
180+ // `openUrlInBrowser`.)
181+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .N ) {
182+ chooserIntent .putExtra (
183+ Intent .EXTRA_EXCLUDE_COMPONENTS ,
184+ new ComponentName []{new ComponentName (context , RouterActivity .class )}
185+ );
186+ }
187+
193188 // Migrate any clip data and flags from the original intent.
194189 final int permFlags = intent .getFlags () & (Intent .FLAG_GRANT_READ_URI_PERMISSION
195190 | Intent .FLAG_GRANT_WRITE_URI_PERMISSION
0 commit comments