I'm building a Cardboard app and testing it on a Nexus 6P.
The problem I have is that when I install the app, it doesn't ask for any permissions.
In my manifest I have this:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Then if I want to download some file from the internet in my app, it doesn't work. It doesn't even create the com. folder.
I have to go manually to the app info and check the storage permission.
It's weird because when building the app for GearVR and testing it on a Note 4, it asks for permission (in the Note 4 I use the sd card, in Nexus 6P the internal)
Why is this happening?
Thank you.
For Android 6+ you need to request permissions at runtime, not startup. This is especially the case if you are considering your app for Google Play featuring,
In short, you need to specify the permission in tour manifest, and also include the following in your application tag
<meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true" />
Then, request the permission(s) at runtime via Android.
There is a great little plugin for this at https://www.assetstore.unity3d.com/#!/content/62735
Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app. Thats a reason why you didn't have request dialog.
If you need to request permission you need to show request rationale and handle user iteration result.
From docs :
Request permission :
if (ContextCompat.checkSelfPermission(thisActivity,Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
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_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
Handle User Choosed Option
In ActivityCompat :
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
// 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.
}
return;
}
// other 'case' lines to check for other
// permissions this app might request
}
}
Starting with Android 6.0 (Marshmallow) apps no longer get all permissions on install like they used to. You now have to request the permissions at runtime (which the user can decline) and have to be able to handle the permission getting revoked any time after it has been granted.
If you want to use the old behavior for now, I believe you should be able to set your target API level to 22.
Read more here: http://developer.android.com/training/permissions/requesting.html
for a quick fix, you can target android 5 (api level 22 instead of 23) and the permissions will keep using the old behavior.
note, if you publish an app targeting android 6 (level 23) api, you can't deprecate the target api level in an update.
https://developer.android.com/training/permissions/requesting.html
Related
I'd like to grant android.permission.READ_PRIVILEGED_PHONE_STATE permission to my app, but even though it's a system app (in system-priv folder on a rooted device for tests) it's not granted.
ADB shows request for this permission, but it's not granted.
In the Manifest I have
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" tools:ignore="ProtectedPermissions" />
When I try to check it in the runtime
if (ActivityCompat.checkSelfPermission(context.getApplicationContext(), Manifest.permission.READ_PRIVILEGED_PHONE_STATE) == PackageManager.PERMISSION_GRANTED)
the AS gives "Cannot resolve symbol 'READ_PRIVILEGED_PHONE_STATE'" and the app won't compile.
Why READ_PRIVILEGED_PHONE_STATE is visible in the Manifest, but not visible in the java code (also missing in Manifest.class) ?
How can I grant this permission?
I tested it on rooted Android Oreo.
Edit: This answers a part of my question: Permission is not a changeable permission type
The permission was granted on Lollipop, but not on Oreo.
But the question remains: Why READ_PRIVILEGED_PHONE_STATE is visible in the Manifest, but not visible in the java code (also missing in Manifest.class) ?
What I think might be happening is that Drobinsky did not call:
String[] permissions = {"android.permission.READ_PHONE_STATE"};
int requestCode = 5;
ActivityCompat.requestPermissions(this,permissions, requestCode);
prior to calling "ActivityCompat.checkSelfPermission(…"
In the activity you can also add a permissions notififcation handler which looks like this:
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case 5: //REQUEST_READ_PHONE_STATE:
if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
// Do what you want to do with the granted permission
Even though you've got the permission added in the manifest, the user must also grant this permission at runtime. What happens is that a popup will occur asking the user to grant this permission, and if the user grants it, the "checkSelfPermission" method will then work correctly. The popup block is automatic; i.e. no code needs to be added to the app. I think you can add a text message that displays the reason the permission is required. Certain permission requests need to be handled in this manner, whereas some permission requests are granted without user intervention required. I think the Android model is that if a request is deemed "dangerous" it requires the user give their permission to grant the app access to these so called dangerous privileges.
I'd like to know why my permission are not asked when I'm launching my app, here's my manifest permissions :
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
And when I go through the param of my phone, I only have the "position" permission (and it's disabled).
If by permission not asked you mean that the user isn't being prompted to allow internet permission then that is normal. Internet is in the normal permissions list so it is auto granted. For more information about normal permissions take a look at: https://developer.android.com/guide/topics/permissions/normal-permissions.html
Also, adding permissions is a two step process; once you have declared the permission you need in your manifest, you will also have to do some setup in your java file. Take a look at https://developer.android.com/training/permissions/requesting
Additionally, if you are looking for easier ways to deal with permissions then there are libraries out there for that too such as RxPermissions: https://github.com/tbruyelle/RxPermissions
Hopefully this helps!
You should ask for a Runtime Permission
Please see the documentation:
Request App Permissions
If you are targeting SDK 26+, then you need to check for permissions in code like this:
if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.ACCESS_FINE_LOCATION)) {
// 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(thisActivity,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
MY_PERMISSIONS_ACCESS_FINE_LOCATION)
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
} else {
// Permission has already been granted - or running on old Android
}
It is described in Request App Permissions
for marshmallow(API 23) and above you should get permission for location, phone states and other dangerous permissions not only in your manifest but in your code (Run Time Permission).for other permissions, manifest is enough.
see this video
also you can find your solution in this Q&A
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.
So this whole new android runtime permissions has gotten me confused. My app is currently compiling and targetting version 23 which means I have to use runtime permissions. My app primarily uses the camera api which needs the camera permission so I added the runtime permissions before opening the camera as such:
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED)
{//ask permissions for camera
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA},
CameraPermissions);
}
else
{//permissions attained now you can open the camera
camera=Camera.open(getCid());
camera.setPreviewCallback(this);
initPreview(width, height);
startPreview();
startTimer();
}
I also check when I stop the camera:
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED) {
camera.setPreviewCallback(null);
camera.release();
faceProc.release();
faceProc = null;
camera = null;
inPreview = false;
cameraConfigured = false;
}
The permission request is handled as such:
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case CameraPermissions: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
StartUpCam();
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("How is this app going to work if you rejected the camera permission.... DUHHHH!!")
.setTitle("Rejected");
builder.setPositiveButton("Exit App", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
//close application
closeApp();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
return;
}
}
}
So when the request is given it calls the StartUpCam which then tries to open the camera if the permissions is given. So here comes my questions, if I add this runtime permission checks how does this affect android devices lower than 6.0?? So a phone with version 5.0.1 will also get a prompt to give camera permissions? If I use runtime permissions, do I have to remove the camera permissions in the manifest file? Currently, I keep the camera permissions in the manifest along with the runtime permissions I don't know if that is correct or not. What if I lower the target and compiling sdk to 22 instead of 23, will android devices above 6.0 won't be able to download my app??? If I lower it to version 22 then I avoid all this headache...
I also check when I stop the camera
That is not needed, assuming that you do not try to stop a camera that you never opened. If the user revokes the permission while your app is running, your process is immediately terminated. As a result, you can never lose permissions in a running app. Since you checked for and had permission to open the camera, you already have permission to close it.
if I add this runtime permission checks how does this affect android devices lower than 6.0?
ContextCompat.checkSelfPermission() will return PackageManager.PERMISSION_GRANTED on older devices, assuming that you have the permission listed in the manifest.
So a phone with version 5.0.1 will also get a prompt to give camera permissions?
No.
If I use runtime permissions, do I have to remove the camera permissions in the manifest file?
No. Those elements are necessary on all Android versions.
What if I lower the target and compiling sdk to 22 instead of 23, will android devices above 6.0 won't be able to download my app?
Your compileSdkVersion has no impact on what versions of Android you support. Android 6.0 users will still be able to download your app.
If you lower your targetSdkVersion to 22 or lower, that too has no impact on what versions of Android that you support. Android 6.0 users will still be able to download your app. Doing this would mean that you could skip the runtime permission code. However, bear in mind that you still may not have permission. Users of Android 6.0 devices, running your targetSdkVersion 22 app, will grant the CAMERA permission by default. But, those users can still go into Settings > Apps, find your app, and revoke the permission. With the camera API, you basically cannot open the camera.
Tactically, going with targetSdkVersion of 22 or lower is certainly possible. Eventually, though, something is going to "force your hand" and require you to move to a targetSdkVersion of 23 or higher. So, someday, you will need to deal with the runtime permissions. Whether that is today or some day in the future is up to you do decide.
No if the Permission is in Menifest file. Android having less than 23 sdk won't receive a prompt about the permission, It will be the same like before.
I've noticed I get the following issue when someone tries to access my android application from Android 6 (SDK 23):
java.lang.SecurityException: "gps" location provider requires ACCESS_FINE_LOCATION permission.
Since it will take time to fix this issue, I decided to downgrade my application target SDK to SDK 22.
My questions are:
Is it possible to run "SDK 22 targeted" app in android 6 (SDK 23)?
What are the solutions for the SecurityException above?
*I already has the ACCESS_FINE_LOCATION permission granted in my Manifiest
Firstly, a device should be backward compatible (though this is not a blanket statement) Android 6.0 APIs to run the app with a lower SDK. You need to ensure you have the SDK 22 installed in your ide.
The other is there are extra issues regarding permissions for android 6.
See here:
Requesting Permissions at Run Time
And the example taken from there Check For Permissions:
// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.WRITE_CALENDAR);
And then Request the permissions you need:
// Here, thisActivity is the current activity
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_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
This answer contains a more comprehensive explanation.
https://stackoverflow.com/a/32084038/3956566