14

so, I tried to get a permission with the new registerForActivityResult() method and ask for with button click with .launch() and it doesn´t seem to be opening any window to ask for it. I´m always getting false in registerForActivityResult().

    // Permission to get photo from gallery, gets permission and produce boolean
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);

        }
    });

This is my LOG always: onActivityResult: PERMISSION DENIED

markato
  • 165
  • 1
  • 1
  • 7
  • Does this answer your question? [Update to androidx.fragment:fragment:1.3.0-alpha08: registerForActivityResult not allowed after onCreate anymore. How to use after onCreate?](https://stackoverflow.com/questions/63879320/update-to-androidx-fragmentfragment1-3-0-alpha08-registerforactivityresult-no) – Bink Sep 20 '22 at 19:15

2 Answers2

20

UPDATE
This answer works, but I found a better solution for permission requests with no open holes here.


From docs:

In your Activity/Fragment, create this field:

// Register the permissions callback, which handles the user's response to the
// system permissions dialog. Save the return value, an instance of
// ActivityResultLauncher, as an instance variable.
private ActivityResultLauncher<String> requestPermissionLauncher =
    registerForActivityResult(new RequestPermission(), isGranted -> {
        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.
        }
    });

Somewhere in the same Activity/Fragment:

if (ContextCompat.checkSelfPermission(
        context, Manifest.permission.ACCESS_BACKGROUND_LOCATION) ==
        PackageManager.PERMISSION_GRANTED) {
    performAction(...);
} else if (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.ACCESS_BACKGROUND_LOCATION);
}

If you are getting unreasonable "Permission denied" all the time, maybe you did not declare it in your manifest.xml?

Ace
  • 2,108
  • 22
  • 29
  • What about denied permissions and the case with "do not ask again" option ??? – Marlon López Sep 24 '20 at 00:48
  • 1
    Is there any way I can check whether the user has denied permanently? To display a relevant message. – Vishak A Kamath Mar 01 '21 at 10:40
  • @VishakAKamath This answer was copied from the linked docs. After practicing some more, I figured a cleaner and better approach to the permission request flow. Check [this](https://stackoverflow.com/a/66051728/3438172) out for answers to all your questions. – Ace May 06 '21 at 17:44
  • @MarlonLópez Check the answer I linked above or [here](https://stackoverflow.com/a/66051728/3438172) – Ace May 06 '21 at 17:45
3

Looking at Update to androidx.fragment:fragment:1.3.0-alpha08: registerForActivityResult not allowed after onCreate anymore. How to use after onCreate?,

private lateinit var checkLocationPermission: ActivityResultLauncher<Array<String>>

// Initialize checkLocationPermission in onAttach or onCreate.
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    checkLocationPermission = registerForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
        if (permissions[Manifest.permission.ACCESS_FINE_LOCATION] == true ||
            permissions[Manifest.permission.ACCESS_COARSE_LOCATION] == true) {
            initUserLocation()
        } else {
            // Permission was denied. Display an error message.
        }
    }
}

fun showMap() {
    if (ActivityCompat.checkSelfPermission(requireContext(),
        Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED ||
        ActivityCompat.checkSelfPermission(requireContext(),
            Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
        initUserLocation()
    } else {
        checkLocationPermission.launch(arrayOf(Manifest.permission.ACCESS_FINE_LOCATION,
            Manifest.permission.ACCESS_COARSE_LOCATION))
    }
}

private fun initUserLocation() {
    googleMap?.isMyLocationEnabled = true
}
CoolMind
  • 26,736
  • 15
  • 188
  • 224
  • Per https://developer.android.com/training/basics/intents/result#register, you want to call registerForActivityResult before your fragment or activity is created. – Bink Sep 20 '22 at 19:09
  • @Bink, it is called in `showMap()`. In the above link it is called in `onCreate`. That's why `registerForActivityResult` is called after the fragment was created. – CoolMind Sep 20 '22 at 20:05