Home > Enterprise >  Passing (new Intent(Intent.ACTION_SENDTO)).setData(Uri.parse("mailto:") to intent.setSelec
Passing (new Intent(Intent.ACTION_SENDTO)).setData(Uri.parse("mailto:") to intent.setSelec

Time:05-19

Based on this post, I am opening an email client to send multiple attachments with the following code:

Intent emailSelectorIntent = new Intent(Intent.ACTION_SENDTO);
emailSelectorIntent.setData(Uri.parse("mailto:"));

Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
intent.putExtra(Intent.EXTRA_EMAIL, addresses);
intent.putExtra(Intent.EXTRA_SUBJECT, subject);

ArrayList<Uri> uriList = new ArrayList<>();
uriList.add(FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID   ".provider", fileA));
uriList.add(FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID   ".provider", fileB));
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.putExtra(Intent.EXTRA_STREAM, uriList);

intent.setSelector(emailSelectorIntent);

if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(intent);
}

Note that, as taught in the linked post above, I need two Intents to make it work for sending attachments (and limiting the selector to only email clients)... emailSelectorIntent and intent, with the former being passed to the latter via intent.setSelector(emailSelectorIntent).

In order to make the selector open up, I also need the following in my Manifest:

<intent-filter>
    <action android:name="android.intent.action.SENDTO" />
    <data android:scheme="mailto" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

But when the selector opens, not only do I get email clients showing (e.g. gmail) I am also getting my own app in the list... which is not capable of sending emails.

This post suggests not putting android.intent.action.SENDTO in the Manifest, but if I remove that then the selector no longer opens at all. If put it back, the selector opens but with my own app as an option for an email client (which it is not).

So how do I avoid my own app showing up in the selector list in this context?

Note that my targetSdk is 32 in case that's relevant, which it may be (see comment from @CommonsWare here).

CodePudding user response:

I'm somewhat mystified that having that <intent-filter> changes anything. Regardless, you really don't want that there, as it can cause other apps to route ACTION_SENDTO requests to your app, which you don't want.

without android.intent.action.SENDTO in the Manifest, startActivity() is never called because the test intent.resolveActivity(getPackageManager()) != null fails

That is due to package visibility rules. Your options are to either add <queries> to say that you need to see who all supports your Intent, or to replace the resolveActivity() call with a try/catch:

try {
    startActivity(intent);
} catch (Exception e) {
    // whatever you want to do to gracefully degrade in case there is no suitable activity to start
}

not sure how this will work on older versions of Android?

<queries> will be ignored on older versions of Android, but package visibility isn't a problem on older versions of Android. Personally, I prefer try/catch, as it handles more scenarios.

CodePudding user response:

The answer from @CommonsWare is (as ever) very pragmatic and informative. I think I prefer the try/catch solution proposed there too, and will adopt it. But the alternative of leaving the resolveActivity() check and adding a <queries> item in the top level of the Manifest also works, like so:

<queries>
    <intent>
        <action android:name="android.intent.action.SENDTO" />
        <data android:scheme="mailto" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent>
</queries>
  • Related