Getting a list of apps that support a particular file type

Inman

Well-Known Member
Licensed User
Longtime User
In the past I have used PackageManager to get a list of all installed apps on a device. Now there are certain apps that are designed to handle certain file types (or MIME types) by default. Like for example, if you touch an MP3 file in a file explorer app (like Astro or EStrong), you get a list of music players that are installed, from which you can select an app to open that MP3 file.

You can use Intents to display a similar Chooser popup for a particular data type, but that only displays it. I was wondering if it is possible to programatically get a list of apps that are capable of handling, say MP3 files.

There is some java code mentioned in the following link

How to get a list of installed android applications and pick one to run - Stack Overflow

It looks like adding some sort of an intent filter to PackageManager so that it returns only a certain type of apps. I was wondering if we can do something like this on B4A.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
It is possible with the help of the Reflection library:
B4X:
Sub Activity_Create(FirstTime As Boolean)
   Dim intent1 As Intent
   intent1.Initialize(intent1.ACTION_SEND, "")
   intent1.SetType("text/plain")
   Dim list1 As List
   list1 = QueryIntent(intent1)
   Log(list1)
End Sub

Sub QueryIntent(Intent1 As Intent) As List
   Dim r As Reflector
   r.Target = r.GetContext
   r.Target = r.RunMethod("getPackageManager")
   Dim list1 As List
   list1 = r.RunMethod4("queryIntentActivities", Array As Object(intent1, 0), Array As String("android.content.Intent", "java.lang.int"))
   Dim listRes As List
   listRes.Initialize
   For i = 0 To list1.Size - 1
      r.Target = list1.Get(i)
      r.Target = r.GetField("activityInfo")
      'listRes.Add(r.GetField("name")) 'return the activity full name
      listRes.Add(r.GetField("packageName"))
   Next
   Return listRes
End Sub
 
Upvote 0

Inman

Well-Known Member
Licensed User
Longtime User
Thank you, Erel. I am almost there. Just one more issue.

There are cases when the intent-filter of an activity, defined in the manifest, doesn't have a MIMEType. For example if you check the Manifest of a web browser, you see something like

B4X:
<activity.....">
          <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:scheme="http" />
            <data android:scheme="https" />

            </intent-filter>
      </activity>

So, based on your code, I made some changes which I hoped would make it suitable to work with the above:

B4X:
Sub Activity_Create(FirstTime As Boolean)
   Dim intent1 As Intent
   
   intent1.Initialize(intent1.ACTION_VIEW, "")
   'intent1.SetType("text/plain")
   intent1.AddCategory("android.intent.category.BROWSABLE")
   intent1.PutExtra("SCHEME","http")
   
   Dim list1 As List
   list1 = QueryIntent(intent1)
   Log(list1)
End Sub

The above code returns a blank list. Since there is no mimetype for the above activity, I am not sure what I should set SetType to. And I am also not sure how I can pass this data called "Scheme".
 
Upvote 0

Inman

Well-Known Member
Licensed User
Longtime User
What do you want to find? All applications that can handle a url?

Yes. By learning that I am hoping I can adapt the idea to find more kinds of apps, like the ones that handle music, movies, doc etc...But for the time being I am trying to find the ones which handle http and https links.
 
Upvote 0

Inman

Well-Known Member
Licensed User
Longtime User
Indeed. That was so simple. Thank you very much.

Erel, I must say this. For the amount of money we pay, the kind of customer support you provide is simply amazing.
 
Upvote 0

Inman

Well-Known Member
Licensed User
Longtime User
I have an issue related to this thread I created. Using the function you provided, I was able to get the list of activities that can handle a url. Then using the following function, I was able to open specific browsers with the link I wanted:

B4X:
    Dim puturl As Intent
   puturl.Initialize(puturl.ACTION_VIEW,link)
   puturl.SetComponent(cname)
   StartActivity(puturl)

Now link is the link I want to open and cname is the component of the browser app I want. For example for Miren Browser, cname=cn.miren.browser/.ui.MiRenBrowserActivity

This component name can be constructed using package name and activity name. It normally follows a specific pattern. In Miren Browser's case

packagename=cn.miren.browser
activityname=cn.miren.browser.ui.MiRenBrowserActivity

From this we can construct cname as cn.miren.browser/.ui.MiRenBrowserActivity
And this is true for most cases

But today I was testing with Opera Mobile and was surprised to see that packagename=com.opera.browser and activityname=com.opera.Opera. Now I am not sure how to construct the component name from this. Any idea how to do this?

Or is it possible to find the component name of the intent as well, in the code you posted above? I tried r.GetField("ComponentName") but it looks like ActivityInfo doesn't have a ComponentName.
 
Last edited:
Upvote 0

Inman

Well-Known Member
Licensed User
Longtime User
I am not sure but I think the problem is with the way B4A handles intent.setcomponent. In B4A, the setcomponent function receives a single argument which is a string

B4X:
Dim i as intent
i.setcomponent("com.package.address/.MainActivity")

The assumption here is that the activity name (com.package.address.MainActivity) always starts with package name (com.package.address). But when a rare case like Opera Mobile where package name (com.opera.browser) and activity name (com.opera.Opera) are completely different, I am not sure how B4A will process it.

In Java, setcomponent is done differently

B4X:
intent.setComponent(new ComponentName("com.package.address","com.package.address.MainActivity"));

The argument is a data type called ComponentName that takes package name and activity name as 2 separate arguments. This allows package and activity names to be completely different.

I guess this can be done using Reflection library. Can someone please translate the java code below to B4A using Reflection library? I have been trying to learn reflection for sometime. But when cases where arguments need to be passed to functions (and in this case argument inside argument) I am completely confused.

B4X:
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://google.com/"));
intent.setComponent(new ComponentName("com.opera.browser","com.opera.Opera"));
startActivity(intent);
 
Upvote 0

Harris

Expert
Licensed User
Longtime User
How would I set this up to get apps that can open PDF? And how would one pass the name of a PDF to open once app is chosen?

Thanks
 
Upvote 0

vb1992

Well-Known Member
Licensed User
Longtime User
Harris, see if this works for what you need.


*See comments inside project, for Google Docs Reader, that would be interesting
 

Attachments

  • pdf-intent.zip
    69.2 KB · Views: 247
Last edited:
Upvote 0

vb1992

Well-Known Member
Licensed User
Longtime User
This works without being logged into Google:


https://docs.google.com/viewer?url=http://samplepdf.com/sample.pdf


So if you wanted to:

1- upload/ftp your pdf you created inside of b4a to a web server
2- then once on web server, use this intent to call google docs to read it

you could use this intent, and not have to worry about a pdf app viewer
(but requires that the user has a connection to the internet)


B4X:
Dim i As Intent 'Requires a reference to the Phone library

i.Initialize(i.ACTION_VIEW, ("http://docs.google.com/viewer?url=" & "http://samplepdf.com/sample.pdf"))
i.SetType("text/html")
 
StartActivity(i)






**Edit** a webview would work also instead of the intent with the url:
B4X:
http://docs.google.com/viewer?url=http://samplepdf.com/sample.pdf
Replace "samplepdf.com" with your webserver address where you uploaded the pdf to
 
Last edited:
Upvote 0

Harris

Expert
Licensed User
Longtime User
Thanks vb,

I will give it a try tonite and see how it works out, along with SMTP I goofed up with....
 
Upvote 0

luiswagnersantos

Member
Licensed User
Longtime User
Very good!
That was exactly what I was looking for.
thank you

Luis Wagner


Harris, see if this works for what you need.


*See comments inside project, for Google Docs Reader, that would be interesting
 
Upvote 0

Harris

Expert
Licensed User
Longtime User
vb1992,

The example in the zip works awesome! I cant believe it worked either!!! (in just 5 lines of code). I don't understand what the other examples in this post were trying to cover....

As you stated, Adobe pdf reader SUCKS!!! (more than just buggy). I open my pdf with it - first time no prob - every other time it said it was corrupt!!! Yea, IT corrupted it the first time IT opened it!!! POS... just the kind of crap you expect from bloatware - ever see their Flex product? This is what happens with corporate software - many developers come and go and nobody cleans it up - they just make it MORE bloated... (ref... See Microsoft OS). But I digress.... (awe, that felt good...)


PDF to go, PDF View work well on my Acer A100.

Question? It there a way to choose which reader to default ( a check box - use by default) to rather than ask each time (like found in Astro file manager)?

Great work - exactly what I was looking for...

THIS STUFF GETS BETTER AND BETTER EVERY DAY - THANKS TO B4A!!!!
(and all of you smart dudes and dudettes in the community)
 
Upvote 0

vb1992

Well-Known Member
Licensed User
Longtime User
vb1992,


Question? It there a way to choose which reader to default ( a check box - use by default) to rather than ask each time (like found in Astro file manager)?


Did you end up seeing the Google/Docs solution?

The user would need internet ( cell or wifi ) connection to use Google / Docs as the reader, but it works really good.
 
Upvote 0
Top