How to make call the phone intent properly in Kotlin? - android

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:
Put this line in AndroidManifest.xml:
< uses-permission android:name="android.permission.CALL_PHONE"/>
Add android:exported="true" at the activity on which the call intent is
invoked:
< activity android:name=".activities.ProfileActivity" android:exported="true"/>
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?

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!

Related

`onRequestPermissionsResult()` is not working in Fragment-Kotlin

Problem:
I have done this LocationPermission task with activity but I want to do it with the fragment. In Fragment method onRequestPermissionsResult() is not being called.
There are many answers to this question but unfortunately non of them worked for me. Some of those answers are in java which is not applicable in kotlin, for instance, one answer says using 'FragmentCompat' this problem can be solved but we don't have FragmentCompat in Kotlin.
What I did so far?
I followed this question and many others.
Before ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1)
After:
requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),1)
though requestPermissions is depricated But nothing worked so far.
PLEASE DO CONSIDER KOTLIN LANGUAGE FOR ANSWERS
Code in Fragment:
fun RequestLocationPermission()
{
Log.d(TAG, "RequestLocationPermission: ")
if(ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
if(ActivityCompat.shouldShowRequestPermissionRationale(requireActivity(), Manifest.permission.ACCESS_FINE_LOCATION)){
requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),1)
}
else{
ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), 1)
requestPermissions(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),1)
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
Toast.makeText(requireContext(), "Request Permission Called", Toast.LENGTH_SHORT).show()
Log.d(TAG, "onRequestPermissionResult Called ")
when (requestCode) {
1 -> when {
grantResults.isEmpty() ->
// If user interaction was interrupted, the permission request
// is cancelled and you receive empty arrays.
Log.d(TAG, "User interaction was cancelled.")
grantResults[0] == PackageManager.PERMISSION_GRANTED ->{
// Permission was granted.
locationPermission = true
fetchLocation()
}
else -> {
// Permission denied.
Toast.makeText(requireContext(), "Permission Denied", Toast.LENGTH_SHORT).show();
}
}
}
}

Request permission dialog isn't appear Android 6.0.1

I'm trying to get a Write_external_storage permission at the beginning of app work. But I can't see permission box. Here is my code:
override fun onStart() {
.....
if (Singleton.isPermissionGranted(this)) {
btn_submit_t.isEnabled
} else {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 1)
}
super.onStart()
}
and then I added onRequestPermissionsResult:
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
1 -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.i("m","permission_is_granted")
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
Toast.makeText(this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show()
Handler().postDelayed({
if (Build.VERSION.SDK_INT >= 23) {
if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED) {
//your permission is granted
} else {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 1)
}
}
else {
//permission is automatically granted on devices lower than android M upon installation
}
//ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), 1)
}, 100)
}
return
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
I tested it on different devices, and my problem appears on Xiaomi device with Android 6.0.1 version. I also added checking but it didn't help me. Where can be the problem?
Have u added "WRITE EXTERNAL STORAGE" permission in Manifest File?

Ask permissions just showing granted

I followed the simple steps to ask for multiple permissions at once, here is my code for the permission request:
class MainActivity : AppCompatActivity() {
private val permissionCode = 100
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
getPermissions()
}
fun getPermissions() {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.NFC, Manifest.permission.INTERNET),
permissionCode
)
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
permissionCode -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted
Toast.makeText(this, "Permissions granted", Toast.LENGTH_SHORT).show()
} else {
// Permission denied
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show()
}
}
}
}
When I am starting the app I dont get any dialog to accept or deny the permissions and just get the toast "Permissions granted" but if I check the permissions in the app info I dont see any permissions granted. What I am doing wrong? Can someone help me?
Neither INTERNET nor NFC are permissions that need to be requested at runtime. Just having them in the manifest (via <uses-permission> elements) is sufficient.
Only permissions with a protection level of dangerous need to be requested at runtime — this table lists those. INTERNET and NFC are normal permissions, not dangerous.

Android runtime permission questions

Let's say I'm trying to save a bitmap image to a png
public void save() {
String filename = "file.png";
File sd = Environment.getExternalStorageDirectory();
File dest = new File(sd, filename);
try {
FileOutputStream out = new FileOutputStream(dest);
fBitmap.compress(Bitmap.CompressFormat.PNG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
If I use Android 6.0 and above, I need to ask for runtime permissions
void validatePermissions() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
} else {
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
}
}
}
I have a few questions:
The above code successfully asks for permissions, however I have to re-start the app,
How do I porperly halt the code until permissions are either granted or not granted?
Below Android 6.0, permissions are granted on install by the manifest file. How does android 5 or lower
handle runtime permissions code?
Thanks
You shouldn't restart the app. You should change a logic of your app: wait when user grants the permission and try to run an operation a second time.
And, yes, you can use third-party libraries for this purpose. For example, my personal choice: Permission dispatcher.
The above code successfully asks for permissions, however I have to re-start the app, How
do I porperly halt the code until permissions are either granted or not granted?
You can use this void
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String permissions[], #NonNull int[] grantResults) {
switch (requestCode) {
case 1: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
Toast.makeText(MainActivity.this, "Permission denied to read your External storage", Toast.LENGTH_SHORT).show();
}
}
// other 'case' lines to check for other
// permissions this app might request
}
}
from this answer
Below Android 6.0, permissions are granted on install by the manifest file. How does
android 5 or lower handle runtime permissions code?
The code will be skipped
You can use Dexter library for better performance. I am sharing here both Dexter code also
Using Dexter, you need to add Dexterdependency in your app.build gradle file.
implementation 'com.karumi:dexter:6.2.2'
Single permission/////
Dexter.withContext(activity)
.withPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.withListener(object : PermissionListener {
override fun onPermissionGranted(p0: PermissionGrantedResponse?) {
downloadImage(url)
}
override fun onPermissionDenied(p0: PermissionDeniedResponse?) {
if (p0!!.isPermanentlyDenied) {
showSettingsDialog()
}
}
override fun onPermissionRationaleShouldBeShown(
p0: PermissionRequest?, p1: PermissionToken?
) {
p1!!.continuePermissionRequest()
}
})
.onSameThread()
.check()
Multiple Permission////
Dexter.withContext(requireContext())
.withPermissions(Manifest.permission.RECORD_AUDIO,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE)
.withListener(object : MultiplePermissionsListener {
override fun onPermissionsChecked(p0: MultiplePermissionsReport?) {
if (p0!!.areAllPermissionsGranted())
{
}else if (p0.isAnyPermissionPermanentlyDenied)
{
openSettings()
}
}
override fun onPermissionRationaleShouldBeShown(p0: MutableList<PermissionRequest>?, permissionToken: PermissionToken?) {
permissionToken?.continuePermissionRequest()
}
}).check()

Location permission callback being called again and again

I have implemented Runtime Permission. For testing purpose I have denied location permission and then again I have denied the permission with "Never to ask again" checkbox.
Now there is the problem. OnRequestPermissionResult is being called again and again from the system. For this, I can't show a dialog or snackbar on the screen properly. Here is my implementation. Where is the problem?
Checking location permission
override fun onResume() {
super.onResume()
if (checkLocationPermission())
startLocationUpdates()
updateUI()
}
This is my location update call
#SuppressLint("MissingPermission")
private fun startLocationUpdates() {
// Begin by checking if the device has the necessary location settings.
mLocationSettingsClient.checkLocationSettings(mLocationSettingsRequest)
.addOnSuccessListener(this, {
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
mLocationCallback, Looper.myLooper());
updateUI()
})
.addOnFailureListener(this, {
handlingLocationClientSettingsFailure(it)
});
}
private fun handlingLocationClientSettingsFailure(it: Exception) {
val apiException = it as ApiException
when (apiException.statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> {
try {
Lg.d(TAG, "Inside start location update method FAILURE: REQUIRED")
// Show the dialog by calling startResolutionForResult(), and check the
// result in onActivityResult().
val rae = it as ResolvableApiException
rae.startResolutionForResult(this#MainActivity, REQUEST_CHECK_SETTINGS);
} catch (sie: IntentSender.SendIntentException) {
Log.i(TAG, "PendingIntent unable to execute request.");
}
}
LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> {
val errorMessage = "Location settings are inadequate, and cannot be " +
"fixed here. Fix in Settings.";
Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show();
mRequestingLocationUpdates = false;
}
}
updateUI()
}
override fun onStop() {
super.onStop()
stopLocationUpdates()
}
private fun stopLocationUpdates() {
if (!mRequestingLocationUpdates) {
Lg.d(TAG, "Permission Denied! So No op!!!")
return
}
mFusedLocationClient.removeLocationUpdates(mLocationCallback)
.addOnCompleteListener(this) { mRequestingLocationUpdates = false }
}
private val MY_PERMISSIONS_REQUEST_LOCATION = 99;
private fun startLocationPermissionRequest() {
ActivityCompat.requestPermissions(this#MainActivity,
arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION),
MY_PERMISSIONS_REQUEST_LOCATION);
}
private fun checkLocationPermission(): Boolean {
if (ContextCompat.checkSelfPermission(this#MainActivity, ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(this#MainActivity, ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
android.Manifest.permission.ACCESS_FINE_LOCATION)) {
showSnackbar(R.string.location_permission_rationale,
android.R.string.ok,
View.OnClickListener {
startLocationPermissionRequest()
})
} else {
// No explanation needed, we can request the permission.
startLocationPermissionRequest()
}
return false
} else {
// Permission has already been granted
return true
}
}
#SuppressLint("NeedOnRequestPermissionsResult")
override fun onRequestPermissionsResult(requestCode: Int,
permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
MY_PERMISSIONS_REQUEST_LOCATION -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// location-related task you need to do.
if (ContextCompat.checkSelfPermission(this#MainActivity, ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
&& ContextCompat.checkSelfPermission(this#MainActivity, ACCESS_COARSE_LOCATION)
!= PackageManager.PERMISSION_GRANTED
) {
setLocationEnabled()
startLocationUpdates()
}
} else {
val showRationale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
shouldShowRequestPermissionRationale(permissions[0])
} else {
TODO("VERSION.SDK_INT < M")
}
if (!showRationale) {
// user also CHECKED "never ask again"
// you can either enable some fall back,
// disable features of your app
// or open another dialog explaining
// again the permission and directing to
// the app setting
showingNecessaryMsgForLocationPermissionDenied()
} else {
// user did NOT check "never ask again"
// this is a good place to explain the user
// why you need the permission and ask if he wants
// to accept it (the rationale)
}
}
return
}
// other 'case' lines to check for other
// permissions this app might request
}
}
private fun showingNecessaryMsgForLocationPermissionDenied() {
Lg.d("TestTag", "Called")
MaterialDialog.Builder(this)
.title("Permission")
.content(R.string.permission_denied_explanation)
.onPositive { dialog, which ->
// Build intent that displays the App settings screen.
val intent = Intent().apply {
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
data = Uri.fromParts("package", APPLICATION_ID, null)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
startActivity(intent)
}
.positiveText(R.string.ok)
.show()
}
In this showingNecessaryMsgForLocationPermissionDenied() function I put a log, in my logcat I see that this function called again and again. How to stop it? Here is the logcat screentshot
I want to show this dialog when user denied permission. But I can't draw this smoothly for the above problem.
Note: I have tested the google repository of location update project. Same problem
Based on the documentation of Activity.requestPermissions
This method may start an activity allowing the user to choose which permissions to grant and which to reject. Hence, you should be prepared that your activity may be paused and resumed. Further, granting some permissions may require a restart of your application.
In this code, you are calling checkLocationPermission() in onResume(). Then from checkLocationPermission() call goes to requestPermissions which takes Activity in onPasue(). After onRequestPermissionsResult(), onResume() gets called again, creating infinte loop.
I would suggest having a boolean variable to decide if to call to checkLocationPermission() required.
var isRequestRequired = true;
override fun onResume() {
super.onResume()
if (isRequestRequired && checkLocationPermission())
startLocationUpdates()
updateUI()
}
then update isRequestRequired to false before showingNecessaryMsgForLocationPermissionDenied()
isRequestRequired = false
showingNecessaryMsgForLocationPermissionDenied()
This will stop onResume() from calling checkLocationPermission() again and again

Categories

Resources