In a widget I display images from SDCard using remoteView.setImageViewUri(). This strategy works correctly except with MarshMallow:
The error is:
Unable to open content: file:///storage/emulated/0/Android/data/applicaitonPackage/files/file.png
open failed: EACCESS (Permission denied)
It's clear that this is a permission problem, but I don't know how to give permissions to the widget container and in theory (see Note 1) the images are already stored in shared storage.
Note 1: The directory where images are stored is shared storage under Environment.getExternalStorageDirectory()
Note 2: Application is not adapted to MarshMallow and uses targetSdkVersion=15
Note 3: Don't just reply explaining about new runtime permissions in MarshMallow. I already know permissions changes and that is not the problem because application is targeted SDKVersion 15 and the app hasn't any problem accessing the external storage, the problem is with the widget container that is the one that I suspect that doesn't has the permissions.
#Docs says
Requesting Permissions at Run Time
Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app.
This approach streamlines the app install process, since the user does not need to grant permissions when they install or update the app. It also gives the user more control over the app's functionality;
Therefore this make sense although you declare permission in manifest but still getting permission denied
I suggest you to read how to get runtime permission
http://developer.android.com/training/permissions/requesting.html
Here is the example provided by Docs
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an expanation 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(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
// MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
Change permission as per you requirement
Hope it leads you to right direction
Did you have this permisstion in your Manifest file?
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
If I set the targetSdkVersion to 15 instead of 23 - will the android M users see the app and be able to download it (granting all permissions at runtime)?
Yes, the app will be available to M users and every permission is granted at install time.
`targetSdkVersion=15`
which is less than 23.User will able to download the app and use it it grants all the permission at run time. If you want to check the permission go to settings and grant the permission. If you want to use the android M permission module at run time you have to set the target SDK version to 23.
If set the targetSdkVersion=15 on android M and higher devices app getting crashed.
If you want to support android M users set targetSdkVersion=23and
handle permission runtime.
Related
I've set my app to target AP 29 and removed requestLegacyExternalStorage=true from manifest.
Now I'm checking if the user has this permission and if result is denied I request for permission.
My problem is that the request for permission is returning Granted without showing the prompt... I know the flow is working since I'm able to read the GPS location from picture after being granted.
I see permission status = Denied and as soon as I explicitly request this permission, it returns Granted without any user interaction.
Eveything looks OK but I'm confused about not seeing the prompt... is this expected? I saw this permission qualifies as "Dangerous" so I was expecting a prompt. I'm testing on a Android 10 device.
I'm not showing any code since the project is Xamarin and the permission logic is handled through a third party library, don't think my code will help as the platform logic to request the permission is hidden by the component.
From
Android 10: fetch the gallery via MediaStore with location information :
This requires holding the ACCESS_MEDIA_LOCATION permission. Note, this permission is not "user visible in the settings UI" (source), which means the user won't see a popup asking for permission, even though it is a runtime permission. This means you have to ask for permission during runtime (in contrast to just the manifest file) but the user won't have to consent to it. Adding this here because you might be wondering why no extra UI popups are shown.
I'm still getting my head around the logic though. I'm in favour of the user being asked for permission but I don't understand why it should be necessary to "request" it if the user doesn't actually grant permission.
I was able to reproduce the issue in a simpler app. I have posted a slightly different question with code snippets.
This is an answer by HilaryN that I believe should not have been deleted (I removed the off-topic bits).
I have an Android app that requires permission to read/write from/to external storage. When the app starts, it prompts the user to allow permission for external storage (and a bunch of other services - location, camera, etc).
Here's how we do it:
ActivityCompat.requestPermissions(this, new String[]{WRITE_EXTERNAL_STORAGE, CAMERA,ACCESS_FINE_LOCATION,INTERNET,WRITE_SETTINGS,ACCESS_WIFI_STATE,READ_PHONE_STATE}, PERMISSION_REQUEST_CODE)
Now, there is also an authentication service for which we need to read from external storage. We call this authentication service during startup.
Now, problem is: When you run the app for the 1st time after install, this call to authentication service may happen often before the permission to external storage is given. Because the authentication service has no permission to external storage, it fails authentication.
Workaround we do now: manually enable permission after install and then run the app. Not a long term solution though.
I did some reading and it seems in older API's we can force the permissions to be done during apk install itself. I am on API 29. Is it possible here to prompt the user to give permissions during install itself?
I also understand that this is considered a critical service and we can't bypass permissions. Rather we cannot force permissions to be default.
What I've done for now:
Initialized the authentication service later in the code so it runs only after permissions are done.
Is there a better solution available? Like some way to either force permissions for external storage by default or some other way? From what I have read, it doesnt look possible for the latest Android version. However, if there is a way to do this, pls let me know.
Thanks,
Anand
In order to know if the user has allowed or not the application with your requested permissions, you should override onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray).
This way, you can do something like this :
if (requestCode == PERMISSION_REQUEST_CODE) {
for (elem in grantResults) {
if (elem != PackageManager.PERMISSION_GRANTED)
// Abort your feature here
}
// Do your feature here
}
If every permission has been passed you can then do what you want.
The Android Developer Documentation has a nice tutorial, more complete than I've done above, but you get the idea.
Not possible to force permission at installation time, you would need to target API level < 23 but now you need to use 28/29 to create/update apps on PlayStore. You could consider to use an alternative storage location like getCacheDir() moving files where you need later when your app has permission or just getExternalFilesDir() path where you can read/write without additional permissions.
Is it possible here to prompt the user to give permissions during install itself?
From official doc:
If the device is running Android 6.0 (API level 23) or higher, and the app's targetSdkVersion is 23 or higher, the user isn't notified of any app permissions at install time.
Also:
If the device is running Android 5.1.1 (API level 22) or lower, or the app's targetSdkVersion is 22 or lower while running on any version of Android, the system automatically asks the user to grant all dangerous permissions for your app at install-time (see figure 2).
In any case pay attention to this point:
Beginning with Android 6.0 (API level 23), users can revoke permissions from any app at any time, even if the app targets a lower API level.
In other word it means that today you have to check for and request permissions in your code.
Initialized the authentication service later in the code so it runs only after permissions are done.
You can use the ContextCompat.checkSelfPermission also in a Service.
When you start the service you can check if the permission is granted and avoid to fail.
You can use ActivityCompat.requestPermissions only in an Activity, but you can use the callback onRequestPermissionsResult to start your service.
Is there a better solution available?
You can't force the permission but for example your Service can check for permissions it needs and if it hasn't been granted yet, you can create a friendly notification to inform user.
Critical permissions like read/write external storage, camera, SMS, contacts, and a few others cannot be forcefully asked for prior to installation. So, they've to be asked for at runtime. The best practice is to ask for them just when they're actually needed instead of asking for them all at a time in the beginning.
If your service uses one of those permissions, you've to check for that permission every time before starting the service and then start the service only if the permission is granted. Otherwise, ask for permission, override onActivityResult and then start service only if the permission is granted.
Also, keep in mind to handle the scenario when the user marks the checkbox "Don't ask again" and denies permission. In that case, the user won't see the prompt again. So, you'll have to open permission settings using intent.
From app I gave the required permission for my app. While my app is running, I went to system settings page and revoked the permission. The app is crashing. Will we be able to handle this?.
Android 6.0 (Marshmallow, API 23) switched from an install-time permission model to a runtime permission model. Now instead of the user granting all permissions at runtime, you the developer are responsible for requesting permissions at runtime and responding appropriately.
You should begin by reading the Requesting Permissions at Run Time documentation. So that you can properly request permissions on devices running Marshmallow.
To prevent your app from crashing, you need to call ContextCompat.checkSelfPermission() to see if you have a permission before attempting to call a method that requires a permission. However, this is only half the equation since you still need to request the permission if you don't already have it.
Android M not showing normal permission like Internet, WIFI in the permission list. Its just saying No special permission to display. Is that how Android M will display permission, it will never show permission prior to install. Can any one experienced this before.
attached screenshot,please check it.
Please help me to finding this answer.
Thanks.
Quoting the documentation:
When the user installs or updates the app, the system grants the app all permissions listed in the manifest that fall under PROTECTION_NORMAL. For example, alarm clock and internet permissions fall under PROTECTION_NORMAL, so they are automatically granted at install time. For more information about how normal permissions are handled, see Normal Permissions.
The system may also grant the app signature permissions, as described in System components and signature permissions. The user is not prompted to grant any permissions at install time.
(emphasis added)
Will the Android permissions WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE trigger the new grant permission dialog of Android M?
I agree with Guillaume Perrot 's answer. I have met the similar question when I write the permission of READ_WRITE_EXTERNAL_STORAGE in AndroidManifest.xml
with no permissions showing up in the app by default , people need to switch the toggle button of storage in the app permissions.Then I modify my targetSdkVersion in build.gradle to less than 23(MNC) and other number related with sdkVersion, the app installed with the permissions on.
The other way is to write requestpermission function in the place that you need the permisson. The code is as follow:
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)==
PackageManager.PERMISSION_GRANTED) {
//do the things} else {
requestPermissions(new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE },
AnyNumber);
Because I have less than 15 reputation so I can't vote for the Guillaume Perrot 's answer.Just use this way to show my idea.
I solved add this if check version for Android M
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
requestPermissions(new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
}
My answer is based on my tests on M Preview SDK version 2, using an emulator.
If you target MNC preview API level, WRITE_EXTERNAL_STORAGE is not granted by default and will be part of the new dynamic permission API.
You will see the storage permission as a toggle button in the new app permissions menu in device settings, and you can use Activity.requestPermissions to show the popup for that permission.
However if you target api level < MNC, it won't be classified as a dangerous permission, and thus will be granted without a way for the user to disable it (not showing up in permission settings), and you will not be able to compile code using Activity.requestPermissions anyway as the preview SDK enforces minSdkVersion="MNC" to use the new APIs.
This is a different behavior than location permissions: whatever the API level you target, the user will be able to turn location off in permission menu.
For the permission menu itself, the permission toggle state is ON by default if:
Target API level < MNC.
Target API level = MNC but you upgrade app on device from a previous install where target API level was less than MNC.
Otherwise you will see the toggle as OFF by default.
Hope it helps.
According to the docs:
Limited Permissions Granted at Install Time: When the user installs or updates the app, the system grants the app all permissions that the app requests that fall under PROTECTION_NORMAL.
So because READ_EXTERNAL_STORAGE is falling under PROTECTION_NORMAL , it won't trigger the dialog.
But because the level of WRITE_EXTERNAL_STORAGE is PROTECTION_DANGEROUS, it will fall under this behavior as described in docs:
User Grants Permissions at Run-Time: When the app requests a permission, the system shows a dialog to the user, then calls the app's callback function to notify it whether the permission was granted. If a user grants a permission, the app is given all permissions in that permission's functional area that were declared in the app manifest
Here is the sources for the protection level:
detailed list
According to Android docs you don't need to request permission about read and write external storage.
Edit: in the latest Android M release you need to ask for both read and write permissions
Storage permission falls under dangerous protection level, So all the dangerous protection level permissions will not be granted at install time in Android M, if App target SDK is set to 23. They will be given at run time.
And yes these permissions can be revoked at run time also.
No permission dialog will not be triggered automatically, you need to do a request by using API such as requestPermissions() method to show that native dialog.
Please check the dangerous level permission list here