Closed Bug 806385 Opened 10 years ago Closed 3 years ago

Automated helper app (intent) selection for every URL

Categories

(Firefox for Android Graveyard :: General, enhancement)

x86
Linux
enhancement
Not set
normal

Tracking

(Not tracked)

RESOLVED INCOMPLETE

People

(Reporter: contact, Unassigned)

References

Details

Attachments

(1 file, 4 obsolete files)

User Agent: Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/17.0 Firefox/17.0
Build ID: 20121023124120

Steps to reproduce:

In bug 653833, functionnality was added to have helper apps open on long press (with android intents). UI should be more discoverable, i.e, it should be automatic to always ask for helper apps the first time.
The original doorhanger-based UI was removed partly because of bugs like 769247.  I think those bugs are solvable, and the important thing here is to figure out the right UX so that it's obvious but not too obtrusive when you don't want it.
Depends on: 653833
Severity: normal → enhancement
Status: UNCONFIRMED → NEW
Ever confirmed: true
Depends on: 734877
If you make utilizing intents automatic, you can rely on Android's ability to permanently save an intent choice. This way the user is fully aware of it and has more control over it, unlike the current system where it's buried and only usable from links which they know should be used by said intent.
Agreed.  If I launch a Wikipedia page from the Android search bar then it launches the local Wikipedia app.  The same happens when I do so from Chrome for Android.

Firefox should replicate this - if I visit a site that has a local application registered for it, then that application should run.  If I didn't want it to do so, then I wouldn't have set my phone up that way.
Anyone working on this? It's very annoying to have Firefox behave different from other browsers and not respect Android's intent system. I know some prefer what Firefox does right now, but you really shouldn't be inconsistent with the target platform unless there's a very good reason.

I would suggest honouring the intents by default, and having a setting to disable that mechanism for users that really don't want things leaving the browser.
And to make matter worse, the helper-apps add on is not compatible with the last firefox releases.

https://addons.mozilla.org/fr/mobile/addon/helper-apps/

According to me, this is a major annoyance as it breaks a platform feature.
(In reply to Carl from comment #5)
> And to make matter worse, the helper-apps add on is not compatible with the
> last firefox releases.
> 
> https://addons.mozilla.org/fr/mobile/addon/helper-apps/
> 
> According to me, this is a major annoyance as it breaks a platform feature.

Bug 899376 added a button in the urlbar that basically replicates the functionality of helper-apps. Its on beta now.
In reply to Wesley.

I know about it, but that "feature" is awkward. 
99.9% of the time I want to open the url with the android app, not with firefox.
At worse, this is a convoluted workaround.
Is there a way to automatically open those links ?

You see, intents are an Android feature. 
Users do understand them. 
They do expect them.
(And by users, I mean everyday users, not geek self professed power users).
That feature grants a relative openness of the Android apps ecoysystem and is a strong differentiator from other fruit inspired OSes.
But Firefox currently adds a step to that very useful feature with a tiny not easily discoverable button. 
Breaking the flow. Breaking the feature.

Let's not kid ourselves, in very few cases Firefox (or any browser) can handle a content better than a native app (that is, most of time, implemented by the content creator).

Take your pick: Play store links, image, mp3. 
And video files.
I don't want Firefox to download video files (mp4 and others), I want them to be sent to my video player of choice (Mx video) that *does* supports streaming wonderfully.
And offers hardware playback. 

I hope this issue is not the result of some political/ideological decision.
Hoping to "promote" the web by making interaction with native apps more complicated. 
Because it is detrimental to the users.
And detrimental to the Android platform.

And while I don't appreciate Chrome very much, I don't support applications that are fighting the platform they are running on.

I am very hopeful that this issue will be resolve at user's best interests.
But if the tiny button is the official solution, please tell me now.
Because, as painful as it may be, it will be time for me to move away from Firefox.
I don't think there ever has been an "official solution". Just lots of ideas/feedback loops. Personally, I feel like if Fennec can handle an url, it should. If it can't, it should send it to the system. But this bug isn't on any tracking radar that I know of, so its unlikely to be fixed for you anytime soon (and tbh, is more likely to be WONTFX).

I wrote a quick addon for you that will try to load every url in an app if it can (only tested on Nightly builds):
https://addons.mozilla.org/en-US/firefox/addon/i-love-apps/
https://github.com/wesj/iloveapps/

Hope this provides some options. I don't have a strong need for this addon, so if someone else wants to take it and maintain it, feel free to. Until that happens, feel free to send me bugs.
It's good that you are passionate about the project that you are involved with. But I have to agree with Carl. Keeping a consistent user experience on the platform you're on should be the default. Keeping everything in Firefox/Fennec for those that so desire is certainly all right, but I don't think it is a suitable default on Android.

I'd like to try out your addon but unfortunately it refuses to install on my device (Firefox 25.0.1).
(In reply to Pierre Ossman from comment #9)
> I'd like to try out your addon but unfortunately it refuses to install on my
> device (Firefox 25.0.1).

Should be fixed now. Thanks for testing :)
It's a bit more nuanced than some are suggesting. I don't believe Firefox will ever throw up popups for native apps on all page navigation. That's far too obtrusive. The Android stock browser does/did that, even for plain old HTML pages! No thanks.

At the same time, we understand that some type of hand-off to native apps would be convenient. We're looking into ways we can balance both.

As for the assertions that Chrome always does the hand-off, I just entered twitter.com and facebook.com into Chrome and was never asked to jump out to the native app. I assume there is some nuance there too.
(In reply to Wesley Johnston (:wesj) from comment #10)
> (In reply to Pierre Ossman from comment #9)
> > I'd like to try out your addon but unfortunately it refuses to install on my
> > device (Firefox 25.0.1).
> 
> Should be fixed now. Thanks for testing :)

Thanks, it installed just fine now. :)

It doesn't behave properly though. Android's dialog for multiple handlers is bypassed somehow and it goes straight for one of the possible apps.

(it also continues working after both disable and uninstall until you restart firefox, but that might be expected)
(In reply to Wesley Johnston (:wesj) from comment #10)

Thanks for your work and dedication, Wesley.
(In reply to Mark Finkle (:mfinkle) from comment #11)

Hello Mark,

> It's a bit more nuanced than some are suggesting. I don't believe Firefox
> will ever throw up popups for native apps on all page navigation. That's far
> too obtrusive. 

I'm pretty sure you are kidding right.
Because, if I understand you correctly, you are comparing the Android intent feature to obtrusive popups that need to be blocked.
Or as you said in a previous comment "designed around".

It goes without saying that your claim that intents are "obtrusive" is at best dubious: the intent system is a platform feature that is loved and envied.
And it has memory. 
So the user can choose to set the app association once and for all.
(Note: this association is reset when one of the intent app is updated. 
So the user has the choice to re evaluate their preference when apps get better) 

Let me say this: what is getting in the way here is not the Android intent resolver.
But Firefox' current implementation.
It breaks the intent system.
It breaks my flow.
It makes browsing the web a less fun experience.
 
> The Android stock browser does/did that, even for plain old
> HTML pages! No thanks.

I don't see the point here. 
Firefox is not handling Android intents properly because of some alleged bug of the stock browser.
Do I understand you correctly?

By the way, do you have a bug report about that issue in the stock browser?
Because I have been using Android well before it was pretty (before ICS) and even before it was usable (before Cupcake) and I fail to remember such issue.

> 
> As for the assertions that Chrome always does the hand-off, I just entered
> twitter.com and facebook.com into Chrome and was never asked to jump out to
> the native app. I assume there is some nuance there too.

So, again, you are telling us that it is OK to break the intent system because of something Chrome does or does not.
I fail to see the logic in that.

I'll play along here for the sake of the argument.
So, when the user explicitly launches Chrome and explicitly types in facebook.com, the url opens in Chrome.
I don't see the issue here.
If the user chooses to open a browser and type in a url, it makes sense that the url is taken care by the browser.
Especially a landing page url (like twitter.com or facebook.com) as opposed to a content/deep linking  url (like https://mobile.twitter.com/paulg/status/397537535452131329?screen_name=paulg)

Your call to nuance tastes more like an attempt to bury the issue and stifle the discussion around it.
And even I'm sure it wasn't your goal, that's pretty much what it did.

There must be a better way to address this issue.

When the user browses the web on Android, he expects a top notch integration with the platform.
Firefox does not currently provide that.
And while I commend Wesley to address this issue in an addon, this must be addressed by the firefox app.
And the sooner, the better.

Here are links that do not open the intent resolver.
[1] https://play.google.com/store/apps/details?id=com.wallpaperbackgrounds.pattern
[2] http://www.youtube.com/watch?v=mFcizXfbcB4
[3] https://plus.google.com/110711646111288800228/posts/6yBRhQoSmCZ
[4] any link to mp4 video. Prompting the complete download of the file instead of starting the streaming
(In reply to Wesley Johnston (:wesj) from comment #10)
> (In reply to Pierre Ossman from comment #9)
> > I'd like to try out your addon but unfortunately it refuses to install on my
> > device (Firefox 25.0.1).
> 
> Should be fixed now. Thanks for testing :)

It doesn,t work for fx 26. Any idea how to fix it ?
At the moment, "importance: enhancement".
And the iloveapps extension doesn't work with the current Firefox version.
Duplicate of this bug: 1360907
Five years and there is still no solution for this issue... The only thing that has changed is the addons that added this functionality are no longer updated/maintained.
With the upcoming changes to firefox addons potentially making an updated version no lomger possible, could we please have this basic functionality that every other mobile browser has standard?
Something as simple as making the extensions like "I love apps" compatible with the latest version of Firefox or adding a small config option would be a huge fix for this issue
This bug has been around for a long time so I think the current situation has changed quite a bit - I currently see a Droid icon on pages that can be opened natively so I think all it takes now is a setting to make opening in a app the default. Seems relatively simple to implement? The current approach doesn't really help at all since loading the page twice, once in browser and once in app eliminates potential performance gains of a native app.

Currently Firefox seems to be significantly faster than Chrome on Android and I imagine many users like me have switched recently - I'm even recommending it to friends if they feel slowness in browsing. But if the usability doesn't keep up then once Chrome catches back up in speed we'll switch back. 

Good time to knock out some of these UX bugs.
I have a PoC implementation that currently just opens _every_ link inside a app if possible, so this would need some more work if we want to make it possible that if the url was openend via the address bar then it just stays in browser (that means mimicking the default chrome behavior).

I agree that this is an important UX bug, which should be taken care of. I need to find my way around mercurial and bugzilla before I can submit a patch, since this is my first contributions and I'm not familiar with the way that this community submits patches, etc.
Comment on attachment 8945223 [details] [diff] [review]
Open URLs in the corresponding native app on loading

Review of attachment 8945223 [details] [diff] [review]:
-----------------------------------------------------------------

Hello, thanks for looking at this.

Some random initial thoughts:

> so this would need some more work if we want to make it
> possible that if the url was openend via the address bar then it just stays
> in browser (that means mimicking the default chrome behavior).

Yes, that is a good idea, although I'd also add a settings option to turn this off completely (personally e.g. I don't want to be kicked out to the Youtube app each time I'm opening a video in the browser).

::: mobile/android/chrome/content/browser.js
@@ +6291,5 @@
> +            if (result.button != 0) {
> +              return;
> +            }
> +            apps[result.icongrid0].launch(this._pageActionUri);
> +            BrowserApp.selectedBrowser.goBack();

This design (letting the page load and then going back) seems a bit suboptimal - it uses data unnecessarily and depending on the page, navigating away and then going back can lose some state - think of one of those pages with infinite scrolling for example.

Somebody more familiar with this could probably give some more helpful tips here, but I think that a better way to abort the load might be like so [1] - hopefully that'll just work.

Additionally, I think that you need to decide whether you're going to abort the load or not earlier on, possibly here if we're not loading the sameDocument [2], although this might need some further thinking.
E.g. onHistoryNewEntry for adding the request to the tab's session history has already been called by the time onLocationChange is called, so you might want to run this check even earlier from somewhere else altogether.

onStateChange directly above could be a possible candidate, or it might also be possible to do e.g. something along the lines of the code that is responsible for deciding whether the request should be loaded internally or passed of to our Helper App/Download system, which would run slightly earlier than onLocationChange as well. Unfortunately I've got really no idea where that code lives and how easily extensible it would be.

As far as distinguishing between user input and clicking on links goes, I think that unfortunately you might be running into the same issue as bug 1278581, i.e. we might not have a good way of determining this at the moment.

[1] https://dxr.mozilla.org/mozilla-central/rev/e22e2c9eb81686e958a9448ea3d1e8cd766743e2/mobile/android/chrome/content/browser.js#4487-4489
[2] https://dxr.mozilla.org/mozilla-central/rev/e22e2c9eb81686e958a9448ea3d1e8cd766743e2/mobile/android/chrome/content/browser.js#4503
(In reply to Jan Henning [:JanH] from comment #28)


> This design (letting the page load and then going back) seems a bit
> suboptimal - it uses data unnecessarily and depending on the page,
> navigating away and then going back can lose some state - think of one of
> those pages with infinite scrolling for example.
> 
> Additionally, I think that you need to decide whether you're going to abort
> the load or not earlier on, possibly here if we're not loading the
> sameDocument [2], although this might need some further thinking.
> E.g. onHistoryNewEntry for adding the request to the tab's session history
> has already been called by the time onLocationChange is called, so you might
> want to run this check even earlier from somewhere else altogether.

The reason I used the goBack() function were the history entrys, because otherwise opening the browser again, would lead to a blank page or worst case would end in a loop in which the browser would always open up the native app again after starting. 

> onStateChange directly above could be a possible candidate, or it might also
> be possible to do e.g. something along the lines of the code that is
> responsible for deciding whether the request should be loaded internally or
> passed of to our Helper App/Download system, which would run slightly
> earlier than onLocationChange as well. Unfortunately I've got really no idea
> where that code lives and how easily extensible it would be.

I tried to use onStateChange but there is a problem with it, it fires when the loading starts and when it stops, but not on Redirects, so when its first fired we don't know the real URI and can't open an app and when its last fired the history is already added and we only could go back, which would lead to bad UX. So maybe someone else knows where this code would be more approriate. 
 
> As far as distinguishing between user input and clicking on links goes, I
> think that unfortunately you might be running into the same issue as bug
> 1278581, i.e. we might not have a good way of determining this at the moment.

That actually seems related as here, there's also the need to distinguish between userInput and clicked.
The problem are redirects I think, since we'd need to kick of the Request/Load Flow but only until we know the final URL and then stop before writing that into the history. If anybody here knows, where I could find that exact moment that'd be perfect.
Also if someone with more knowledge wants to help me, I'd appreaciate that.
(In reply to taaem from comment #29)
> The reason I used the goBack() function were the history entrys, because
> otherwise opening the browser again, would lead to a blank page or worst
> case would end in a loop in which the browser would always open up the
> native app again after starting.

Yes, given that onHistoryNewEntry has already been called, it does make sense that onLocationChange is already too late to cancel the load without anybody noticing. I've also realised that just as you state, onStateChange is on the other hand a little too early with regard to redirects.

I think you'd need to poke somewhere around the URILoader to find the right place for intercepting things, but yes, best try asking around. If you can't find anybody in #mobile, you can also try #developers, since the generic problem of intercepting a load and distinguishing whether it was triggered via the URL bar or not isn't specific to Firefox on Android anyway.
Boris, are you still the right person to ask about this?

To summarise, what we'd want to do in Fennec is to intercept each page load as early as possible (i.e. before we start navigating away from the old page, create a new history entry, etc.), but after any redirects have already been resolved. Then, if a local app is available to handle that URI and some other criteria are met [1], the load should be aborted and handed off to the OS to launch the appropriate app - otherwise everything continues normally.
From looking around a bit, I'm guessing that this needs to happen somewhere within the Uriloader, but I'm not really sure where and how exactly.


[1] I.e.
1.) the feature being generally enabled in the first place and
2.) the URL not having been loaded through the URL bar, similar to bug 1278581 - although depending on where we could intercept things maybe this time we might be able to make use of the LOAD_LINK flag?
Flags: needinfo?(bzbarsky)
"start navigating away" happens before redirects (beforeunload firing, etc).  But you can catch a load at the point where we'd hand off to a helper app or something.

uriloader would be an ok place to hook into this stuff.  nsDocumentOpenInfo::DispatchContent is the method that tries to figure out how to handle the data.  You'd want to take your escape hatch before we TryContentListener(m_contentListener, aChannel) if you want to intercept URLs that we would normally just render (like http://).

Finding whether the load came from the URL bar.. that part is harder.  I'm not sure we really track that right now, in a sane way.  You could check for a non-system triggering principal on the loadinfo, though, for loads triggered from the web....

Does that help?
Flags: needinfo?(bzbarsky)
I researched a bit more and maybe it would be practical to set forceExternalHandling [1] to true, so the ExternalApps Service gets the URL.
For this there has to be a check if the specific URL has a corresponding app. I don't think you can get that from plain C++ so I suppose there is the need for some jni checking in a #ifdef Android.
Furthermore nsIExternalAppsService and nsExternalAppsService need to be aware of that if a URL matches the jni check metioned earlier then it should pass it of to java and let Java open the corresponding app. The best way in my opinion would be to add a function to nsExternalAppsService that is checkURLForNativeApp(), that calls some Java, that checks the URL for corresponding apps via the Android APIs for that and then returns a boolean true if there is an app, false if not.
Than the DoContent function that is already there needs to check again if there is an native App and if so just pass of to Java and let the app handle that URL, otherwise continue as normal.

That's just my quick draw of how this could potentially work, but i fear this is over my knowledge. Because I'm totally unfamiliar with the Gecko source and I'm no virtuos in C++. So if somebody wants to jump in or guide me through that would be really appreaciated.
On Android if a link is clicked check for installed apps, that may
register handlers for URLs. If an app is found, the Android native
App chooser is shown, and the user can decide what to do.
Attachment #8945223 - Attachment is obsolete: true
Here is a new patch that works like the original intention was. If a user clicks on a link, there is a check for native apps and if one is shown the request stops. This is all without adding or removing items from the history.
Attachment #8947583 - Attachment is obsolete: true
On Android if a link is clicked check for installed apps, that may
register handlers for URLs. If an app is found, the Android native
App chooser is shown, and the user can decide what to do.
Attachment #8947593 - Flags: review?(bzbarsky)
Attachment #8947593 - Flags: review?(snorp)
Years ago, I remember we made the conscious decision to not do this. I think we need a product decision on whether or not we want it now.
Flags: needinfo?(bbermes)
Flags: needinfo?(abovens)
Comment on attachment 8947593 [details] [diff] [review]
Automated helper app (intent) selection for every URL

Review of attachment 8947593 [details] [diff] [review]:
-----------------------------------------------------------------

::: mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
@@ +277,5 @@
>                          TextUtils.isEmpty(action) ? Intent.ACTION_VIEW : action, "");
> +
> +                String[] handlers = IntentHelper.getHandlersForIntent(intent);
> +
> +                // Filter out Browser so, we know if a native app is installed for a  URL

You're filtering them out here to decide whether to launch a native app or not, but the activity chooser then still includes all those browsers, which doesn't seem quite right, so it might still be better to user our own activity chooser prompt here.

Plus you're probably duplicating some of the code in HelperApps.jsm, which might in the end be unavoidable, but at a first glance doesn't seem ideal.

::: uriloader/base/nsURILoader.cpp
@@ +409,4 @@
>    if (NS_SUCCEEDED(rv) && disposition == nsIChannel::DISPOSITION_ATTACHMENT) {
>      forceExternalHandling = true;
>    }
> +  #if defined(ANDROID)

Can you please also put this behind a pref?
1. In case of unexpected issues we'll want a way to turn this back off in a hurry
2. This new behaviour might not be to everybody's taste (I can't even start playing an MP3 file without being kicked out into a helper app). For our settings UI look here:
https://dxr.mozilla.org/mozilla-central/source/mobile/android/app/src/main/res/xml

If you need any further help in that regard, I can try digging out some patch that includes adding a new preference here, but basically android:key needs to match the name of the corresponding Gecko preference from about:config.

@@ +431,5 @@
> +
> +      // Found a native app start showing the Android Chooser and abort the request
> +      if (nativeApp == true) {
> +        info->LaunchWithURI(uri, nullptr);
> +        return NS_OK;

Boris will be able to confirm this, but I think you should return NS_BINDING_ABORTED here to actually cancel the request.
(In reply to Jan Henning [:JanH] from comment #39)

> ::: mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
> @@ +277,5 @@
> >                          TextUtils.isEmpty(action) ? Intent.ACTION_VIEW : action, "");
> > +
> > +                String[] handlers = IntentHelper.getHandlersForIntent(intent);
> > +
> > +                // Filter out Browser so, we know if a native app is installed for a  URL
> 
> You're filtering them out here to decide whether to launch a native app or
> not, but the activity chooser then still includes all those browsers, which
> doesn't seem quite right, so it might still be better to user our own
> activity chooser prompt here.

That filtering out is only there to check if there are actually native Apps installed, because for every URL all browser also show up. I checked with the Chrome behavior and there it also shows all browsers.

> Plus you're probably duplicating some of the code in HelperApps.jsm, which
> might in the end be unavoidable, but at a first glance doesn't seem ideal.

I know but I didn't find a way around that.

> ::: uriloader/base/nsURILoader.cpp
> @@ +409,4 @@
> >    if (NS_SUCCEEDED(rv) && disposition == nsIChannel::DISPOSITION_ATTACHMENT) {
> >      forceExternalHandling = true;
> >    }
> > +  #if defined(ANDROID)
> 
> Can you please also put this behind a pref?
> 1. In case of unexpected issues we'll want a way to turn this back off in a
> hurry
> 2. This new behaviour might not be to everybody's taste (I can't even start
> playing an MP3 file without being kicked out into a helper app). For our
> settings UI look here:
> https://dxr.mozilla.org/mozilla-central/source/mobile/android/app/src/main/
> res/xml

This is also the default behavior of Chrome, so it is not surprising for the end user to get a pop up on a mp3.
As for the setting maybe that also clears out James concerns about UX. I think it is a better UX like this. If the user wants he can just choose Firefox for eg. mp3 and then Firefox will never ask him again.

Thanks for the feedback!
(In reply to taaem from comment #40)
> I think it is a better UX like this.
I disagree, but I accept that it's also a matter of individual opinion.

> If the user wants he can just choose
> Firefox for eg. mp3 and then Firefox will never ask him again.
This doesn't work properly yet with your current patch. Even if I set my test build as the default app after clicking on an MP3 link, in practice the load doesn't proceed normally and still takes a detour through launching an "external" app via an intent.

In addition, launching apps for pages the we could have rendered ourselves is a new feature, so fine, but we already used to show our Helper App activity chooser for files that we *couldn't* handle ourselves. This patch somewhat interferes with that, because the option to download that file in Firefox is now missing and besides our download handling isn't really compatible with using the OS's activity chooser dialogue.

So *if* we'd actually want to do something like this, I think this needs some more thoughts how everything in that area should interact with each other and how this needs to be implemented...
(In reply to Jan Henning [:JanH] from comment #41)
> > If the user wants he can just choose
> > Firefox for eg. mp3 and then Firefox will never ask him again.
> This doesn't work properly yet with your current patch. Even if I set my
> test build as the default app after clicking on an MP3 link, in practice the
> load doesn't proceed normally and still takes a detour through launching an
> "external" app via an intent.

Yes that is right, since we get back from the OS if one of the application is set as the system default, we than could skip all the External Apps thing, if it is matching Firefox. That is totally possible and probably also wanted, since that would be a much faster and cleaner way. I wanted to do this already, but I didn't find a good way to detemine if an App is actually us, we get back a List of Strings (Name, Activity, Intent) but since there are many different Firefox we can't hardcode that check. Maybe there is a way to find out what the current app name/activity is and match via that at runtime? 

> In addition, launching apps for pages the we could have rendered ourselves
> is a new feature, so fine, but we already used to show our Helper App
> activity chooser for files that we *couldn't* handle ourselves. This patch
> somewhat interferes with that, because the option to download that file in
> Firefox is now missing and besides our download handling isn't really
> compatible with using the OS's activity chooser dialogue.

For downloading there should be no issue only a difference UI wise. I just downloaded a mp3 just fine with the Firefox intern Activity Chooser.

> So *if* we'd actually want to do something like this, I think this needs
> some more thoughts how everything in that area should interact with each
> other and how this needs to be implemented...

I absolutly agree with you, that there is some more stuff still involved, especially UX wise.
(In reply to taaem from comment #42)
> For downloading there should be no issue only a difference UI wise. I just
> downloaded a mp3 just fine with the Firefox intern Activity Chooser.

I didn't mean MP3 files here, as those aren't automatically downloaded anyway. Once you actually manage to open one internally instead of being handed off to the activity chooser, using the context menu to trigger the download of course just works fine.

What I meant is, try something that Firefox cannot handle internally, like a ZIP file, a PDF document, or anything else like that. Instead of our download menu that clearly includes a "Download" item in addition to any other apps that might handle that file, I get the system activity chooser that only includes a generic "Firefox" item. Pressing that then opens a new tab (which previously didn't happen) and then finally triggers our own activity chooser, which allows me to download the file after all.
On Android if a link is clicked check for installed apps, that may
register handlers for URLs. If an app is found, the Android native
App chooser is shown, and the user can decide what to do.
Attachment #8947593 - Attachment is obsolete: true
Attachment #8947593 - Flags: review?(snorp)
Attachment #8947593 - Flags: review?(bzbarsky)
Attachment #8947677 - Flags: review?(snorp)
Attachment #8947677 - Flags: review?(bzbarsky)
Comment on attachment 8947677 [details] [diff] [review]
Automated helper app (intent) selection for every URL;  bz

Review of attachment 8947677 [details] [diff] [review]:
-----------------------------------------------------------------

::: uriloader/base/nsURILoader.cpp
@@ +425,5 @@
> +      nsCOMPtr<nsIURI> uri;
> +      aChannel->GetURI(getter_AddRefs(uri));
> +      nsCOMPtr<nsIHandlerInfo> info;
> +
> +      urlHandlerService->GetURLHandlerInfoFromOS(uri, &nativeApp, getter_AddRefs(info));

You're ignoring the MIME type here, even though that's an integral part of Android's intent filter system.
(In reply to taaem from comment #40)
> If the user wants he can just choose
> Firefox for eg. mp3 and then Firefox will never ask him again.

No, because clicking on a link (that Firefox could actually handle internally) and then choosing to always use Firefox apparently doesn't work without also setting Firefox as your default browser at the same time.

So this won't work properly if you've already got a different default browser [1] - unless you do some special shenanigans, recent-ish Android versions (going back to M or perhaps even L) will only include your default browser among the list of suitable apps, so when the activity chooser appears, your current non-default browser won't even be offered, or else if you don't want to set a default browser [2].

Those might not be the most common use cases, but it's still something that's worse now if you can't turn this off.

[1] E.g. in some circles it's apparently quite popular to use Firefox Focus as a default browser and only explicitly switch to Firefox.
[2] Because for example you have multiple browsers installed for testing/development and want to be able to choose among them on demand (and installing and uninstalling browsers resets your default browser each time anyway).
Comment on attachment 8947677 [details] [diff] [review]
Automated helper app (intent) selection for every URL;  bz

The commit message should probably be more specific about this being for Android.

I didn't look at the .java bits.

>+  #if defined(ANDROID)

Please outdent this all the way; same for the #endif.

>+    if (forceExternalHandling == false && loadType == LOAD_LINK) {

This should be happening before you start wasting cycles on do_GetInterface and do_GetService.  So:

  if (!forceExternalHandling) {
    // Get docshell, if docshell get loadtype, check loadtype, only
    // _then_ do other things.
  }

>+      urlHandlerService->GetURLHandlerInfoFromOS(uri, &nativeApp, getter_AddRefs(info));

Does the MIME type really not matter?  What are the desired semantics here?  Those should be in the commit message...

>+      if (nativeApp == true) {

"if (nativeApp)".

That said, is GetURLHandlerInfoFromOS guaranteed to never return error?  Per its contract it's not, and then you're examining random memory in nativeApp...

>+        return NS_OK;

This is not aborting the request.  It's letting the request keep going and just ignoring all the notifications it sends.  The comments say you want to abort... So you should probably return NS_BINDING_ABORTED or so.
Attachment #8947677 - Flags: review?(bzbarsky) → review-
On Android Apps can register for URLs being associated with their apps.
The OS keeps a list of URL -> App and any app can ask, which app is
listening for an URL [1]. The MIME-Type is not relevant for this, since
this is only intended for linking into Apps.

We only want to do this, when the user clicks on a link, because we assume
that there are reasons why a user would explictly navigate to a site of
which the user also has a native app. If the user has clicked on a link,
we ask the system, if there are apps for this URL and filter out regular
http:// handlers, like browsers, etc. and after we found out that an app
has a native app, we hand of to the OS to show a chooser, where the user
can choose in which app the user would like to open the URL.

If the user decides to rather want the old behavior, there is a new setting
in the settings view, which disables all changes this patch makes and
everything returns to the way it was before.

[1] https://developer.android.com/training/app-links/deep-linking.html
Attachment #8947677 - Attachment is obsolete: true
Attachment #8947677 - Flags: review?(snorp)
Attachment #8948061 - Flags: review?(snorp)
Attachment #8948061 - Flags: review?(bzbarsky)
This is a huge change to how Firefox for Android behaves. Product manager/UX should sign off on changing the behavior from preferring opening http(s) links with Firefox to handing off http(s) links that are associated with an installed app to that app. It may significantly decrease usage of Firefox for Android.
Comment on attachment 8948061 [details] [diff] [review]
Android: Open Urls in native Apps if possible;  bz

I'd really like us to be clear on the behavior we want before we start changing code.
Attachment #8948061 - Flags: review?(bzbarsky)
> It may significantly decrease usage of Firefox for Android.

Or tt may significantly increase usage of Firefox for Android.
Kevin, Boris were you able to find a PM to comment on this? FWIW with a setting that is defaulted off, there would be no immediate impact on usage and could start we A/B tests. There was good progress on getting things done, but it looks like the discussion has been pushed away, as it has many times in the past, which is a shame.
Comment on attachment 8948061 [details] [diff] [review]
Android: Open Urls in native Apps if possible;  bz

Review of attachment 8948061 [details] [diff] [review]:
-----------------------------------------------------------------

I'm going to just clear this review request because I don't think we can take this patch right now. There are no full-time Fennec engineers or UI/UX folks to support it or make a decision on whether the feature should be included.

Tim, we'll try to get back to this at some point, but unfortunately it's just a very bad time to try to make these kinds of changes in Firefox.
Attachment #8948061 - Flags: review?(snorp)
As James mentions the timing is not good. In the future it may be possible to look at this patch. It did seem that reversing the default behavior was preferred. Firefox would continue to load URLs that are associated with apps by default and there would be a pref in the settings that enables the behavior that is requested in this bug. 

* Need clarity on when this behavior is selected
** How does this behave with private browsing?
** When the user types in/paste/paste and go a url that has an associated app?
** When the user taps a link?
** When the user selects a history or bookmark item?
** When Firefox gets an intent from another app?
* Abuse of users by directing them to shady apps on Google Play, visiting a play.google.com url would instantly open the Play Store
* What are the boundaries? If an app registers formats that Firefox can handle such as media do we pass that off? ex. mp3, png, mp4
* The interaction with the existing helper app selection system for downloading content that we wouldn't have been able to handle ourselves anyway
+1 for the functionality @taaem has outlined. On android it makes sense for native apps to load by default. If you have a native app for google maps, youtube, play store it almost never makes sense to open those links in the browser.

I am having to stick with chrome because of this for now.
> we'll try to get back to this at some point, but unfortunately it's just a very bad time to try to make these kinds of changes in Firefox.

I agree. I'm happy to reconsider this feature in the future, but at this point (when we're reworking our mobile product), it's not a good time to include this patch in the current Fennec product.
Flags: needinfo?(abovens)
Maybe not a good time to patch the builds straight away. But as this is 5+ years old issue at this point. It should be a priority for whoever makes such product decisions at Mozilla to come up with a reasoning for why this should be changed or not. 

As it stands the browser is 'surprising' the users(including me) by behaving in this way.
(In reply to Andreas Bovens [:abovens] from comment #59)
> > we'll try to get back to this at some point, but unfortunately it's just a very bad time to try to make these kinds of changes in Firefox.
> 
> I agree. I'm happy to reconsider this feature in the future, but at this
> point (when we're reworking our mobile product), it's not a good time to
> include this patch in the current Fennec product.

A rework sounds like an ideal time to incorporate this so that it's there from the beginning and you can plan for it in development, instead of coding it similar to the way it was before and perhaps making it difficult (again) to patch later.
Duplicate of this bug: 1458311
Duplicate of this bug: 1463620
(In reply to ashnichdavis from comment #61)
> A rework sounds like an ideal time to incorporate this so that it's there
> from the beginning and you can plan for it in development, instead of coding
> it similar to the way it was before and perhaps making it difficult (again)
> to patch later.

This still needs support from the Gecko platform as well, though, no matter whether Firefox for Android gets rewritten or not.


(In reply to Jan Henning [:JanH] from comment #55)
> * The interaction with the existing helper app selection system for
> downloading content that we wouldn't have been able to handle ourselves
> anyway

Which is especially import for the handling of downloads that can be downloaded only once. I.e. either we do helper app selection just based on what can be gleaned from the URL [1], or else if we do connect to the server to learn the MIME type the server is claiming for that URL [2], things need to work like they do with today's helper app selection system - Firefox must maintain the connection until the user (or some automated logic) has decided whether to continue within Firefox or not.

I.e. we cannot hand the URL to the default Android intent handling system and abort the connection like in the patch above and then, if the user chooses Firefox, attempt to download that file again, because by that time the link would be no longer valid.

[1] Which would be a step backward compared to today, since having the content type available is beneficial for retrieving the right set of apps that could handle that URL and guessing it from the URL will usually be more imprecise than taking the server's response into account.
[2] In which case handing off the download to some other app obviously won't work, but at least we shouldn't break downloading within Firefox as well.
> [1] Which would be a step backward compared to today, since having the content type available is beneficial for retrieving the right set of apps that could handle that URL and guessing it from the URL will usually be more imprecise than taking the server's response into account.

Are you sure content type is used today to get the right set of apps?

I'm currently struggling with how Firefox for Android handles downloaded files. As far as I can see on stable my custom Content-Type is completely ignored and after downloading the file I can see only generic list of apps. Opening the same file in file explorer brings only relevant, intent-filtered apps.

For the record, built-in browser (Chrome) ignores `android:mimeType` filter when looking for apps, just uses host, scheme and path filters but checks them even for redirects.
Opening downloads after they've been downloaded is a different kettle of fish (admittedly maybe not from a user perspective, but implementation-wise it is - if you want you can open a separate bug for that), but I'm fairly certain the MIME type is used for retrieving the selection of alternative apps that you can use for downloading the file in the first place.
> Opening downloads after they've been downloaded is a different kettle of fish 

I agree with that.

> I'm fairly certain the MIME type is used for retrieving the selection of alternative apps that you can use for downloading the file in the first place.

That's not my experience. I tried using https based intents to handle links from an app. Then MIME types after files were downloaded, no luck (the app is https://www.openkeychain.org for managing OpenPGP keys).

I've also built a sample app for testing that and found out that Firefox will launch third party app *only* when it's using scheme that Firefox doesn't support. No amount of trickery would convince Firefox to handle non-standard files from http(s) schemes.

From my perspective the original issue is the most important (handling URLs by registered apps), handling downloads correctly is next (but still annoying).
For downloading files (i.e. http/https links, but with a content type that Firefox cannot render natively, i.e. not text/html and such-like) it should be: https://dxr.mozilla.org/mozilla-central/rev/b75acf9652937ce79a9bf02de843c100db0e5ec7/mobile/android/components/HelperAppDialog.js#155
Jan, you are right, I tried a different combination of conditions in the intent-filter and Firefox for Android showed app chooser dialog correctly.

I am terribly sorry for the confusion, apparently I didn't try hard enough to get this working.

For the record the supported intent-filter that will trigger app dialog in Firefox for Android:

  <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:host="*" android:scheme="https" android:mimeType="application/vnd.sample" />
  </intent-filter>
> From my perspective the original issue is the most important (handling URLs by registered apps), handling downloads correctly is next (but still annoying).

More details and parity with other browsers on "HTTPs App login" can be found here: https://bugzilla.mozilla.org/show_bug.cgi?id=1463620
Duplicate of this bug: 1488189
Duplicate of this bug: 1499950
Duplicate of this bug: 1512495
Duplicate of this bug: 1516800

I just wanted to comment that I am switching from Firefox for Android to Chrome
for Android. I prefer to use "NewPipe" for watching YouTube. With Chrome for
Android I can set default and from then on YouTube pages will open with NewPipe
with a single tap.

With Firefox for Android, I would need to long press followed by "open with an
app". Alternatively I can single tap, let the page load in Firefox, then click
Android icon, then let page load in app. Neither of these are really acceptable
given that:

  1. Chrome can give expected result with single tap, for several years now
  2. This issue was reported 7 years ago with no movement

I will still use Firefox desktop, but I wanted it to be known that youve lost
a mobile user.

I am switching from Firefox to Chrome because this is still not fixed and it makes browsing apps that opens webpages extremely annoying. I don't want to open two web browsers and load the page twice just to be able to use my preferred browser.

Flags: needinfo?(bbermes)

Vesta, this might be something to consider for Fenix.

Flags: needinfo?(vzare)

Likely fixed by bug 1529258.

(In reply to Andreas Bovens [:abovens] from comment #77)

Vesta, this might be something to consider for Fenix.

As long as it'd be configurable...

(In reply to Kevin Brosnan [:kbrosnan] from comment #78)

Likely fixed by bug 1529258.

I don't see how. That bug was only about properly filtering out apps that register themselves for all URLs with regards to our manual app selection (via the URL bar button).

(In reply to Jan Henning [:JanH] from comment #79)

(In reply to Andreas Bovens [:abovens] from comment #77)

Vesta, this might be something to consider for Fenix.

As long as it'd be configurable...

If done using native Android functionality, it would automatically be configurable because Android itself would ask a user to set their preferred default between Firefox and the external apps. And then remember it, so they won't be asked again. It also has the advantage of not being an all or nothing option, as the user could still choose to open some websites on Firefox but others on external apps.

Thanks Andreas, will look into it!

Flags: needinfo?(vzare)

Any updates? I switched from Firefox to Edge on Android because of this but would really like to switch back (primarily since I use it on DT). Will this be included in Fenix, if not on Firefox on Android?

Flags: needinfo?(vzare)

I tried Firefox preview and even the button on address bar is not present. Moved back to regular Firefox on Android and this button breaks way too many things. This means back to Chrome, which I'm really not a fan. It's unrelated but frustrating that I also tried using Firefox on my Mac and hit a similar wall with bug 1404042. Cannot consider firefox because of those big issues in both of my main platforms.

Firefox for Android work is largely done, major features such as this one will not be added to it. It is shipping the Firefox ESR 68 code. Firefox Preview (Fenix) is the successor to Firefox for Android.

Status: NEW → RESOLVED
Closed: 3 years ago
Flags: needinfo?(vzare)
Resolution: --- → INCOMPLETE
Restrict Comments: true
Product: Firefox for Android → Firefox for Android Graveyard
You need to log in before you can comment on or make changes to this bug.