Android 11 (R) return empty list when querying intent for ACTION_IMAGE_CAPTURE
T

4

37

Device: Emulator pixel 3a - Android 11

Code:

    final List<Intent> cameraIntents = new ArrayList<Intent>();
    final Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    final List<ResolveInfo> listCam = 
    context.getPackageManager().queryIntentActivities(captureIntent, 0);

When using:

targetSdkVersion 30
compileSdkVersion 30

listCam size is 0

and when changing to:

compileSdkVersion 29

listCam size is 1 - as it should be.

Using the following code:

    val captureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    baseActivity.startActivity(captureIntent)

Works fine and shows the camera app.

Any idea why queryIntentActivities is not returning the camera intent?

Thanks!

Terret answered 4/8, 2020 at 12:0 Comment(1)
A
100

Android 11 changes how apps can query and interact with other apps.

From the docs:

The PackageManager methods that return results about other apps, such as queryIntentActivities(), are filtered based on the calling app's <queries> declaration.

So you need to declare <queries> in your AndroidManifest.xml:

<manifest package="com.example">
    <queries>
        <intent>
            <action android:name="android.media.action.IMAGE_CAPTURE" />
        </intent>
    </queries>
    ...
</manifest>
Apiarist answered 4/8, 2020 at 12:21 Comment(6)
Yes, but: Starting in Android 11, only pre-installed system camera apps can respond to the following intent actions: android.media.action.VIDEO_CAPTURE android.media.action.IMAGE_CAPTURE android.media.action.IMAGE_CAPTURE_SECURE So even if we declared <queries> tag - queryIntentActivities function returns only one system camera app, alwaysPostmillennialism
Is there a workaround for ADB? these intents have stopped working on Android 11 even via the ADB.Neuro
That was exactly the solution for me as well! I had to put these query elements in the manifest. I just want to mention in order to get that working I had to upgrade gradle. I had a very old code base with a very old version of gradle. My job here was to upgrade from API level 22 to 30 and this is one issue I had to solve. About gradle support for the element take a look at thisCosme
What is the package name "com.example", Is this your app's package name or the app you are targeting?Saltant
@Saltant It is your app's package nameApiarist
There is also a more detailed blog-post (written by a Google employee) on medium explaning these changes here: medium.com/androiddevelopers/…Swoop
K
31

packageManager.queryIntentActivities(intent, 0) will return an EMPTY list if your app is running on targetSdkVersion 30

To resolve this issue you have to use <queries> in manifest as queryIntentActivities() are filtered based on the calling app's declaration.

Fix image capture + image upload to work with Android "scoped storage"

The issue can be related to new package visibility (https://developer.android.com/about/versions/11/privacy/package-visibility). After all updates (at least Android Studio 4.1) try to add in your manifest the that show what action is required in your app.

In my case, the problem disappears when I add IMAGE_CAPTURE for CAMERA, GET_CONTENT for GALLERY (to get files change mimeType if you want video), PICK for GALLERY (should change mimetype if u want video) CHOOSER for GALLERY (if someone has other image browsers)

You can also check in logcat what queries you have to add (should contains "BLOCKED" or "no permission". Error is because ImagePickerModule when you don't have permission in Intent with resolveActivity returns null (you can comment it to check better errors in startActivityForResult)

Add <query> in AndroidManifest.xml

<manifest>
.....
.....
<queries>
    <!-- Browser -->
    <intent>
        <action android:name="android.intent.action.VIEW" />
        <data android:scheme="http" />
    </intent>
    <!-- Camera -->
    <intent>
        <action android:name="android.media.action.IMAGE_CAPTURE" />
    </intent>
    <!-- Gallery -->
    <intent>
        <action android:name="android.intent.action.GET_CONTENT" />
        <data android:mimeType="image/*" />
    </intent>
    <intent>
        <action android:name="android.intent.action.PICK" />
        <data android:mimeType="image/*" />
    </intent>
    <intent>
        <action android:name="android.intent.action.CHOOSER" />
     </intent>
</queries>
.....
.....
</manifest>
Kosaka answered 29/4, 2021 at 11:59 Comment(1)
perfect, thanks for sharing !Architrave
P
8

My solution for Android 11, for getting ResolveInfo list.

  • When we scan only by MediaStore.ACTION_IMAGE_CAPTURE filter then we will get only One! application record - System default camera app.
  • For using additional camera apps we need to specify each application by package name, and provide it with setPackage() call - and then queryIntentActivities works correctly, even in Android R

The full solution is below:

/**
 * Return all camera possible apps
 * @param context
 * @return
 */
public static List<ResolveInfo> getCameraAppsResolveInfo(Context context){
    List<ResolveInfo> resolveInfo = new ArrayList<>();
    if (Utils.isNull(context)){
        return resolveInfo;
    }
    final Intent capturePhoto = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    PackageManager pm = context.getPackageManager();
    resolveInfo = pm.queryIntentActivities(capturePhoto, 0);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R){
        // For Android 11 we need to add specific camera apps
        // due them are not added during ACTION_IMAGE_CAPTURE scanning...
        resolveInfo.addAll(getCameraSpecificAppsInfo(context));
    }
    return resolveInfo;
}

/**
 * For Android 11
 * Return camera possible apps
 */
static final String[] CAMERA_SPECIFIC_APPS =  new String[]{
        "best.camera",
        "net.sourceforge.opencamera",
        "com.google.android.GoogleCamera",
        "tools.photo.hd.camera",
};
private static List<ResolveInfo> getCameraSpecificAppsInfo(Context context){
    List<ResolveInfo> resolveInfo = new ArrayList<>();
    if (Utils.isNull(context)){
        return resolveInfo;
    }
    PackageManager pm = context.getPackageManager();
    for (String packageName : CAMERA_SPECIFIC_APPS) {
        resolveInfo.addAll(getCameraSpecificAppInfo(packageName, pm));
    }
    return resolveInfo;
}
private static List<ResolveInfo> getCameraSpecificAppInfo(String packageName, PackageManager pm){
    Intent specificCameraApp = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    specificCameraApp.setPackage(packageName);
    return pm.queryIntentActivities(specificCameraApp, 0);
}

Of course in manifest file we should add these lines (as described in accepted answer)

<queries>
        <intent>
            <action android:name="android.media.action.IMAGE_CAPTURE" />
        </intent>
</queries>
Postmillennialism answered 25/9, 2020 at 8:18 Comment(1)
Can you give a workaround for ADB? This - adb -d shell am start -a android.media.action.IMAGE_CAPTURE doesn't do anything on android 11Neuro
S
4

@saurabh-thorat is correct about the queries. But I found out that even if you want all, you still need to add a data tag for it to work with all mime types (or at least that was my case in my react-native app). So it should be as below for actions on mime types (e.g.: view/send/open):

<manifest package="com.example">
    <queries>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:mimeType="*/*" />
        </intent>
    </queries>
    ...
</manifest>
Shark answered 22/12, 2021 at 10:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.