preface

EasyPermissions is a library for checking and applying for Android dynamic permissions, simplifying native permissions logic. Please refer to the official document for the usage method.


A, requirements,

It is necessary to replace the two prompt pop-up boxes encapsulated in the library with the unified internal design style of app, which are as follows:

  • Prompt box 1: indicates that a user refuses permission.

  • Prompt box 2: show the built-in AppSettingsDialog when the user refuses permission and chooses not to ask again.
@Override
public void onPermissionsDenied(int requestCode, List<String> perms) {
  Log.d(TAG, "onPermissionsDenied:" + requestCode + ":" + perms.size());

  // (Optional) Check whether the user denied any permissions and checked "NEVER ASK AGAIN."
  // This will display a dialog directing them to enable the permission in app settings.
  if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
      new AppSettingsDialog.Builder(this).build().show(); }}Copy the code

Click OK to jump to the application information in the Settings for changing permissions

public void onClick(DialogInterface dialog, int which) {
        if (which == Dialog.BUTTON_POSITIVE) {
            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                    .setData(Uri.fromParts("package", getPackageName(), null));
            intent.addFlags(mIntentFlags);
            startActivityForResult(intent, APP_SETTINGS_RC);
        } else if (which == Dialog.BUTTON_NEGATIVE) {
            setResult(Activity.RESULT_CANCELED);
            finish();
        } else {
            throw new IllegalStateException("Unknown button type: "+ which); }}Copy the code

Second, the implementation

  1. Prompt 2 is easy to replace, just replace AppSettingsDialog with your own Dialog.
override fun onPermissionsDenied(requestCode: Int, perms: List<String>) {
       if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
           CommonDialog.Builder(this).build().show()
       }
   }
Copy the code

  1. Prompt 1 did not find a method to expose the replacement.

Call for a time limit:

private fun requestPermission(vararg perms: String) {
       val request = PermissionRequest.Builder(this, REQUEST_CODE_PERMISSIONS, *perms)
           .setRationale("This app may not work correctly without the requested permissions.")
           .setPositiveButtonText("Sure")
           .setNegativeButtonText("Cancel")
           .build()
       EasyPermissions.requestPermissions(request)
   }
Copy the code

Get the PermissionHelper from the PermissionRequest getHelper() and requestPermissions from the requestPermissions method

public static void requestPermissions(PermissionRequest request) {

        // Check for permissions before dispatching the request
        if (hasPermissions(request.getHelper().getContext(), request.getPerms())) {
            notifyAlreadyHasPermissions(
                    request.getHelper().getHost(), request.getRequestCode(), request.getPerms());
            return;
        }

        // Request permissions
        request.getHelper().requestPermissions(
                request.getRationale(),
                request.getPositiveButtonText(),
                request.getNegativeButtonText(),
                request.getTheme(),
                request.getRequestCode(),
                request.getPerms());
    }
Copy the code

The PermissionHelper is created when the PermissionRequest is created

 public Builder(@NonNull Activity activity, int requestCode,
                       @NonNull @Size(min = 1) String... perms) {
            mHelper = PermissionHelper.newInstance(activity);
            mRequestCode = requestCode;
            mPerms = perms;
        }
        
public Builder(@NonNull Fragment fragment, int requestCode,
                       @NonNull @Size(min = 1) String... perms) {
            mHelper = PermissionHelper.newInstance(fragment);
            mRequestCode = requestCode;
            mPerms = perms;
        }
Copy the code

PermissionHelper call showRequestPermissionRationale display box

public void requestPermissions(@NonNull String rationale,
                                   @NonNull String positiveButton,
                                   @NonNull String negativeButton,
                                   @StyleRes int theme,
                                   int requestCode,
                                   @NonNull String... perms) {
        if (shouldShowRationale(perms)) {
            showRequestPermissionRationale(
                    rationale, positiveButton, negativeButton, theme, requestCode, perms);
        } else{ directRequestPermissions(requestCode, perms); }}Copy the code

PermissionHelper is an abstract class with the following inheritance

Look at the find a BaseSupportPermissionsHelper showRequestPermissionRationale method

public void showRequestPermissionRationale(@NonNull String rationale,
                                               @NonNull String positiveButton,
                                               @NonNull String negativeButton,
                                               @StyleRes int theme,
                                               int requestCode,
                                               @NonNull String... perms) {

        FragmentManager fm = getSupportFragmentManager();

        // Check if fragment is already showing
        Fragment fragment = fm.findFragmentByTag(RationaleDialogFragmentCompat.TAG);
        if (fragment instanceof RationaleDialogFragmentCompat) {
            Log.d(TAG, "Found existing fragment, not showing rationale.");
            return;
        }

        RationaleDialogFragmentCompat
                .newInstance(rationale, positiveButton, negativeButton, theme, requestCode, perms)
                .showAllowingStateLoss(fm, RationaleDialogFragmentCompat.TAG);
    }
Copy the code

RationaleDialogFragmentCompat inherited from DialogFragment

@Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        // Rationale dialog should not be cancelable
        setCancelable(false);

        // Get config from arguments, create click listener
        RationaleDialogConfig config = new RationaleDialogConfig(getArguments());
        RationaleDialogClickListener clickListener =
                new RationaleDialogClickListener(this, config, mPermissionCallbacks, mRationaleCallbacks);

        // Create an AlertDialog
        return config.createSupportDialog(getContext(), clickListener);
    }
Copy the code

RationaleDialogConfig:

AlertDialog createSupportDialog(Context context, Dialog.OnClickListener listener) {
        AlertDialog.Builder builder;
        if (theme > 0) {
            builder = new AlertDialog.Builder(context, theme);
        } else {
            builder = new AlertDialog.Builder(context);
        }
        return builder
                .setCancelable(false)
                .setPositiveButton(positiveButton, listener)
                .setNegativeButton(negativeButton, listener)
                .setMessage(rationaleMsg)
                .create();
    }
Copy the code

It is possible to download a copy of the source code to replace the default AlertDialog and package it. Another solution is used here: you can hook the mHelper for PermissionRequest

private final PermissionHelper mHelper;
Copy the code

Change mHelper showRequestPermissionRationale method to the pop-up Dialog, first define a proxy class:

public class PermissionsHelperProxy<T>(
    private val permissionHelper: BaseSupportPermissionsHelper<T>
) : BaseSupportPermissionsHelper<T>(permissionHelper.host!!) {

    override fun directRequestPermissions(requestCode: Int.vararg perms: String?). {
        permissionHelper.directRequestPermissions(requestCode, *perms)
    }

    override fun shouldShowRequestPermissionRationale(perm: String): Boolean {
        return permissionHelper.shouldShowRequestPermissionRationale(perm)
    }

    override fun getContext(a): Context {
        return permissionHelper.context
    }

    override fun getSupportFragmentManager(a): FragmentManager {
        return permissionHelper.supportFragmentManager
    }

    override fun showRequestPermissionRationale(
        rationale: String,
        positiveButton: String,
        negativeButton: String.@StyleRes theme: Int,
        requestCode: Int.vararg perms: String
    ) {
        CommonDialog.Builder(context).build().show()
    }
Copy the code

Replace at the limit of claim:

private fun requestPermission(vararg perms: String) {
        val request = PermissionRequest.Builder(this, REQUEST_CODE_PERMISSIONS, *perms)
            .setRationale("This app may not work correctly without the requested permissions.")
            .setPositiveButtonText("Sure")
            .setNegativeButtonText("Cancel")
            .build()
        try {
            val clazz = request.javaClass
            val field = clazz.getDeclaredField("mHelper")
            field.isAccessible = true
            val permissionHelper =
                field.get(request) asBaseSupportPermissionsHelper<AppCompatActivity? > field.set(request, PermissionsHelperProxy(permissionHelper))
        } catch (e: Exception) {
        }
        EasyPermissions.requestPermissions(request)
    }
Copy the code

Success: