1

I tried to call the phone intent on Kotlin, like this:

 imgPhone.setOnClick {
            val intent = Intent(Intent.ACTION_CALL, Uri.parse("tel:" + "1122334455"))
            startActivity(intent)
        }

When the phone image is clicked, nothing visually happens. Turns out the debugger showed you this:

java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.CALL dat=tel:xxxxxxxxxx cmp=com.android.server.telecom/.components.UserCallActivity }

I've tried several solutions:

  1. Put this line in AndroidManifest.xml:

< uses-permission android:name="android.permission.CALL_PHONE"/>

  1. Add android:exported="true" at the activity on which the call intent is invoked:

    < activity android:name=".activities.ProfileActivity" android:exported="true"/>
    
  2. Ask permission explicitely:

    override fun onCreate() {
    super.onCreate()
    /*
    more codes here
    */
    setupPermissions()
     }
    
    fun setupPermissions() {
    val permission = ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE)
    
        if (permission != PackageManager.PERMISSION_GRANTED) {
        Log.i("Error", "Permission to call denied")
        }
    }
    

So far, none of those workarounds work (on Android 6). The same SecurityException still occurs. What is the proper solution, then?

anta40
  • 6,511
  • 7
  • 46
  • 73

1 Answers1

4

In Marshmallow you have to request permission during runtime, just in the manifest is not enough. On the option (3) you wrote you almost did it. There you're only checking for permission, but not asking for it.

The official docs is this: https://developer.android.com/training/permissions/requesting

The code will be something similar to this:

fun checkPermission() {
   if (ContextCompat.checkSelfPermission(this,
           Manifest.permission.CALL_PHONE)
           != PackageManager.PERMISSION_GRANTED) {

       // Permission is not granted
       // Should we show an explanation?
       if (ActivityCompat.shouldShowRequestPermissionRationale(this,
            Manifest.permission.CALL_PHONE)) {
           // Show an explanation to the user *asynchronously* -- don't block
           // this thread waiting for the user's response! After the user
           // sees the explanation, try again to request the permission.
       } else {
           // No explanation needed, we can request the permission.
           ActivityCompat.requestPermissions(this,
                   arrayOf(Manifest.permission.CALL_PHONE),
                   42)
       }
   } else {
       // Permission has already been granted
       callPhone()
   }
}

override fun onRequestPermissionsResult(requestCode: Int,
        permissions: Array<String>, grantResults: IntArray) {
    if (requestCode == 42) {
            // If request is cancelled, the result arrays are empty.
            if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                // permission was granted, yay!
                callPhone()
            } else {
                // permission denied, boo! Disable the
                // functionality
            }
            return
        }
}

fun callPhone(){
        val intent = Intent(Intent.ACTION_CALL, Uri.parse("tel:" + "1122334455"))
        startActivity(intent)
}

And don't forget you also need it on the manifest. And you can remove that exported from your activity, that's pointless.

I hope it helps!

Budius
  • 39,391
  • 16
  • 102
  • 144