Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix opening downloads and streams on external players on Android 11+ and refactor external intents #9833

Closed
wants to merge 3 commits into from

Conversation

AudricV
Copy link
Member

@AudricV AudricV commented Feb 18, 2023

What is it?

  • Bugfix (user facing)

Description of the changes in your PR

This PR fixes opening streams on external players and downloads on Android 11 and higher and refactors how external intents are handled.

It does more precisely the following changes:

  • the check of the availability of a default package has been removed and replaced by try catch blocks. As a result, the HTTP default browser test for web links has been removed;
  • an app chooser on Android 10+ is always shown for chooser intents, even if there is only one action to handle the original intent, so the user can use actions in the chooser, such as copying a text to clipboard in the share sheet for ACTION_SEND intents;
  • the method to open an app chooser in ShareUtils, openAppChooser, has been made public and is now used when sharing a download in MissionAdapter, in order to avoid code duplication;
  • some other changes about the parameters of the methods of ShareUtils have been also made: see the commits messages and the code changes for more details;
  • as we only use now standard intents, we do not need to query packages anymore: see https://web.archive.org/web/20200817164113/https://developer.android.com/preview/privacy/package-visibility#use-cases-not-affected. That's the reason why the queries element in the Android manifest has been removed.
  • the toast_no_player string resource has been removed, as it was only used in MissionAdapter when trying to a play a download, and has been replaced by the generic one No app on your device can open this with the usage of the method openIntentInApp in ShareUtils instead of starting manually the intent.
  • opening links on the about and licenses pages, RSS feed in the account/channel page where applicable, the issues GitHub page and the privacy policy links in the error activity and web links in comments, descriptions, metadata and meta-info no longer always use an app chooser, this task is now handled by the Android system. Let me know if I should revert completely or partially these changes.

Fixes the following issue(s)

APK testing

The APK can be found by going to the "Checks" tab below the title. On the left pane, click on "CI", scroll down to "artifacts" and click "app" to download the zip file which contains the debug APK of this PR.

Please test that the changes work fine with this build, by using the following locations where external chooser and view intents are used:

  • stream dialog entry, channel/account, playlist, content details, in-app player: open in browser and share;
  • comment: open links;
  • content details: open description and metadata;
  • channel/account: open RSS feed, where applicable;
  • external player dialog: open a stream URL in an external app and open a content in browser;
  • play queue: share a stream;
  • license dialog: open license's website;
  • about page: open links;
  • download context menu: open and share files;
  • app install dialog: install VLC and Kodi;
  • error report actions: create an email to send an error report, open report on GitHub and privacy policy links and share error report;
  • editable or selectable texts: share selected text.

I personally tested the changes on an Android 14 Developer Preview 1 emulator and my Honor 9X device, running EMUI 10.0 with Android 10, and everything about external intents I have been able to test was working as excepted.

Due diligence

- Don't check the availability of a default package due to package visibility
  restrictions on Android 11+, use try-catches blocks instead. HTTP default
  browser test has been removed;
- Always show an app chooser on Android 10+ if there is only one action to
  handle the original intent, so the user can use actions in the chooser, such
  as copying a text to clipboard in a share sheet for ACTION_SEND intents;
- Remove openUrlInBrowser delegate method and use directly the remaining method
  in the previous usages of the delegate. This change clarifies whether a
  chooser will be shown for the ACTION_VIEW intent which will be created from
  the given URL;
- Make ShareUtils.openAppChooser public, so functions and methods which need to
  use a system chooser don't have to write a similar code. It also requires a
  new string argument, chooserTitle, which is the title which will be set to
  the chooser for all intents except the ACTION_SEND ones on Android 9+, as the
  system ignores it on these Android versions.
  This method is now used in MissionAdapter to share a downloaded file.
As we only use now standard intents, we do not need to query packages for http,
https and market schemes anymore, so we can remove the query declaration in
Android manifest: see
https://web.archive.org/web/20200817164113/https://developer.android.com/
preview/privacy/package-visibility#use-cases-not-affected for more details.
As ShareUtils.openIntentInApp is used directly with showNoAppToast set to true
in MissionAdapter.viewWithFileProvider, the string resource
"No app installed to play this file" (toast_no_player) is not used anymore and
has been replaced by a similar one already used for other intents,
"No app on your device can open this" (no_app_to_open_intent).

That's the reason why it is removed with this commit.
@AudricV AudricV added bug Issue is related to a bug device/software specific Issues that only happen on some devices or with some specific hardware/software labels Feb 18, 2023
@sonarqubecloud
Copy link

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 1 Code Smell

0.0% 0.0% Coverage
0.0% 0.0% Duplication

Copy link
Member

@Stypox Stypox left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks good to me, I just have some suggestions on how to improve the ShareUtils methods structure. Thanks!

The behavior requested in #9403 seems now to be NewPipe's behavior. So when opening in browser, the official youtube app would show up instead. Only if I disable the official app's "Open by default" system setting, then the browser shows up. And if I then set NewPipe to open supported links, opening in browser results in the NewPipe share dialog coming up, which is surely not wanted. Note that this happens both if I set useChooser to false and true, with the only difference that in the first case no chooser shows up. Is this the way Android is supposed to work?

Comment on lines +149 to +151
* app or browser (the default app associated with this link or the default
* browser if there is no default app will be only shown in the system
* chooser on Android 12 and higher)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* app or browser (the default app associated with this link or the default
* browser if there is no default app will be only shown in the system
* chooser on Android 12 and higher)
* app or browser (only the default app associated with this link, or the default
* browser if there is no default app, will be shown in the system
* chooser on Android 12 and higher)

* web URL with false for the boolean param.
* It uses {@link #openIntentInApp(Context, Intent, boolean)} to open the market scheme
* and {@link #openUrlInBrowser(Context, String, boolean)} to open Google Play Store's
* web URL with false for the boolean parameter.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* web URL with false for the boolean parameter.
* web URL without an app chooser.

return resolveInfo.activityInfo.packageName;
public static boolean openIntentInApp(@NonNull final Context context,
@NonNull final Intent intent,
final boolean showNoAppToOpenToast) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about creating two methods and removing this boolean parameter? I would call the two methods:

  • tryOpenIntentInApp which just does try{...}catch{return false}; return true
  • openIntentInApp which does if (!tryOpenIntentInApp()) showToast and has return type void

*/
public static boolean openUrlInBrowser(@NonNull final Context context,
final String url,
final boolean useChooser) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here. I think it would be better to create two different methods, so that it is clear what's happening just by reading the code (no need to look up parameter documentation).

  • openUrlInDefaultBrowser
  • openUrlInBrowserWithChooser

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a bad idea, but I would use openUrlInDefaultApp and openUrlWithAppChooser, as we do not look at a browser anymore.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right

@AudricV
Copy link
Member Author

AudricV commented Feb 21, 2023

And if I then set NewPipe to open supported links, opening in browser results in the NewPipe share dialog coming up, which is surely not wanted. Note that this happens both if I set useChooser to false and true, with the only difference that in the first case no chooser shows up. Is this the way Android is supposed to work?

Yes, it is, starting with Android 12.

Another solution would be to reintroduce query packages permission for http and https link, which are removed with this PR, query all packages without Android filtering for web links (excluding disabled apps) (like done here but without the MATCH_DISABLED_COMPONENTS flag instead of the MATCH_DISABLED_UNTIL_USED_COMPONENTS), and then show a dialog with all apps which can open this link and open the corresponding app with the intent when it's tapped.

@Stypox
Copy link
Member

Stypox commented Feb 22, 2023

Yes, it is, starting with Android 12.

Mmmh, then I guess this is the right thing to do, let's hope it does not create issues for users. I don't think we should implement non-standard things: users have the ability to copy the url e.g. from the share sheet (including older android versions if there is a "Copy to clipboard" app installed).

Then I think the "Open in browser" button should become "Open in..." with this icon (or similar)

@AudricV
Copy link
Member Author

AudricV commented Feb 24, 2023

Closing in favor of #9850, which aims to keep the current behavior as much as possible and embed the requested changes.

@AudricV AudricV closed this Feb 24, 2023
@AudricV AudricV deleted the external-intents-refactor branch February 24, 2023 21:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue is related to a bug device/software specific Issues that only happen on some devices or with some specific hardware/software
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Android 11+] Cannot open downloads from the app ("No app installed to play this file" toast)
2 participants