I was wondering, how to handle the runtime permission in capsulated objects.
So, let's say we have a loggerobject which needs to write to disk.
The only thing the objects should do is writing to the disk.
Shall this object also handle runtime permissions?
Shall the object be in the beginning unable to write (by a flag) and the flag will swap if we get the permission?
I will be glad to know, how some of you do this.
Thank you!
The permission is granted for the whole app, not for individual objects.
If you get the permission for your app once, you don't need to request it again and again.
In your case you can check and request the necessary permissions before writing to a file or even before the creation of your object.
The best practice is to request the permissions in the context just before using the features which require the permissions.
Check my library for handling permissions easily. Just get a reference of context and you can request permissions from anywhere.
https://github.com/nabinbhandari/Android-Permissions
There is no one clear answer for your question. Your question is related to the software architecture in general. So there might be a lot of different opinions. I will give you mine.
Often times you want a class to have a single responsibility and do only one job. Therefore, a logger only logs messages but it doesn't care a lot about permissions.
So I would say it's often a question about how to design your API and make it easy to work with.
For example, let's say we have an interface for Logger:
interface Logger {
void d(String tag, String message);
}
Then we introduce a concrete implementation called FileLogger:
final class FileLogger implements Logger {
#Override
public void d(String tag, String message) {
// write a message to a file somehow
}
}
The question here is should FileLogger#d fails with SecurityException if the permission has not been granted yet? Or should it just warn a developer somehow?
Personally, in this case I would modify FileLogger to not fail if the permission has not been granted yet, but the permission itself must be granted in another part of the application.
final class FileLogger implements Logger {
#Override
public void d(String tag, String messsage) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
// write a log to a file
}
}
}
Let's take a look at another example. Imagine we have an interface called LocationApi:
interface LocationApi {
#Nullable
Location getLastLocation();
}
A user must grant a permission to the application so it can obtain his last location. Is it a critical to fail immediately if the app doesn't have a permission? I would say yes!
The implementation of this interface would look something like this:
final class LocationApiImpl implements LocationApi {
#Nullable
public Location getLastLocation() {
if (ContextCompat.checkSelfPermission(..) != PackageManager.PERMISSION_GRANTED) {
throw new SecurityException();
}
// obtain a location
}
}
P.S. There is a special annotation RequiresPermission that can help you to indicate that a method requires a permission, otherwise it might throw SecurityException.
Then we can modify LocationApi interface like this:
interface LocationApi {
#RequiresPermission(Manifest.permission.ACCESS_FINE_LOCATION)
#Nullable
Location getLastLocation();
}
Related
I really struggle with this since a while :( as I need an solution that works within UNITY3D.
I need to check if the user has given the permission to access the Android device camera (and location on a second level).
Normally the app start by asking for this permissions at launch, but if the user denies the access for the camera I need to know and check that later.
Otherwise the user could hit the camera UI button I made and try to access the camera via webcamtexture... and that leads into a crash of the app.
Since Android API 23 you cannot ignore or already grant permissions by changing the android manifest like I tried after reading several posts about that.
Thank's to everyone who has an idea to solve this.
Check this library: https://github.com/sanukin39/UniAndroidPermission
In that library I got these methods to check and request Permission.
public static void requestPermission(String permissionStr){
if(!hasPermission(permissionStr)) {
UnityPlayer.currentActivity.requestPermissions(new String[]{permissionStr}, 0);
}
}
public static boolean hasPermission(String permissionStr) {
if(Build.VERSION.SDK_INT < 23) {
return true;
}
Context context = UnityPlayer.currentActivity.getApplicationContext();
return context.checkCallingOrSelfPermission(permissionStr) == PackageManager.PERMISSION_GRANTED;
}
Hope it helps:)
I know that android 6.0 requires runtime permissions. Could you please help me implement runtime permissions for Bluetooth? I tried using the example on https://developer.android.com/training/permissions/requesting.html but was getting a bunch of errors. Thanks.
You can easily create a Permit object to start requesting permission(s) from user.
Firstly initialize the Permit object passing your activity
Permit permit=new Permit(MainActivity.this);
Then attach a listner to this object
permit.setOnPermitStatusListner(new Permit.OnPermitStatusListner()
{
#Override
public void onAllPermitsGranded()
{
// ALL PERMITS ACCEPTED
}
#Override
public void onSomePermitsDenied(ArrayList<String> deniedPermits)
{
// SOME PERMITS ACCEPTED
}
#Override
public void onAllPermitsDenied()
{
// ALL PERMITS DENIED
}
});
Then ask for what all permissions you need to work(Must be declared in the Manifest)
permit.askPermitsFor(Manifest.permission.BLUETOOTH,Manifest.permission.BLUETOOTH_ADMIN,Manifest.permission.<Other BT permissions>);
You need to add this library to work with Permit object. Here is the complete documentation : https://github.com/sangeethnandakumar/TestTube
I've seen SO question Can you request permissions synchronously in Android Marshmallow (API 23)'s runtime permissions model?. The answer is no.
Hence, I added a code as below (simplified version):
public class MyActivity ... {
private boolean hasGotPermissionRequestResult = false;
#Override
public void onCreate(...) {
if (ContextCompat.checkSelfPermission(...) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermission(...);
while (!hasGotPermissionRequestResult) {}
}
}
#Override
public void onRequestPermissionResult(...) {
// whether granted or not
hasGotPermissionRequestResult = true;
}
}
However, I am not sure whether my approach is nice, safe and efficient.
Well, what you trying to achieve simply ain't possible, however there are several ways to overcome this:
Only trigger the method you wanna call when the permission is granted.
If you'd like to make the User only uses your app because that particular permission is so important that your app will not function without it, then use an educated screen to tell the users why you would want to use this permission in an intro screen kinda way.
I've created a library just for this kind of scenario where the library simplify the Permissions for you, it can be also used as a stand Alone Activity that has an Intro to your permission. you could check it out in Github PermissionHelper Github
I'm using Google's EasyPermissions library. In my app I have two buttons, one to record video and one to capture image. Since both require Camera Permissions they are both annotated with #AfterPermissionGranted.
So my method to record video looks like this :
#Override
#AfterPermissionGranted(RC_CAMERA_PERM)
public void openCameraToRecordVideo() {
if (EasyPermissions.hasPermissions(this, Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
// Code here
}
And similarly for taking pictures :
#Override
#AfterPermissionGranted(RC_CAMERA_PERM)
public void openCameraToCaptureImage() {
if (EasyPermissions.hasPermissions(this, Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
// Code here
}
They are both annotated with Permissions since I don't know which one user will click first.
What happens is when user clicks one button and accepts the permissions then both methods run one after the other. Which is obviously not the behavior I want.
I'd really appreciate any help on how to handle this situation.
Thank you.
Remove AfterPermissionGranted from both openCameraX function. Defined a private field lastAction. Write a new function openCamera with a AfterPermissionGranted annotation that check is lastAction is set and if so, call related function. In each openCameraX, check if you have camera permission and if not, update lastAction and start request camera permission.
Actually, what you are doing is asking the same permission two times with different function name so remove either openCameraToCaptureImage() method or openCameraToRecordVideo() method.
I am updating my app to work with the new Android Marshmallow permission framework and it looks like it's enough for the user to grant the ACCESS_FINE_LOCATION permission at runtime for the app to work fine. This is what I do:
public static final String[] runtimePermissions = { permission.ACCESS_FINE_LOCATION };
public static final int LOCATION_PERMISSION_IDENTIFIER = 1;
and further down the class:
public static boolean checkConnectionPermission(final Context context) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
if (context.checkSelfPermission(permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
return true;
}
else {
((Activity) context).requestPermissions(runtimePermissions,
LOCATION_PERMISSION_IDENTIFIER);
return false;
}
}
// since in API levels below M the permission is granted on
// installation,
// it is considered a given that the permission has been granted since
// the
// app is running. So we return true by default
else {
return true;
}
}
I am just concerned that I am overlooking something that could cause trouble in the future (the app is near-production) with Security Exception(s).
I guess my ultimate question is: does granting FINE_LOCATION somehow auto-grant COARSE_LOCATION too?
Sort of already answered here.
If I have ACCESS_FINE_LOCATION already, can I omit ACCESS_COARSE_LOCATION?
Some additional information, you should look at permission group.
https://developer.android.com/preview/features/runtime-permissions.html
They are in the same permission group. If you really want to play safe, just include both in your manifest, and request them on need. It would be transparent to user.
According to this blog post, if you have specified both in the manifest and the user has granted you one, then when you ask for the other it will be automatically granted (since they're both in the same permission group).
That means that if you have been granted COARSE_LOCATION and then ask for FINE_LOCATION you can get it without the user being prompted, but the catch is that you still have to specify both in the manifest.
Apps can actually register for two types of location updates. Fine grained, which uses the Global Positioning System to get the device’s location accurate to within a few meters, vs coarse-grained, which uses the Wifi, Cell towers and other data available to the device to get a rough (accurate to 10s of meters) location of the device.
Choice is yours.