I am working with Android API 25 and need to make permissions requests in the app.
There are a ton of code samples on how to make a request as well as how to show the rationale. This link here shows a simple methodology as do these: Android M Request Multiple permission at a single time , Android M request permission non activity
The problem I am having is I am requesting multiple permissions at once (Location, Write storage access, and Contacts) and the ActivityCompatApi23.shouldShowRequestPermissionRationale source code only takes in a String for a single permission and not an array for multiple permissions. (source: android.support.v4.app.ActivityCompat)
So in my code, I can do this:
ActivityCompat.requestPermissions(activity, permissionsStringArray, 123);
And try to request multiple at once, but I can't then show the explanation for the ones needed if they return true from:
ActivityCompat.shouldShowRequestPermissionRationale(activity,
currentPerm.getPermissionManifestName()
Does anyone have any recommendations on how I can show a dialog that includes multiple rationales in it as opposed to one at a time?
I recommend this open source.
https://github.com/ParkSangGwon/TedPermission
You can use simply. for example
private void CheckPermission() {
new TedPermission(this)
.setPermissionListener(permissionlistener)
.setDeniedMessage(getString(R.string.str_permission1))
.setPermissions(Manifest.permission.CAMERA, android.Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)
.check();
}
Related
we're developping an app that will run as a service. One of the feature would be to download file at given URL (ex PDF) and save it into the download folder so user can load it from a specific application (Avenza Maps).
All the download process should be without any user interaction since it's by a service that run in the background.
i've added the following permission:
AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
<application
android:requestLegacyExternalStorage="true"
whatever i'll try i got the following error
java.io.FileNotFoundException: /storage/emulated/0/Download/name.pdf (Permission denied)
how can i get the permission to write on Download folder (this is system Download folder)
without having to open an activity to save the file?
i'll try multiple solution yet(2 day of google) without success
for now as stated we target API 28 (android 9)
we will later target other API since we provide the device to the client so we develop only for the API our device have.
I've recently had to develop an app that downloads voice files to a device. While you can specify permissions in the Android manifest, you must request permissions from the user. I've done so in Java, but a conversion to Kotlin should be simple.
//method is called to check the storage permissions for this app
//ensures the app can write and read files
private void checkStoragePermissions() {
Log.i("Permissions", "Checking Storage Permissions");
int writePermissionCode = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);//get current write permission
int readPermissionCode = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);//ge current read permission
Log.i("Permissions", "Fetching Read & Write Codes: " + readPermissionCode + "/" + writePermissionCode);
//if permissions to read and write to external storage is not granted
if (writePermissionCode != PackageManager.PERMISSION_GRANTED || readPermissionCode != PackageManager.PERMISSION_GRANTED) {
//request read and write permissions
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PackageManager.PERMISSION_GRANTED);
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PackageManager.PERMISSION_GRANTED);
Log.i("Permissions", "Asking For Storage Permissions");
} else {//else: if permissions to read and write is already granted
permissionsGranted = true;//set permissions granted bool to true
}
}
After you've done this the downloading of the files can be done in many ways. It's worth noting that files can't be downloaded to any location on an Android device. Only a specific destinations can be used.
I hope this helps to clear some of your confusion. Happy coding!
how can i get the permission to write on Download folder (this is system Download folder) without having to open an activity to save the file?
The simplest solution is to write somewhere else, where you do not need permissions. The methods on Context that return File objects, like getFilesDir() and getExternalFilesDir(), are your primary candidates.
Beyond that, it appears that your app is pre-installed on some device ("we provide the device to the client"). If you have developed a custom firmware image, you should be able to pre-grant the permission to your app as part of that image. Or, if the device is being distributed already configured (no first-time-power-on onboarding UI), you could manually grant WRITE_EXTERNAL_STORAGE to your app or have a UI automation script do it.
If none of those are options, then you have no choice but to ask the user for permission.
I am working on a files app and after targeting to API-30, I need permissions for not just media store permission (WRITE_EXTERNAL_STORAGE), but also need to be an external storage manager (MANAGE_EXTERNAL_STORAGE). In order to do so, I have to show 2 different system dialogs to the customer. The first one is the media store permissions dialog:
/* Code to show this permission */
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.MANAGE_EXTERNAL_STORAGE},
1);
And then I have to show the following one to get external storage manager permissions:
/* Code to show this permission */
final Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
final Uri uri = Uri.fromParts("package", activity.getApplicationContext().getPackageName(), null);
intent.setData(uri);
activity.startActivity(intent);
Is there something in the android system that shows user a dialog that bundles all the storage permissions together, or any android system flow that can be launched that guides user throughout both permission together? Having two different flows seems like a terrible amount of redundant logic that needs to be owned by apps. I was not able to find something like that, so asking here if I missed anything.
Is there something in the android system that shows user a dialog that bundles all the storage permissions together
Not in terms of MANAGE_EXTERNAL_STORAGE, as that is not a runtime permission that you handle via requestPermissions(). READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE can be requested together using requestPermissions().
or any android system flow that can be launched that guides user throughout both permission together?
No, sorry.
Note that I have not tried holding MANAGE_EXTERNAL_STORAGE without WRITE_EXTERNAL_STORAGE. Perhaps WRITE_EXTERNAL_STORAGE is not needed if you hold MANAGE_EXTERNAL_STORAGE. The documentation suggests that this might be the case.
Having two different flows seems like a terrible amount of redundant logic that needs to be owned by apps
Very few apps should be asking the user to grant MANAGE_EXTERNAL_STORAGE. And apparently Google really wants users to think through whether they should be granting that permission to your app.
I want to write a simple app which accesses the device's location. Only I will ever use the app. This is my first attempt in about 10 years to write an Android app, so it is the first time I've had to deal with runtime permissions.
My first question is, given that the app is solely for my use, is it possible to by-pass the need for runtime permission code?
Failing that, is there any simple example code that fills in the numerous gaps in the Android documentation?
To take one example: the doc includes the following:
when {
ContextCompat.checkSelfPermission(
CONTEXT,
Manifest.permission.REQUESTED_PERMISSION
) == PackageManager.PERMISSION_GRANTED -> {
// You can use the API that requires the permission.
performAction(...)
What does this mean? What "API that requires the permission"? What replaces the "..."?
There are several other similar gaps on the page.
You have mentioned that app is solely for your use then you don't have to write the code for the runtime permission you can skip it...
How to do this... ?
Step 1 : Just put all the permission you need inside the app manifest file and install the app
Step 2 : Go to the app settings or app info in the phone and check for app permissions all the permission that you mentioned will be displayed there just toogle them manually
That's it now write code to access the things which you supposed to write after getting permission
If you want to avoid run time permission request you can build your app with Android SDK version below 23 (Android 6 Marshmellow)
For Android API Level 23 or above (after adding permission in your manifest file):
First, add your permission to AndroidManifest.xml file:
<uses-permission android:name="android.permission.THE_PERMISSION" />
Then in your Activity:
Check Permission:
fun checkPermission(permission: String): Boolean {
return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
}
Get Permission:
fun getPermission(permission: String) {
ActivityCompat.requestPermissions(this, arrayOf(permission), REQ_CODE_PERMISSION)
}
Get Permission Result:
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
if (requestCode == REQ_CODE_PERMISSION && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
...
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
If you are using Fragments:
A fragment contains a method for requesting permission and getting the result back to its onRequestPermissionsResult:
fun getPermission(permission: String) {
requestPermissions(arrayOf(permission), REQ_CODE_PERMISSION)
}
REQ_CODE_PERMISSION: is some random number like 123 you use to identify your request with.
is it possible to by-pass the need for runtime permission code?
You still need the <uses-permission> element. But you could manually grant the permission to your app via the Settings app.
The point of runtime permission code is to request the permission from the user and defend against cases where that permission has not been granted. In your case, if your app crashes because you revoked the permission, you can yell the developer. You, as the developer, in turn, can yell at you, as the user, for failing to manually grant the permission. Since you will be yelling at yourself, it is recommended to do this in a private location, or perhaps have a Bluetooth headset in your ear as cover. :-)
What does this mean?
We request runtime permissions because we want to use some Android API that is defended by such a permission. We usually do not request runtime permissions because we woke up one morning and decided that requesting runtime permissions sounds like a really fun thing to do.
What "API that requires the permission"? What replaces the "..."?
In your case, it would appear to be either methods on LocationManager or stuff using the fused location API from Google Play Services.
is there any simple example code that fills in the numerous gaps in the Android documentation?
The problem is that "example code" is 5% permission-related and 95% whatever it is that you are using that requires the permission. Any sample code that only shows permissions is going to have the same hand-wavy stuff that you don't like from the documentation. In your case, any up-to-date examples of using location APIs should also show the runtime permission elements.
FWIW, this directory contains several sample projects from this book that show getting the location. They are a bit old but do show requesting runtime permissions (mostly contained in an AbstractPermissionActivity). This sample is newer and in Kotlin, but it is for file-access permissions, not for locations (and is covered in this other book).
Is there a way to choose which order the user is prompted for permissions in Android Marshmellow's new permissions dialog?
When the user launches the camera in my app, I'm prompting for:
Manifest.permission.CAMERA
Manifest.permission.WRITE_EXTERNAL_STORAGE
Manifest.permission.RECORD_AUDIO
Because it makes the most sense (e.g. open camera, app requests camera permissions), I want the permissions to be requested in that order as well. But they aren't requested in that way - the Permissions dialog seems to just ignore the order I have in the String array.
Code below, using the EasyPermissions library, but the same thing happens without the EasyPermissions library.
ArrayList<String> permissionsToRequest = new ArrayList<String>();
permissionsToRequest.add(Manifest.permission.CAMERA);
permissionsToRequest.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
permissionsToRequest.add(Manifest.permission.RECORD_AUDIO);
EasyPermissions.requestPermissions(
this,
"To take pictures & record video, we need access to your device's camera & storage. Allow?",
R.string.acceptPermission, R.string.declinePermission,
RequestConstants.REQUEST_CAMERA_PERMISSIONS,
permissionsToRequest.toArray(new String[0])
);
Regardless of how I order the permissions in permissionsToRequest, the user is prompted in the same order (Audio, Storage, Camera), which in my opinion is the least intuitive order. Any way to fix this?
Although there isn't a clear way to define the order of permission, I found that it is somehow related to the order defined in the AndroidManifest.xml and in the array passed in Activity.requestPermissions(String[] permissions, String requestCode)
In a device, the order of the permission array was the order it showed in the screen. In a different device, the order defined in the manifest prevailed.
Hope this helps.
I am trying to implement the Google's Fingerprint API in my app (in my Fragment specifically). Google has given an example but it's implemented inside an Activity here.
My specific question is that the code below to check if there are enrolled fingerprints already, it is giving me an error (screenshot below):
Question --> What change do I need to do to make it work in my Fragment (as opposed to an activity like Google has)?
if (!mFingerprintManager.hasEnrolledFingerprints()) {
purchaseButton.setEnabled(false);
// This happens when no fingerprints are registered.
Toast.makeText(getActivity(),
"Go to 'Settings -> Security -> Fingerprint' and register at least one fingerprint",
Toast.LENGTH_LONG).show();
return;
}
Android 6.0 must 'ask' for permission at run time. https://developer.android.com/training/permissions/requesting.html
Dangerous permissions can give the app access to the user's
confidential data. If your app lists a normal permission in its
manifest, the system grants the permission automatically. If you list
a dangerous permission, the user has to explicitly give approval to
your app.
Even if you have <uses-permission android:name="android.permission.USE_FINGERPRINT"/> in your manifest, My understanding is that you must ask for the permission. So it looks like the error is because your app doesn't have -run time- permission to use the fingerprint manager.
(only like 90% sure of this, since I'm sticking with 5.0 for now, sorry)
Update: http://developer.android.com/reference/android/Manifest.permission.html#USE_FINGERPRINT
public static final String USE_FINGERPRINT ---------- Added in API level 23
Allows an app to use fingerprint hardware.
Protection level: normal
So it appears you shouldn't need this permission at run time.
1) Do you have the permission in your manifest?
2) You should put the following code in yours to check to see if permission is revoked/not given for some reason.
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.USE_FINGERPRINT) // this might need massaged to 'android.permission.USE_FINGERPRINT'
!= PackageManager.PERMISSION_GRANTED) {
Log.d ("TEST", "You don't have permission");
}
(or something close to this) like the example from https://developer.android.com/training/permissions/requesting.html