Android - onRequestPermissionsResult() is deprecated. Are there any alternatives?

23,911

Solution 1

onRequestPermissionsResult() method is deprecated in androidx.fragment.app.Fragment.

So you use registerForActivityResult() method instead onRequestPermissionsResult().

You can refer this URL.

Following is kotlin code. but you can refer it.

val permReqLuncher = registerForActivityResult(ActivityResultContracts.RequestPermission()){
  if (it) {
     // Good pass
  } else {
     // Failed pass
  }
}

I added java code from following URL.
How to get a permission request in new ActivityResult API (1.3.0-alpha05)?

private ActivityResultLauncher<String> mPermissionResult = registerForActivityResult(
        new ActivityResultContracts.RequestPermission(),
        new ActivityResultCallback<Boolean>() {
            @Override
            public void onActivityResult(Boolean result) {
                if(result) {
                    Log.e(TAG, "onActivityResult: PERMISSION GRANTED");
                } else {
                    Log.e(TAG, "onActivityResult: PERMISSION DENIED");
                }
            }
        });



        // Launch the permission window -- this is in onCreateView()
    floatingActionButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
         mPermissionResult.launch(Manifest.permission.ACCESS_BACKGROUND_LOCATION);

        }
    });

You can request multiple permissions.

    val requestMultiplePermissions = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
        permissions.entries.forEach {
            Log.e("DEBUG", "${it.key} = ${it.value}")
        }
    }

    requestMultiplePermissions.launch(
        arrayOf(
            Manifest.permission.READ_CONTACTS,
            Manifest.permission.ACCESS_FINE_LOCATION
       )
    )

Solution 2

A simple way in Kotlin

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ActivityCompat
import androidx.fragment.app.Fragment

class MyFragment : Fragment() {

companion object {
    val TAG: String = MyFragment::class.java.simpleName
    var PERMISSIONS = arrayOf(
        Manifest.permission.CAMERA,
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
    )
}

private val permReqLauncher =
    registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
        val granted = permissions.entries.all {
            it.value == true
        }
        if (granted) {
            displayCameraFragment()
        }
    }

private fun takePhoto() {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
        displayCameraFragment()
    }
    activity?.let {
        if (hasPermissions(activity as Context, PERMISSIONS)) {
            displayCameraFragment()
        } else {
            permReqLauncher.launch(
                PERMISSIONS
            )
        }
    }
}

// util method
private fun hasPermissions(context: Context, permissions: Array<String>): Boolean = permissions.all {
    ActivityCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}

private fun displayCameraFragment() {
    // open camera fragment
}
}

Solution 3

Alternative registerForActivityResult

Example use:

 private fun permissionSetup() {
    val permission = ContextCompat.checkSelfPermission(
        requireContext(), Manifest.permission.READ_CONTACTS)

    if (permission != PackageManager.PERMISSION_GRANTED) {
        permissionsResultCallback.launch(Manifest.permission.READ_CONTACTS)
    } else {
        println("Permission isGranted")
    }
}

private val permissionsResultCallback = registerForActivityResult(
    ActivityResultContracts.RequestPermission()){
    when (it) {
        true -> { println("Permission has been granted by user") }
        false -> {
            Toast.makeText(requireContext(), "Permission denied", Toast.LENGTH_SHORT).show()
            dialog.dismiss()
        }
    }
}

Solution 4

This works for me - (kotlin):

private fun checkPermissions() {
    if (mContext?.let {
        ContextCompat.checkSelfPermission(
            it,
            READ_EXTERNAL_STORAGE
        )
    } != PackageManager.PERMISSION_GRANTED) {
    Log.d(TAG, "Request Permissions")
    requestMultiplePermissions.launch(
        arrayOf(READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE))
 } else {
        Log.d(TAG, "Permission Already Granted")
    }
}

private val requestMultiplePermissions =
    registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
        permissions.entries.forEach {
            Log.d(TAG, "${it.key} = ${it.value}")
        }
        if (permissions[READ_EXTERNAL_STORAGE] == true && permissions[WRITE_EXTERNAL_STORAGE] == true) {
            Log.d(TAG, "Permission granted")
        } else {
            Log.d(TAG, "Permission not granted")
        }
    }

Solution 5

Please refer to the official documentation: https://developer.android.com/training/permissions/requesting

Review the following, which can be found in the documentation.

// Register the permissions callback, which handles the user's response to the
// system permissions dialog. Save the return value, an instance of
// ActivityResultLauncher. You can use either a val, as shown in this snippet,
// or a lateinit var in your onAttach() or onCreate() method.
val requestPermissionLauncher =
    registerForActivityResult(RequestPermission()
    ) { isGranted: Boolean ->
        if (isGranted) {
            // Permission is granted. Continue the action or workflow in your
            // app.
        } else {
            // Explain to the user that the feature is unavailable because the
            // features requires a permission that the user has denied. At the
            // same time, respect the user's decision. Don't link to system
            // settings in an effort to convince the user to change their
            // decision.
        }
    }

After which, launch the request

when {
    ContextCompat.checkSelfPermission(
            CONTEXT,
            Manifest.permission.REQUESTED_PERMISSION
            ) == PackageManager.PERMISSION_GRANTED -> {
        // You can use the API that requires the permission.
    }
    //Is not needed for it to work, but is a good practice as it plays a role
    //in letting user know why the permission is needed.
    shouldShowRequestPermissionRationale(...) -> {
        // In an educational UI, explain to the user why your app requires this
        // permission for a specific feature to behave as expected. In this UI,
        // include a "cancel" or "no thanks" button that allows the user to
        // continue using your app without granting the permission.
        showInContextUI(...)
    }
    else -> {
        // You can directly ask for the permission.
        // The registered ActivityResultCallback gets the result of this request.
        requestPermissionLauncher.launch(
                Manifest.permission.REQUESTED_PERMISSION)
    }
}
Share:
23,911
ashley
Author by

ashley

Updated on July 05, 2022

Comments

  • ashley
    ashley almost 2 years

    I tried to implement request permissions for writing and reading from storage. Everything worked good but today Android showed me that the method onRequestPermissionsResult(...) is deprecated. There are so many questions about this topic in StackOverflow, but unfortunately, they are outdated.

    I called the methods below in a fragment.

    It was suggested simply to call:

    requestPermissions(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
    StorageKeys.STORAGE_PERMISSION_CODE)
    

    instead of my approach:

    ActivityCompat.requestPermissions(getActivity(),
    new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
    StorageKeys.STORAGE_PERMISSION_CODE))
    

    But both of them show that onRequestPermissionsResult(...) is deprecated.

    Here is my onRequestPermissionsResult(...)-method:

      @Override
      public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                             @NonNull int[] grantResults) {
    
        if (requestCode == StorageKeys.STORAGE_PERMISSION_CODE) {
    
          if (grantResults.length > 0
              && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    
            exportBibTex.createBibFile();
            exportBibTex.writeBibFile(exportBibTex
                .getBibDataLibrary(libraryModel, bookDao, noteDao));
    
            Toast.makeText(getContext(),
                getString(R.string.exported_file_stored_in) + '\n'
                    + File.separator + StorageKeys.DOWNLOAD_FOLDER + File.separator + fileName
                    + StorageKeys.BIB_FILE_TYPE, Toast.LENGTH_LONG).show();
    
          } else {
            Toast.makeText(getContext(), R.string.storage_permission_denied,
                Toast.LENGTH_SHORT).show();
          }
        }
      }
    

    Here is a simple alert dialog, in which I call the onRequestPermissionsResult(...):

      private void showRequestPermissionDialog() {
        AlertDialog.Builder reqAlertDialog = new AlertDialog.Builder(getContext());
        reqAlertDialog.setTitle(R.string.storage_permission_needed);
        reqAlertDialog.setMessage(R.string.storage_permission_alert_msg);
    
        reqAlertDialog.setPositiveButton(R.string.ok,
            (dialog, which) -> ActivityCompat.requestPermissions(getActivity(),
                new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
                StorageKeys.STORAGE_PERMISSION_CODE));
        reqAlertDialog.setNegativeButton(R.string.cancel,
            (dialog, which) -> dialog.dismiss());
    
        reqAlertDialog.create().show();
      }
    

    Is there any alternative for onRequestPermissionsResult(...), that I can use?

  • ashley
    ashley over 3 years
    Thanks, can I use the ActivityResultLauncher(..) for multiple permissions? For example requestPermissionLauncher.launch( Manifest.permission.WRITE_EXTERNAL_STORAGE); requestPermissionLauncher.launch( Manifest.permission.READ_EXTERNAL_STORAGE);
  • Daniel.Wang
    Daniel.Wang over 3 years
    yes, you can use it. but you need to change some part of my code. i updated my post.
  • Daniel.Wang
    Daniel.Wang over 3 years
    So you need to use ActivityResultContracts.RequestMultiplePermissions() when call registerForActivityResult() method.
  • ianhanniballake
    ianhanniballake over 3 years
    This is also specifically mentioned in the documentation.
  • CoolMind
    CoolMind almost 3 years
    In your case you call registerForActivityResult in onCreateView. In my experience it is usually enough to create permissionRequest variable in onCreate, onAttach or as a initialized local variable. In onCreate we should check an order of calls. It would be better to create the variable before other operators, because sometimes it can be called too early.
  • tanni tanna
    tanni tanna almost 3 years
    @CoolMind, I totally agree with you. I did mention the same in the description. I have corrected that now. Thanks.