I'm implementing app permission flow to use geo location. I requested ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION by requestPermissions() in a Fragment.
requestPermissions(
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION),
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION
)
companion object {
private const val PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION = 1
:
}
And I received the request permissions result by onRequestPermissionsResult() in Fragment.
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION -> {
if (grantResults.isNotEmpty() &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// User granted permission in system dialog
} else {
// User denied permissions
}
}
}
}
But onRequestPermissionsResult() strangely received only single permission which was ACCESS_COARSE_LOCATION in the second parameter as permissions: Array.
And checkSelfPermission() also returned false even choosing allow in a system dialog.
// this condition returns false after receiving permission result on onRequestPermissionsResult()
ContextCompat.checkSelfPermission(requireContext(),
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(requireContext(),
Manifest.permission.ACCESS_COARSE_LOCATION) {
}
I wonder why onRequestPermissionsResult() received only ACCESS_COARSE_LOCATION as the result, even though I request multiple permissions by giving array of ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION when I call requestPermissions().
Could you please explain to me why permissions request only returns the single permission result?
Thank you in advance for your help.
You need to use only single permission for ACCESS_FINE_LOCATION. You don't need to use both. Because your request permission ACCESS_FINE_LOCATION is include both ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION.
https://developer.android.com/training/location/retrieve-current#Permission
For handle multiple permissions I'm highly recommended the below library is perfectly handle every scenarios.
Dexter: com.karumi:dexter:6.#.#
For multiple permissions you could use:
Dexter.withContext(this)
.withPermissions(
Manifest.permission.CAMERA,
Manifest.permission.READ_CONTACTS,
Manifest.permission.RECORD_AUDIO
).withListener(new MultiplePermissionsListener() {
#Override public void onPermissionsChecked(MultiplePermissionsReport report) {/* ... */}
#Override public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {/* ... */}
}).check();
Good luck
Related
In Android 13, I need a basic flow to get permission for push notifications:
class MainActivity : ComponentActivity(), LocationListener {
val notificationPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
if (isGranted) {
// Permission is granted. Continue the action or workflow in your
// app.
} else {
// Explain to the user that the feature is unavailable because the
// feature requires a permission that the user has denied. At the
// same time, respect the user's decision. Don't link to system
// settings in an effort to convince the user to change their
// decision.
}
}
private fun requestPushNotificationPermissions(){
if ((ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED)) {
// granted
}else {
// not granted, ask for permission
notificationPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
}
}
This is what happened:
when user first installed the app, checkSelfPermission returns not granted, and we then lauch permission launcher
user sees the permission dialog in Android 13
user selects Allow
Expected: registerForActivityResult callback will be fired with isGranted true
Actual: registerForActivityResult callback is not fired.
Same if user selects Not Allow. callback is never fired. Why?
This is my dependencies:
implementation 'androidx.activity:activity-ktx:1.2.0-alpha07'
implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha07'
sadly can't help why it doesn't work. But I used EasyPermission for handling the permissons request and it works fine.
https://github.com/googlesamples/easypermissions
Turns out, the registerForActivityResult callback never fires, because somewhere in the Activity, there is this piece of old function "onRequestPermissionsResult" that is accidentally catching all permissions callback:
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
if (requestCode == locationPermissionCode) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//Location permission granted
}
else {
//Location permission denied
}
}else{
//Notification permission callback accidentally landed here silently
}
}
Hope this helps someone.
I'm developing an APP using jetpack compose. On the onboarding screen I need to ask user for permission, but only when I ask for fine location permission, there is dialog popup. When I ask for BLUETOOTH, nothing happened. I debug my code, print log information.
Here is my button for requesting permission
Button(onClick = {
// navController.navigate(Screen.OnboardingLocationScreen.route)
Log.d("bluetooth permission", "${activity.checkSelfPermission(android.Manifest.permission.BLUETOOTH) == PackageManager.PERMISSION_GRANTED}")
ActivityCompat.requestPermissions(activity,
arrayOf(
android.Manifest.permission.BLUETOOTH,
android.Manifest.permission.BLUETOOTH_SCAN,
android.Manifest.permission.BLUETOOTH_CONNECT
),
3
)
}
It turns out without asking permission, Bluetooth is already granted. I find log information is true and I receive message from onRequestPermissionsResult() without grant permission on the app.
#Deprecated("Deprecated in Java")
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 3) {
Log.d("permission","bluetooth")
}
Here is log information
D/bluetooth permission: true
D/permission: bluetooth
I'm using API29 now.
I am new to Android App development and I'd really like to know if there is a way to check in another Class (a Foreground Service that gathers some location data) if the location Permission was given in the Main Activity.
In my main Activity, I am requesting the permission straight upon app start like this:
private fun requestPermissions() {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION),
PERMISSION_ID
)
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSION_ID) {
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
Toast.makeText(this, "Right Permissions Granted", Toast.LENGTH_LONG).show()
}
}
}
}
Its working and I can give my app the permission to access the location. To use a function in my other I class, I need to check if the permission was granted, and I do it like this:
fun dummy(){
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
// do work that needs the location permission
}
}
However, if I try to execute this function, I get a null pointer reference. What am I missing here?
Thank you!
You can't request permissions from a Service. The reason is that when the request permission dialog comes up, the user is naturally going to think it belongs to the foreground app. THat confusion is why Google doesn't allow it. My best suggestion would be to launch an Activity that then asks for permission.
I was asking for WRITE_EXTERNAL_STORAGE permission with the following statement
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), PERMISSION_WRITE)
This was working...until now. In the method onRequestPermissionsResult, grantResults always contains -1
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String?>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == PERMISSION_WRITE) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Timber.i("PERMISSION GRANTED")
} else {
showSettingsDialog()
}
}
}
Also, I have the uses-permission in the manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
The thing is, if I go to the app settings the permission appears as granted but from the app it always return is not granted.
I tried deleting build folders because none has changed and this was working fine for a week
Any idea about what can I test?
best regards
It seems a bug in android 10, so you can replace the permission in manifest with:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="replace"/>
I tried to grant WRITE_SETTING permissions to allow my application to increase the brightness in a view I tried the code below as it is mentioned in the documentation of android but every time no popup that allows the user to accept or deny the permission I tried to debug the code grantResults [0] is always equal to -1
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.WRITE_SETTINGS
) != PackageManager.PERMISSION_GRANTED
) {
// Permission is not granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_SETTINGS)) {
// 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.WRITE_SETTINGS),
10
)
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
} else {
Settings.System.putInt(
this.contentResolver,
Settings.System.SCREEN_BRIGHTNESS, 255
)
}
}
override fun onRequestPermissionsResult(requestCode: Int,
permissions: Array<String>, grantResults: IntArray) {
when (requestCode) {
10 -> {
// If request is cancelled, the result arrays are empty.
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
Settings.System.putInt(
this.contentResolver,
Settings.System.SCREEN_BRIGHTNESS,255
)
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return
}
// Add other 'when' lines to check for other
// permissions this app might request.
else -> {
// Ignore all other requests.
}
}
}
}
WRITE_SETTINGS is not one that you can request via requestPermissions(). That is only for dangerous permissions, and WRITE_SETTINGS does not have that protectionLevel.
Quoting the documentation:
Note: If the app targets API level 23 or higher, the app user must explicitly grant this permission to the app through a permission management screen. The app requests the user's approval by sending an intent with action Settings.ACTION_MANAGE_WRITE_SETTINGS. The app can check whether it has this authorization by calling Settings.System.canWrite().