I am totally confused regarding the new permission system in Android 6 (Marshmallow).
I am using two so called 'dangeorus permissions' -
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
And I use these permissions in many places.
I need to access the user accounts for Registering the app, Sending Feedback etc.And I also access Device Id for registering the app.
I wrote two functions to get the list of Mail Accounts and the device id in a Java Class named util, and uses these function in AsyncTask as well as fragments.
Now, I am totally at loss, how to request for those permissions! Should I ask in the functions or every time I call these functions? And in the AsyncTask, how can I get a response?
Please help.
You shouldn't ask for permissions in AsyncTask. In fact you shouldn't even retrieve deviceId or some information in it - pass it as a parameter.
Settings of each application has list of 'dangerous' permissions with their status. If you app targeting sdk 23, they're all disabled by default. So, when you use code which requires such permission, you need to check if it's granted and if not - ask for it.
The simplies way is to create utility class for permissions like this:
public final class PermissionUtils {
private PermissionUtils() {
}
public static boolean checkPermissions(Context context, String... permissions) {
for (String permission : permissions) {
if (!checkPermission(context, permission)) {
return false;
}
}
return true;
}
public static boolean checkPermission(Context context, String permission) {
return ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED;
}
public static boolean isDeviceInfoGranted(Context context) {
return checkPermission(context, Manifest.permission.READ_PHONE_STATE);
}
public static void requestPermissions(Object o, int permissionId, String... permissions) {
if (o instanceof Fragment) {
FragmentCompat.requestPermissions((Fragment) o, permissions, permissionId);
} else if (o instanceof Activity) {
ActivityCompat.requestPermissions((AppCompatActivity) o, permissions, permissionId);
}
}
}
And then use it like this:
(in your Fragment / Activity)
if (PermissionUtils.isDeviceInfoGranted(this)) {
//get deviceId and proccess your code
} else {
String[] permissions = new String[]{READ_PHONE_STATE};
PermissionUtils.requestPermissions(this, PHONE_STATE_PERMISSION_ID, permissions);
}
Override handler for permission result in your AppCompatActivity or implement OnRequestPermissionsResultCallback interface:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case PHONE_STATE_PERMISSION_ID:
boolean granted = grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED;
if (granted) {
//get deviceId and proccess your code
} else {
//nobody knows what to do
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
As you see, we still have a problem - what to do, if user denied permission? As a variant, we can show explaining dialog. Or (may be better) ask for permissions only after onboarding screens.
First of all you must implement the following method in your activity/fragment:
@Override
public void onRequestPermissionsResult(int requestCode,@NonNull String permissions[], @NonNull int[] grantResults) {
switch (requestCode) {
case Permissions.READ_CONTACTS: { //Permissions.READ_CONTACTS is an int constant
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
getContactsFromPhone();
}
}
}
}
Then in ur onclick to get this contacts you should ask if you have this permission:
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(activity,
new String[]{Manifest.permission.READ_CONTACTS}, Permissions.READ_CONTACTS); //Permissions.READ_CONTACTS is an int constant
return false;
} else {
getContactsFromPhone();
}
1) Yes, you should check that permission is granted every time you called these functions.
2) You can check and request permissions from main thread. I think that check and request permissions from AsyncTask isn't good way, because permission request is a dialog, and you will have to wait asynctask thread until you get user response. Try to check permission from main thread, get user response, and then, if permission granted, start your asynctask.
Dexter is an Android library that simplifies the process of requesting permissions at runtime.