Status Update
Comments
ad...@google.com <ad...@google.com>
ad...@google.com <ad...@google.com> #4
ej...@google.com <ej...@google.com> #5
Similar to android:mimeType
attributes in your <intent>
elements:
<queries>
<intent>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.APP_CONTACTS" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data
android:scheme="content"
android:host="contacts"
android:mimeType="vnd.android.cursor.dir/person"/>
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data
android:scheme="content"
android:host="com.android.contacts"
android:mimeType="vnd.android.cursor.dir/contact" />
</intent>
</queries>
Or you might prefer the more succinct but slightly less precise form: (since a content URI is assumed when only a mime-type is specified)
<queries>
<intent>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.APP_CONTACTS" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:mimeType="vnd.android.cursor.dir/person"/>
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:mimeType="vnd.android.cursor.dir/contact" />
</intent>
</queries>
When you use an Intent
in your code, the mime-type of the data is inferred based on the content URI (unless you set the mime-type explicitly). That's how your second and third example intents (where you don't set the mime-type) are able to match intent filters that do specify a mime-type. eg. See the intent filters of the
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="vnd.android.cursor.item/person"/>
<data android:mimeType="vnd.android.cursor.item/contact"/>
<data android:mimeType="vnd.android.cursor.item/raw_contact"/>
</intent-filter>
That mime-type inference doesn't apply to <intent>
elements in the <queries>
declaration, and so it is necessary to state the android:mimeType
attributes explicitly.
You can find the mime-type for an arbitrary URI via adb:
$ adb shell content gettype --uri content://com.android.contacts/contacts
Result: vnd.android.cursor.dir/contact
Or via the developer documentation.
Also note that specifying the android:path
attribute in the <data>
elements of a <queries>
declaration have no effect. Per
You cannot use the path, pathPrefix, pathPattern, or port attributes in a <data> element. The system behaves as if you set each attribute's value to the generic wildcard character (*).
lb...@gmail.com <lb...@gmail.com> #6
1. The "category" is marked in the IDE as something that isn't supported.
2. Your solution caused the IDE to be almost useless for Kotlin code. Reported here:
3. See this is quite a hard thing to do. Please provide a better migration for this part.
Why not have a tool for it, have logs for it (warning on debug version, that some intents were filtered and what we can do to make it work properly), have an API for this,...
Even the docs don't have what you've mentioned, of the adb command.
4. Why can't we still have a nice file-extension solution? If I want to support handling of file "*.ABCD" there is still no way to do it nicely...
Description
- Steps to reproduce the problem (including sample code if appropriate).
1. Install some apps that are considered as contacts apps, or ones that can handle the Intent for it:
2. Try to make an app that will offer to open the Contacts app/s of the device, that will use multiple methods query what's available and see if it's even possible to open it (to offer the user a result with maximum chance that he could do it):
fun getOpenContactsAppIntent(context: Context) {
val packageManager = context.packageManager
val intents = ArrayList<Intent>()
intents.add(Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_APP_CONTACTS))
intents.add(Intent(Intent.ACTION_VIEW).setData(Uri.parse("content://contacts/people")))
intents.add(Intent(Intent.ACTION_VIEW, ContactsContract.Contacts.CONTENT_URI))
intents.forEachIndexed { index, intent ->
val activities = packageManager.queryIntentActivities(intent, 0)
val apps = HashSet<String>(activities.size)
activities.forEach { apps.add(it.activityInfo.packageName) }
Log.d("AppLog", "$index apps activities found for intent:${activities.size} apps:$apps")
}
}
Notice that on Android 11 (when targeting it), you will need to add some configurations to the manifest, as opposed to before:
<intent>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.APP_CONTACTS" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data
android:host="contacts" android:path="/people" android:scheme="content" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data
android:host="com.android.contacts" android:path="/contacts" android:scheme="content" />
</intent>
Run and notice that you get Google's contacts app (com.google.android.contacts) for each and Tasker (net.dinglisch.android.taskerm) as an additional result for the first one. Meaning:
2,1,1
Now compare this to what happens in these cases:
a. Remove the first "queries" child tag, meaning the second and third Intents should still work.
b. Add QUERY_ALL_PACKAGES permission, or run on Android 10 and below with the same apps installed:
<uses-permission
android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" />
c. Add Google's own app to the "queries", while also removing the first "queries" child tag:
<package android:name="com.google.android.contacts" />
- What happened.
Sadly, compared to before (or compared to having just QUERY_ALL_PACKAGES permission), this can result in less items.
The only Intent that seems to work here is the first one (with the Intent.CATEGORY_APP_CONTACTS), but even then, you won't get all results.
For #a , you will get: 0,0,0 , meaning you won't get even one result.
For #b, you will actually 2,2,3 , meaning you got more than the original.
For #c, you will get 1,1,1, because it got it all for Google's own app.
As a bonus, for some reason I've noticed it doesn't always show all Intents results. No idea why.
- What you think the correct behavior should be.
Each should still work as before, because it was set as such. I've set the queries configurations to be exactly as the Intents I've queried.
Even if I add Google's own app into the "queries" tag, it shows that it got it for each of the Intents, but this is not a practical solution as I would have to add each contacts app out there.
Using this one won't help at all (brings you 0 results for each of the Intents) :
<intent>
<action android:name="android.intent.action.VIEW" />
</intent>
See attached.
So, the only workaround for this would be to either use the new permission, or use this:
<intent>
<action android:name="android.intent.action.MAIN" />
</intent>