Skip to content

Instantly share code, notes, and snippets.

@patrickhammond
Last active April 30, 2018 21:10
Show Gist options
  • Save patrickhammond/47cff299bc34e976e18b to your computer and use it in GitHub Desktop.
Save patrickhammond/47cff299bc34e976e18b to your computer and use it in GitHub Desktop.
Pushing permission ugliness handling to one place.
import android.app.Activity;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull;
import android.support.annotation.Size;
import android.support.v4.app.ActivityCompat;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
public class ActivityPermissionDelegate {
public interface PermissionRationaleRetryBehavior {
void requestAgain();
}
public interface PermissionCallback {
void handleGranted();
void handleRationale(PermissionRationaleRetryBehavior behavior);
void handleDenied();
}
public static class PermissionRequest {
private final String name;
private final PermissionCallback callback;
private final String[] permissions;
public PermissionRequest(
@NonNull String name,
@NonNull PermissionCallback callback,
@Size(min = 1) String...permissions) {
this.name = name;
this.callback = callback;
this.permissions = permissions;
}
}
private final Activity activity;
private final PermissionRequest requests[];
public ActivityPermissionDelegate(
@NonNull Activity activity,
@Size(min = 1) PermissionRequest[] requests) {
this.activity = activity;
this.requests = requests;
}
public void requestPermission(@NonNull String requestName) {
final PermissionRequest request = mapRequestCodeToRequest(requestName);
if (checkPermissionsGranted(request)) {
request.callback.handleGranted();
} else {
if (shouldShowRequestPermissionRationale(request)) {
request.callback.handleRationale(new PermissionRationaleRetryBehavior() {
@Override
public void requestAgain() {
requestPermissions(request);
}
});
} else {
requestPermissions(request);
}
}
}
@CheckResult
public boolean onRequestPermissionsResult(
int requestCode,
@NonNull String[] permissions,
@NonNull int[] grantResults) {
PermissionRequest request = mapRequestCodeToRequest(requestCode);
if (request != null) {
if (verifyPermissions(grantResults)) {
request.callback.handleGranted();
return true;
} else {
request.callback.handleDenied();
return true;
}
}
return false;
}
private boolean checkPermissionsGranted(PermissionRequest request) {
for (String permission : request.permissions) {
if (ActivityCompat.checkSelfPermission(activity, permission) != PERMISSION_GRANTED) {
return false;
}
}
return true;
}
private boolean shouldShowRequestPermissionRationale(PermissionRequest request) {
for (String permission : request.permissions) {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
return true;
}
}
return false;
}
private void requestPermissions(PermissionRequest request) {
int requestCode = mapNameToRequestCode(request.name);
ActivityCompat.requestPermissions(activity, request.permissions, requestCode);
}
private int mapNameToRequestCode(String requestName) {
for (int i = 0; i < requests.length; i++) {
if (requests[i].name.equals(requestName)) {
return i;
}
}
throw new IllegalArgumentException(requestName);
}
private PermissionRequest mapRequestCodeToRequest(String requestName) {
for (int i = 0; i < requests.length; i++) {
if (requests[i].name.equals(requestName)) {
return requests[i];
}
}
throw new IllegalArgumentException(requestName);
}
private PermissionRequest mapRequestCodeToRequest(int requestCode) {
if (requestCode < 0 || requestCode >= requests.length) {
return null;
}
return requests[requestCode];
}
private boolean verifyPermissions(int[] grantResults) {
if (grantResults.length < 1){
return false;
}
for (int result : grantResults) {
if (result != PERMISSION_GRANTED) {
return false;
}
}
return true;
}
}
public class BarcodeLoggerActivity extends Activity {
private ActivityPermissionDelegate permissionDelegate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PermissionRequest request = new PermissionRequest(
"camera",
new PermissionCallback() {
@Override
public void handleGranted() {
startBarcodeCapture();
}
@Override
public void handleRationale(final PermissionRationaleRetryBehavior behavior) {
fragment.showPermissionDetails(new OnClickListener() {
@Override
public void onClick(View v) {
behavior.requestAgain();
}
});
}
@Override
public void handleDenied() {
fragment.showPermissionDetails(null);
}
},
android.Manifest.permission.CAMERA
);
permissionDelegate = new ActivityPermissionDelegate(this, new PermissionRequest[]{request});
if (savedInstanceState == null) {
permissionDelegate.requestPermission("camera");
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (!permissionDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults)) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
public class MyFragment extends Fragment {
...
public void showPermissionDetails(OnClickListener retryBehavior) {
showViewState(true, false, false);
retryPermissionView.setOnClickListener(retryBehavior);
retryPermissionView.setVisibility(retryBehavior == null ? View.GONE : View.VISIBLE);
}
public void showProgressView() {
showViewState(false, true, false);
}
public void showFailedView() {
showViewState(false, false, true);
}
private void showViewState(boolean permissionVisible, boolean progressVisible, boolean failedVisible) {
permissionView.setVisibility(permissionVisible ? View.VISIBLE : View.GONE);
progressView.setVisibility(progressVisible ? View.VISIBLE : View.GONE);
failedView.setVisibility(failedVisible ? View.VISIBLE : View.GONE);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment