3

I'm querying for activities using queryIntentActivities which worked fine in api level 29, but as soon as I upgraded to level 30 the result is always empty.

This is the intent:

val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
intent.putExtra("android.intent.extras.CAMERA_FACING", typeCamera)
uri?.grantWriteForIntent(activity, intent)
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
if (intent.isIntentSafe(activity)) {
    activity.__waitResult__ = true
    activity.startActivityForResult(intent, requestCode)
}

Then the isIntentSafe function:

fun Intent?.isIntentSafe(context: Context) =
    if (this == null)
        false
    else
        context.packageManager.queryIntentActivities(this, PackageManager.MATCH_DEFAULT_ONLY).size > 0

This is where queryIntentActivites is empty in level 30 and has content in level 29. Does anyone know what changed between these level which could have this effect?

I should add that if I skip the isIntentSafe check in both api levels the activity starts fine anyway. But I want to know why isIntentSafe stopped working in the newer api.

EDIT: I have tried changing the intent for the front facing camera like in this answer How to launch front camera with intent? which doesn't make a difference.

just_user
  • 11,769
  • 19
  • 90
  • 135

2 Answers2

1

I went through the Android 11 changes again and found "Media intent actions require default system camera".

So I searched a bit more and found a solution from CommonsGuy. Modified his code a little bit to open the front facing camera, worked straight away!

fun enhanceCameraIntent(context: Context, baseIntent: Intent, title: String): Intent {
    val pm = context.packageManager

    val cameraIntents =
        CAMERA_CANDIDATES.map { Intent(baseIntent).setPackage(it) }
            .filter { pm.queryIntentActivities(it, 0).isNotEmpty() }
            .toTypedArray()

    return if (cameraIntents.isEmpty()) {
        baseIntent
    } else {
        Intent
            .createChooser(baseIntent, title)
            .putExtra(Intent.EXTRA_INITIAL_INTENTS, cameraIntents)
    }
}

fun openFrontFacingCamera(activity: BaseActivity, uri: Uri?, requestCode: Int) {
    try {
        val baseIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)

        uri?.grantWriteForIntent(activity, baseIntent)
        baseIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri)
        baseIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
        baseIntent.putExtra("android.intent.extra.USE_FRONT_CAMERA", true)

        activity.startActivityForResult(
            enhanceCameraIntent(activity, baseIntent, MediaStore.ACTION_IMAGE_CAPTURE),
            requestCode
        )
    } catch (ex: ActivityNotFoundException) {
        Log.d("No default camera", "Activity not found!")
    }
}

As many times before, hat off to CommonsGuy!

just_user
  • 11,769
  • 19
  • 90
  • 135
0

In Android 11 there are new rules for interacting with the apps installed on the device.

So if your app targets Android 11 or higher, you might need to add the <queries> element in your app's manifest file:

<queries>
  <intent>
    <action android:name="android.media.action.IMAGE_CAPTURE" />
  </intent>
</queries>

You can also find more details in this guide.

DmitryArc
  • 4,757
  • 2
  • 37
  • 42
  • Android Studio complains if I added a tag directly inside the manifest putting a mustard background on it and says "this tag isn't allowed here". – just_user Oct 08 '20 at 10:27