5

I have an alertDialogBuilder that creates an Intent to send an email.

It worked well but since last week it stopped to work and is giving the following error:

java.lang.SecurityException: Permission Denial: starting Intent

I am using the same device all the time with Android versión 4.4.2 and on my gradle I am supporting the following versions:

minSdkVersion 16
targetSdkVersion 23

My code is:

alertDialogBuilder
    .setMessage("Do you want to send an email to " + getString(R.string.companyName) + "?")
    .setCancelable(false)
    .setPositiveButton("Send",new DialogInterface.OnClickListener() {
          public void onClick(DialogInterface dialog,int id) {

                Intent gmail = new Intent(Intent.ACTION_SEND);
                gmail.setClassName("com.google.android.gm","com.google.android.gm.ComposeActivityGmail");
                gmail.putExtra(Intent.EXTRA_EMAIL, new String[] { "myEmail@email.com" });
                gmail.setData(Uri.parse("myEmail@email.com"));
                gmail.setType("plain/text");
                startActivity(gmail);
          }
    })
    .setNegativeButton("Cancel",new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int id) {
                   dialog.cancel();
            }
    });

I know that there are two questions directly related with this question:

but I could not solve my problem with none of them. I also does not understand why it worked one week ago and now it stopped to work. I did not make any changes on Gmail application on my device and I have it installed on the device too.

What am I missing? I can paste the full stacktrace if required, I have put only the error name to reduce the size of the question.

EDIT: My error stacktrace is the following:

12-27 17:38:15.507 7816-7816/com.project.user.product E/AndroidRuntime: FATAL EXCEPTION: main
         Process: com.project.user.product, PID: 7816
         java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.SEND typ=plain/text cmp=com.google.android.gm/.ComposeActivityGmail (has extras) } from ProcessRecord{428b7c68 7816:com.project.user.product/u0a107} (pid=7816, uid=10107) not exported from uid 10048
             at android.os.Parcel.readException(Parcel.java:1472)
             at android.os.Parcel.readException(Parcel.java:1426)
             at android.app.ActivityManagerProxy.startActivity(ActivityManagerNative.java:2222)
             at android.app.Instrumentation.execStartActivity(Instrumentation.java:1425)
             at android.app.Activity.startActivityForResult(Activity.java:3480)
             at android.app.Activity.startActivityForResult(Activity.java:3432)
             at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:842)
             at android.app.Activity.startActivity(Activity.java:3683)
             at android.app.Activity.startActivity(Activity.java:3651)
             at com.project.user.product.LoginActivity$7$2.onClick(LoginActivity.java:284)
             at android.support.v7.app.AlertController$ButtonHandler.handleMessage(AlertController.java:157)
             at android.os.Handler.dispatchMessage(Handler.java:110)
             at android.os.Looper.loop(Looper.java:193)
             at android.app.ActivityThread.main(ActivityThread.java:5333)
             at java.lang.reflect.Method.invokeNative(Native Method)
             at java.lang.reflect.Method.invoke(Method.java:515)
             at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:828)
             at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:644)
             at dalvik.system.NativeStart.main(Native Method)

Thanks in advance!

Community
  • 1
  • 1
Francisco Romero
  • 12,787
  • 22
  • 92
  • 167
  • 1
    "I can paste the full stacktrace if required" -- that is probably a good idea. A better idea is to get rid of `gmail.setClassName("com.google.android.gm","com.google.android.gm.ComposeActivityGmail");`, as AFAIK that activity is no longer exported (which would lead to your error message), and it was a user-hostile idea in the first place. – CommonsWare Dec 27 '16 at 16:29
  • @CommonsWare Thank you for answer but I do not really understand what do you mean with the second part of your comment. And instead of that function what should I use? Or just rid it? – Francisco Romero Dec 27 '16 at 16:34
  • "I do not really understand what do you mean with the second part of your comment" -- not everybody uses Gmail. Your code assumes that everybody does. For non-Gmail users, your app may crash (Gmail does not exist) or route users into a Gmail onboarding that they do not want. "Or just rid it?" -- correct. – CommonsWare Dec 27 '16 at 16:40
  • @CommonsWare So, how should I configure it? Or just rid that line? I have updated the question with the error stacktrace. In the device that I am using now I have installed Gmail. – Francisco Romero Dec 27 '16 at 16:42
  • @CommonsWare Ok. Thank you! It worked so good. – Francisco Romero Dec 27 '16 at 16:50

2 Answers2

5
gmail.setClassName("com.google.android.gm","com.google.andro‌​id.gm.ComposeActivit‌​yGmail");

This statement says that your app requires that the user use Gmail, and more specifically, that the user use some older version of Gmail. Hence, your code does not support:

  • Users of devices where Gmail simply is not installed (which may or may not be a possibility, depending upon your app distribution channels)

  • Users of devices where they do not have access to Gmail (e.g., secondary device users)

  • Users of devices where they have Gmail disabled, because they use some other email account (e.g., me)

  • Users of devices where they have Gmail available, but do not normally use it or would prefer not to use it for this particular situation

  • Users of devices with a current version of Gmail, as com.google.andro‌​id.gm.ComposeActivit‌​yGmail is no longer available for direct launch by third-party apps, such as yours

The latter point is what is leading to your exception.

So, delete that statement. Also:

  • plain/text is not a valid MIME type. Use text/plain. Or, better yet, get rid of gmail.setType("plain/text"); entirely, as you are not using EXTRA_TEXT or EXTRA_STREAM, and that is what the MIME type of an ACTION_SEND Intent is tied to.

  • Delete gmail.setData(Uri.parse("myEmail@email.com"));, as ACTION_SEND does not use the data facet of the Intent.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Thank you very much! Nice explanation. Nevertheless, it does not give me any problem using `plain/text`. Is just a coincidence? – Francisco Romero Dec 27 '16 at 16:56
  • @Error404: The apps that are responding to your `Intent` probably have a MIME type filter of `*/*`. Any that had `text/plain` or `text/*` would not show up as an option for you. – CommonsWare Dec 27 '16 at 16:58
  • I have tried removing the line `gmail.setType("plain/text")` and it gives to me the following error: `android.content.ActivityNotFoundException: No Activity found to handle Intent`. If I use `text/plain` instead I get more applications to choose between than when I was using `plain/text`. – Francisco Romero Dec 27 '16 at 17:08
  • 1
    @Error404: Usually, when developers use `ACTION_SEND`, it is with the intent to actually send something, and the MIME type is the type of the "something". In your case, you are not sending anything (no `EXTRA_TEXT` and no `EXTRA_STREAM`). I had not thought that all the way through, and you are going to need some MIME type, even if it is superfluous. "If I use text/plain instead I get more applications to choose between than when I was using plain/text." -- from the user's standpoint, this is generally a good thing. – CommonsWare Dec 27 '16 at 17:13
  • Ok, now I understand it. Thank you very much for your help. As usually, you saved my day :) – Francisco Romero Dec 27 '16 at 17:16
1

Updated 2020 answer:

Instead of setClassName, use setPackage("com.google.android.gm")

Lorenzo
  • 1,605
  • 14
  • 18