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.
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 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.
In my application, i need to request write and read permission from the storage. Since i want to show the user that the app needs these permissions, i have created and Activity containing a button, which on click, should call the Storage permission Dialog.
However, since the recent Android changes, this doesnt work anymore.
Is there a new (and clean) way to ask permission? Am i doing something wrong?
I have added the uses-permission line inside the AndroidManifest.xml:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
This is the code inside the Activity:
class ActivityPermission : AppCompatActivity() {
companion object {
var PERMISSION_REQUEST_CODE = 12
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPermissionBinding.inflate(layoutInflater)
setContentView(R.layout.activity_permission)
binding.btnPermission.setOnClickListener {
ActivityCompat.requestPermissions(this, arrayOf(
android.Manifest.permission.READ_EXTERNAL_STORAGE,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE),
PERMISSION_REQUEST_CODE)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
if (requestCode == PERMISSION_REQUEST_CODE) {
if(grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, getString(R.string.permissiongranted), Toast.LENGTH_SHORT).show();
finish()
} else {
Toast.makeText(this, getString(R.string.permissiondenied), Toast.LENGTH_SHORT).show();
}
}
}
}
Thanks to everyone for helping me discover more about Android Permissions.
I decided to change the way i ask for the permission. Instead of an Activity, i decided to use a Fragment instead ("show an educational UI to the user. In this UI, describe why the feature, which the user wants to enable, needs a particular permission." - source | Thanks to #Michael in the comments for pointing it out).
Since now im using a Fragment, i have to use requestPermissions (Thanks to this reply). This now works flawlessly without any issues.
Turns out you need a combination of checks when trying to request a permission. You have to first check if the permission is actually enabled with checkSelfPermission, so you can easily choose where the user should go to start using the app.
I want onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) method in fragment
I found google and anwser fragment
(mainActivity)getActivity.onrequestPermissionResult
but I don't know this parametor
Do you have any other way or know this parameter? All I know is requestCode
viewmodel
private val _permissionVisibility = MutableLiveData<Boolean>(ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS) != PERMISSION_GRANTED)
val permissionVisibility: LiveData<Boolean>
get() = _permissionVisibility
xml binding
android:visibility="#{homeViewModel.permissionVisibility ? View.VISIBLE : View.GONE}"
mainActivity
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
Timber.d("Test ${requestCode} , ${permissions} , $grantResults ")
}
You can use new Activity Result APIs to get the result of permission and activityresult in much simplier way.
The Activity Results API provides two methods — RequestPermission and RequestMultiplePermissions . These two does exactly what their names are. Here’s a quick example code.
// Requesting Location Permission
bi.btnRequestPermission.setOnClickListener {
askLocationPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
}
// Single Permission Contract
private val askLocationPermission = registerForActivityResult(ActivityResultContracts.RequestPermission()) { result ->
if(result){
Log.e("TAG", "Location permnission granted")
}else{
Log.e("TAG", "Location permnission denied")
}
}
// -------------------------------------------------------------------
// Requesting Mutliple Permissions - Location & Bluetooth
bi.btnRequestPermission.setOnClickListener {
askMultiplePermissions(arrayOf(
android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.BLUETOOTH
))
}
you have to add the following dependencies in your app’s build.gradle file.
implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha04'
Check the blog for reference- https://wajahatkarim.com/2020/05/activity-results-api-onactivityresult/
I need to use the camera on one of my pages, but it won't work (NotAllowedError: Permission denied), and I tried to authorise the camera on my app via my device but it's still not wot working
I also added the authorisations on my Manifest:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.any" android:required="false" />
But I think it's because I use jasonnette that the app use the authorisation of the navigator I display rather than the authorisations of the app itself
You have to ask for the runtime permissions I did it this way in a project some time ago:
First:
ActivityCompat.requestPermissions(activity!!,
arrayOf(android.Manifest.permission.CAMERA),
PERMISSIONS_REQUEST_CAMERA)
Then:
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
PERMISSIONS_REQUEST_CAMERA -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//do your stuff
}
return
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
I hope this helps!