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 ;
1011import android .content .pm .PackageManager ;
2324
2425import org .schabi .newpipe .BuildConfig ;
2526import org .schabi .newpipe .R ;
27+ import org .schabi .newpipe .RouterActivity ;
2628import org .schabi .newpipe .extractor .Image ;
2729import org .schabi .newpipe .util .image .ImageStrategy ;
2830import org .schabi .newpipe .util .image .PicassoHelper ;
@@ -62,8 +64,9 @@ public static void installApp(@NonNull final Context context, final String packa
6264 }
6365
6466 /**
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)}.
67+ * Open the url with the system default browser. If no browser is installed, falls back to
68+ * {@link #openAppChooser(Context, Intent, boolean)} (for displaying that no apps are available
69+ * to handle the action, or possible OEM-related edge cases).
6770 * <p>
6871 * This function selects the package to open based on which apps respond to the {@code http://}
6972 * schema alone, which should exclude special non-browser apps that are can handle the url (e.g.
@@ -77,44 +80,25 @@ public static void installApp(@NonNull final Context context, final String packa
7780 * @param url the url to browse
7881 **/
7982 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.
83+ // Target a generic http://, so we are sure to get a browser and not e.g. the yt app.
8184 // Note that this requires the `http` schema to be added to `<queries>` in the manifest.
82- final ResolveInfo defaultBrowserInfo ;
8385 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- }
9186
9287 final Intent intent = new Intent (Intent .ACTION_VIEW , Uri .parse (url ))
9388 .setFlags (Intent .FLAG_ACTIVITY_NEW_TASK );
9489
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)
90+ intent .setSelector (browserIntent );
91+ try {
92+ context .startActivity (intent );
93+ } catch (final ActivityNotFoundException e ) {
94+ // No browser is available. This should, in the end, yield a nice AOSP error message
95+ // indicating that no app is available to handle this action.
96+ //
97+ // Note: there are some situations where modified OEM ROMs have apps that appear
98+ // to be browsers but are actually app choosers. If starting the Activity fails
99+ // related to this, opening the system app chooser is still the correct behavior.
100+ intent .setSelector (null );
108101 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- }
118102 }
119103 }
120104
@@ -190,6 +174,18 @@ private static void openAppChooser(@NonNull final Context context,
190174 chooserIntent .putExtra (Intent .EXTRA_TITLE , context .getString (R .string .open_with ));
191175 }
192176
177+ // Avoid opening in NewPipe
178+ // (Implementation note: if the URL is one for which NewPipe itself
179+ // is set as handler on Android >= 12, we actually remove the only eligible app
180+ // for this link, and browsers will not be offered to the user. For that, use
181+ // `openUrlInBrowser`.)
182+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .N ) {
183+ chooserIntent .putExtra (
184+ Intent .EXTRA_EXCLUDE_COMPONENTS ,
185+ new ComponentName []{new ComponentName (context , RouterActivity .class )}
186+ );
187+ }
188+
193189 // Migrate any clip data and flags from the original intent.
194190 final int permFlags = intent .getFlags () & (Intent .FLAG_GRANT_READ_URI_PERMISSION
195191 | Intent .FLAG_GRANT_WRITE_URI_PERMISSION
0 commit comments