Closed mtwalli closed 1 year ago
@Mo-Jamal thanks for the heads up! I hadn't heard about this new API. You're right, EasyPermissions should use it.
Is there any plan to support the new API? thanks
I haven't had time to work on this, if anyone wants to submit a PR I am happy to review.
@samtstern I have used this library for years due to its simplicity. with the new api "registerForActivityResult" I found a way to simplify it further. I'd love to have your opinion on this.
the usage are like:
private val permissionLauncher = RequestPermissionLauncher(this) // this must be class variable
permissionLauncher.launch("titleRational", "messageRational", Manifest.permission.XXX, Manifest.permission.YYY).observe(this) {
if (it == RequestPermissionsManager.PermissionResult.GRANTED) {
// TODO do what you want
} else if (it == RequestPermissionsManager.PermissionResult.DENIED) {
// TODO user refuse
} else if (it == RequestPermissionsManager.PermissionResult.PERMANENTLY_DENIED) {
// TODO user permanently refuse
}
}
@xanscale I can't access that link you posted but this seems really interesting! If you're interested in sending a Pull Request for this I would be happy to review it. Or if you want to save yourself some work you could try outlining the complete approach in an issue so we could discuss it.
@samtstern sorry, i renamed the file. just updated previous post
this system not use annotation to intercept callback, use livedata. i don't know, how to integrate with easypermission.
i linked to you because i used some your ideas in my code, and i loved easypermission, so i will love your comment to my library
@samtstern any review?
@xanscale sorry I haven't had time to take a look! I don't really work on EasyPermissions much anymore since it's been stable for so long, I'll try to find some time when I can.
With an adjustment that I have added the request code when calling launch()
and also I'm passing the request code back.
import android.content.Context;
import android.content.pm.PackageManager;
import android.text.TextUtils;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import java.util.Map;
public final class RequestPermissionContract implements ActivityResultCallback<Map<String, Boolean>> {
private final RequestPermissionCallback callback;
private int currentRequestCode;
private final ActivityResultLauncher<String[]> permissionLauncher;
private FragmentActivity activity;
private Fragment fragment;
public RequestPermissionContract(Fragment fragment, RequestPermissionCallback callback) {
this.callback = callback;
this.fragment = fragment;
permissionLauncher = fragment.registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), this);
}
public RequestPermissionContract(FragmentActivity activity, RequestPermissionCallback callback) {
this.callback = callback;
this.activity = activity;
permissionLauncher = activity.registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), this);
}
/**
* launch the dialog to request the permissions.
* You can pass as many permissions as required.
*
* @param rationale is required of you want to show the dialog before requesting the permission and permission was already denied previously.
*/
public void launch(int requestCode, @Nullable String rationale, String... permissions) {
if (checkSelfPermission(permissions)) {
// permissions are already granted, so pass the callback
callback.onActivityResult(requestCode, PermissionResult.GRANTED);
return;
}
if (shouldShowRequestPermissionRationale(permissions)) {
if (!TextUtils.isEmpty(rationale)) {
// user want to show the rationale dialog
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
if (rationale != null)
builder.setMessage(rationale);
builder.setPositiveButton(android.R.string.ok, (dialog, which) -> launchPermissionLauncher(requestCode, permissions));
builder.setNegativeButton(android.R.string.cancel, (dialog, which) -> callback.onActivityResult(requestCode, PermissionResult.DENIED));
builder.create().show();
return;
}
}
// launch the permissions
launchPermissionLauncher(requestCode, permissions);
}
private void launchPermissionLauncher(int requestCode, String... permissions) {
this.currentRequestCode = requestCode;
// request the permissions
permissionLauncher.launch(permissions);
}
@Override
public void onActivityResult(Map<String, Boolean> results) {
if (results.isEmpty()) {
callback.onActivityResult(currentRequestCode, PermissionResult.DENIED);
return;
}
String[] permissions = results.keySet().toArray(new String[0]);
if (checkSelfPermission(permissions)) {
// all permissions are granted
callback.onActivityResult(currentRequestCode, PermissionResult.GRANTED);
} else if (shouldShowRequestPermissionRationale(permissions)) {
callback.onActivityResult(currentRequestCode, PermissionResult.DENIED);
} else {
// permissions are permanently disabled
callback.onActivityResult(currentRequestCode, PermissionResult.PERMANENTLY_DENIED);
}
}
private FragmentActivity getActivity() {
if (activity != null)
return activity;
else
return fragment.requireActivity();
}
private boolean shouldShowRequestPermissionRationale(String... permissions) {
for (String perm : permissions)
if (ActivityCompat.shouldShowRequestPermissionRationale(getActivity(), perm))
return true;
return false;
}
/**
* check if all the permissions are granted
*/
private boolean checkSelfPermission(String... permissions) {
return checkSelfPermission(getActivity(), permissions);
}
public static boolean checkSelfPermission(Context context, String... permissions) {
for (String perm : permissions)
if (ContextCompat.checkSelfPermission(context, perm) != PackageManager.PERMISSION_GRANTED)
return false;
return true;
}
public interface RequestPermissionCallback {
/**
* function to pass the result with request code.
* Will return the aggregated result of all permissions i.e. if all the permissions are granted then it will be true.
*/
void onActivityResult(int requestCode, PermissionResult result);
}
public enum PermissionResult {GRANTED, DENIED, PERMANENTLY_DENIED}
}
Usage:
private final RequestPermissionContract permissionLauncher = new RequestPermissionContract(this, (requestCode, permissionResult) -> {
if (requestCode == PERMISSION_REQUEST_CODE) {
if (permissionResult == RequestPermissionContract.PermissionResult.GRANTED) {
// Permission is granted
} else if (permissionResult == RequestPermissionContract.PermissionResult.DENIED) {
// permission denied
} else if (permissionResult == RequestPermissionContract.PermissionResult.PERMANENTLY_DENIED) {
// permanently denied
}
}
});
// call the below code on click of button for e.g:
permissionLauncher.launch(PERMISSION_REQUEST_CODE, "Allow this permission to use the functionality", Manifest.permission.CALL_PHONE);
Current permission request in Android will be deprecated starting from
androidx.activity:activity:1.2.0
andandroidx.fragment:fragment:1.3.0
.The new Activity Result API will be used instead of current one. It would be nice to add support for it.