Skip to content
This repository has been archived by the owner on Jul 2, 2021. It is now read-only.

Screen rotation while showing Rationale dialog invalidates PermissionListener #276

Open
nsk90 opened this issue Jan 18, 2021 · 13 comments
Open
Labels

Comments

@nsk90
Copy link

nsk90 commented Jan 18, 2021

Expected behaviour

PermissionListener passed to withListener() function is triggered after permission request.

Actual behaviour

PermissionListener is invalidated on screen rotation and its callbacks are not triggered.

Steps to reproduce

Rotate screen while showing dialog from onPermissionRationaleShouldBeShown callback.

Version of the library

6.2.2

I suppose that using ViewModel for DexterActivity should fix the problem, but it requires jetpack dependency.

@traviszim
Copy link

Expected behaviour

PermissionListener passed to withListener() function is triggered after permission request.

Actual behaviour

PermissionListener is invalidated on screen rotation and its callbacks are not triggered.

Steps to reproduce

Rotate screen while showing dialog from onPermissionRationaleShouldBeShown callback.

Version of the library

6.2.2

I suppose that using ViewModel for DexterActivity should fix the problem, but it requires jetpack dependency.

@pedrovgs pedrovgs added the bug label Jan 22, 2021
@pedrovgs
Copy link
Contributor

@nsk90 what do you mean by invalidated? Could you describe the issue from the user point of view?

@nsk90
Copy link
Author

nsk90 commented Jan 22, 2021

what do you mean by invalidated?

I mean it is replaced with default one, and so it is not triggered.

  void onActivityDestroyed(Activity oldActivity) {
    if (activity == oldActivity) {
      activity = null;
      isRequestingPermission.set(false);
      rationaleAccepted.set(false);
      isShowingNativeDialog.set(false);
      listener = EMPTY_LISTENER; // as I see this line invalidates my listener
    }
  }

Could you describe the issue from the user point of view?

from the user point of view is depends on what my app is doing in onPermissionRationaleShouldBeShown()

here are some cases:

  • in onPermissionRationaleShouldBeShown() I show AlertDialog with ok button. Screen rotation closes dialog and default (replaced) listener shows permission request.
  • in onPermissionRationaleShouldBeShown() I show DialogFragment with ok button. DialogFragment supports orientation changes so it is not closed by screen rotation. Permission request is shown above DialogFragment by the same reason as before.
  • in onPermissionRationaleShouldBeShown() I show AlertDialog with ok button. And in onPermissionGranted() I do some action which user must see (show some notification for example).
    In this case user will see notification if he clicks ok on rationale dialog and grands permission. But he will not see notification if he will rotate screen while rationale dialog is shown and grand permission.
    There is not way to fix this with DialogFragment.

I wrote that in my opinion ViewModel for DexterActivity should help, now I can add that there is a simpler option "headless fragment".
I hope this will help to support screen rotations (configuration changes) correctly.

@pedrovgs
Copy link
Contributor

I don't know right now what's the best fix for this issue. I need to review it in detail before changing anything. I'm also checking how to reproduce the issue manually and the sample app we provide seems to work properly. If you open the sample app, tap on the audio permission and waits for the dialog to be shown you can rotate the screen and the library works as expected. Maybe I'm missing something...could you try it out? If you can reproduce the error in our sample project it could be great if you create a branch reproducing the error. As a workaround, you could use configure your activity configChanges to avoid restoring the activity when the device screen rotates.

@nsk90
Copy link
Author

nsk90 commented Jan 22, 2021

Audio button in sample app does not use Rationale dialog. Use CAMERA button.

Steps to reproduce on Sample app.

  • press CAMERA button
  • see rationale dialog
  • rotate screen
  • accept or reject permission.

Take a look at SampleActivity.showPermissionRationale() method it is called from SamplePermissionListener.
There is an AlertDialog which calls token.cancelPermissionRequest(); and token.continuePermissionRequest(); (in 3 places)
you can place breakpoints or logs on this calls to see that no one of them is called if you rotate screen while dialog is up.
In this condition permission is actually requested (made call to token.continuePermissionRequest();) from BaseMultiplePermissionsListener (default). To see that listener is "invalidated" (replaced with default one) put breakpoints or logs to onPermissionGranted() and onPermissionDenied() methods in SamplePermissionListener. This methods will not be triggered if you rotate screen while rationale dialog is up.

The problem is just hidden by default listener which is calling token.continuePermissionRequest();.

@pedrovgs
Copy link
Contributor

I'm afraid this is not easy to fix at all. When the device is rotated the OS recreates the activity and this means we lose every reference to the original listener. As far as I've reviewing there is no way we can get a reference of any listener pointing at the new activity. I'm all ears in case any of you are able to find a fix for this, right now I can't any possible solution but blocking screen orientation which is not a solution at all.

@nsk90
Copy link
Author

nsk90 commented Feb 19, 2021

Storing a reference to the listener in a Fragment with setRetainInstance(true) does not help?

@pedrovgs
Copy link
Contributor

That would help if you are using Dexter but that wouldn't fix the issue and it would not be valid for anybody using activities.

@nsk90
Copy link
Author

nsk90 commented Feb 19, 2021

Looks like I explained not correctly.

I meant, to use such a fragment (with setRetainInstance(true)) inside DexterActivity.
Move Dexter.onActivityReady(this); and Dexter.onActivityDestroyed(this); calls to that fragment.

I expect this will extend lifetime of references stored in Dexter class and they will be retained across configuration changes.

@pedrovgs
Copy link
Contributor

@nsk90 I think that's not going to work because the listener would hold a reference to a destroyed activity. Even if we save the listener in a static property the activity of the developer who uses dexter will be recreated and the listener we saved would point at a dead activity :(

@deinlandel
Copy link

This is a serious bug. At least make some kind of broadcast so we can check that rights were granted or means to cancel this dialog after rotation.

@pedrovgs
Copy link
Contributor

pedrovgs commented Apr 9, 2021

Indeed! It's a serious bug @deinlandel. Keep in mind, I'm the only developer actively working on this project for years and I have to maintain the other company repositories. https://github.com/Karumi/KotlinSnapshot and https://github.com/Karumi/Shot are just two examples. I'm afraid I only have 12 days per year to work on our open-source projects and two hands. If you think this is a serious bug and it is blocking you I'd really appreciate it if you can have the time to help us and collaborate. If you don't have the time, I guess you can use only portrait rotation whenever you are requesting this permission. There are also other libraries you can use if you need it.

@deinlandel
Copy link

@pedrovgs That's okay, life often leaves us without time for our side projects. Although please at least write in library's readme that it's unmantained because you don't have time to maintain it. So new users would know that they should not expect any updates and bug fixes.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants