I want to know if my app's camera permission is granted or not. Then I written the below functions, but they are always return incorrect result. Not matter how can I disabled the camera permission of my app in system settings, the both functions always return TRUE. Do you know something wrong in my codes?
public static boolean checkCameraPermission() {
String permission = "android.permission.CAMERA";
int res = App.getInstance().checkCallingOrSelfPermission(permission);
return (res == PackageManager.PERMISSION_GRANTED);
}
public static boolean checkCameraPermission(Context context) {
PackageManager pm = context.getPackageManager();
boolean permission = (PackageManager.PERMISSION_GRANTED ==
pm.checkPermission("android.permission.CAMERA", pm.getNameForUid(Binder.getCallingUid())));
return permission;
}
I want to know if my app's camera permission is granted or not
If your targetSdkVersion is 23 or higher, and you are running on an Android 6.0+ device, use checkSelfPermission(). The native implementation of checkSelfPermission() is on Context; ContextCompat has a version that will not crash on older Android devices.
If your targetSdkVersion is 22 or lower, or you are running on an Android 5.1 or older device, you always have your requested permissions (exception: possibly some custom ROMs).
If your targetSdkVersion is 22 or lower, and you are running on an Android 6.0 or higher device, you also always have your requested permissions, in terms of the methods that you are calling as outlined in your question. The user, in Settings, can block your access to data associated with those permissions, but technically the user is not actually revoking the permissions themselves (though we often say they are just to keep the explanation simple). I know of no way for you to determine that the user is blocking your camera access, other than by catching the relevant exceptions when you attempt to access the camera. Note that those exceptions will be raised in other scenarios (e.g., camera access is blocked by device policy).
Related
I'm trying to get a list of apps (on Android 8.0+) that have REQUEST_INSTALL_PACKAGES permissions marked as granted.
context.packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS or PackageManager.GET_META_DATA).forEach { pi ->
if (pi.requestedPermissions != null) {
for (i in pi.requestedPermissions.indices) {
if (pi.requestedPermissions[i] == android.Manifest.permission.REQUEST_INSTALL_PACKAGES) {
if ((pi.requestedPermissionsFlags[i] and PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) {
// permission is granted, do stuff here
}
}
}
}
}
The problem is, that corresponding requestedPermissionsFlags entry is always 1, which means REQUESTED_PERMISSION_REQUIRED and that is obviously wrong.
I tried different api: context.packageManager.checkPermission(android.Manifest.permission.REQUEST_INSTALL_PACKAGES, pi.packageName) == PackageManager.PERMISSION_GRANTED with the same result.
In tried this on Android 8, 9 and 10 on different devices and the only success I had was on Pixel 3a that came positive for com.android.nfc. Others were always false even when I can see in system settings that chrome and other apps have this permission granted.
Am I missing something for this API? Is it private? There is not much to find about it.
Because this permmission has a signature protection level. According to documentation:
A permission that the system grants only if the requesting application is signed with the same certificate as the application that declared the permission
So requestedPermissionsFlags is correct - only com.android.nfc is granted.
Actually REQUEST_INSTALL_PACKAGES has a signature|appop protection level, that's why not only system apps can use it although this perrmission is not granted for them. For a little bit more details - Acquiring Android Permission with Signature Protection Level.
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.
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.
API 23 has renamed permission protection level system into privileged. It has also introduced a preinstalled protection level.
Does privileged implies preinstalled? In other words, if an application has access to privileged permissions (i.e. it is a system application), does it have access to preinstalled permissions as well, even if those permissions are not listed as privileged (only preinstalled)?
It's possible for apps to be pre-installed but not have elevated system permissions (e.g. Calculator). This is why the distinction is present between these two flags and why system protection level has been deprecated for privileged.
The answer seems to be yes, as long as a privileged app is part of the system image (i.e. pre-installed). The package manager will grant a preinstalled permission to what it (internally) calls a system app, see grantSignaturePermission():
if (!allowed && (bp.protectionLevel
& PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0
&& isSystemApp(pkg)) {
// Any pre-installed system app is allowed to get this permission.
allowed = true;
}
Internally, a system app is actually a pre-installed app (refactoring is limited to the public API, not in the source), see ActivityInfo:
/**
* Value for {#link #flags}: if set, this application is installed in the
* device's system image.
*/
public static final int FLAG_SYSTEM = 1<<0;
// Many lines not shown
public boolean isSystemApp() {
return (flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
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