Summary:
Dialogs are not showing up(sometimes) in the HomePage, because the parser says that the current dialog view already has a parent and adding it to another parent would require us to remove this dialog view from the existing parent.
System logs:
```
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.view.ViewGroup.addViewInner(ViewGroup.java:5034)
at android.view.ViewGroup.addView(ViewGroup.java:4865)
at android.view.ViewGroup.addView(ViewGroup.java:4837)
at com.android.internal.app.AlertController.setupCustomContent(AlertController.java:627)
at com.android.internal.app.AlertController.setupView(AlertController.java:521)
at com.android.internal.app.AlertController.installContent(AlertController.java:264)
at android.app.AlertDialog.onCreate(AlertDialog.java:436)
at android.app.Dialog.dispatchOnCreate(Dialog.java:407)
at android.app.Dialog.show(Dialog.java:302)
at fr.free.nrw.commons.utils.DialogUtil.showSafely(DialogUtil.java:33)
at fr.free.nrw.commons.utils.DialogUtil.showAlertDialog(DialogUtil.java:140)
at fr.free.nrw.commons.utils.DialogUtil.showAlertDialog(DialogUtil.java:96)
at fr.free.nrw.commons.contributions.ContributionsFragment.showNearbyCardPermissionRationale(ContributionsFragment.java:523)
at fr.free.nrw.commons.contributions.ContributionsFragment.checkPermissionsAndShowNearbyCardView(ContributionsFragment.java:504)
at fr.free.nrw.commons.contributions.ContributionsFragment.onResume(ContributionsFragment.java:484)
at androidx.fragment.app.Fragment.performResume(Fragment.java:2499)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:926)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1229)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1295)
at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.java:2605)
at androidx.fragment.app.FragmentManagerImpl.dispatchResume(FragmentManagerImpl.java:2577)
at androidx.fragment.app.FragmentController.dispatchResume(FragmentController.java:267)
at androidx.fragment.app.FragmentActivity.onResumeFragments(FragmentActivity.java:463)
at androidx.fragment.app.FragmentActivity.onPostResume(FragmentActivity.java:453)
at androidx.appcompat.app.AppCompatActivity.onPostResume(AppCompatActivity.java:173)
at android.app.Activity.performResume(Activity.java:7325)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3814)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3854)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:51)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:145)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:70)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1816)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6718)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
2019-06-23 10:36:28.746 10262-10262/fr.free.nrw.commons.beta E/ContributionsFragment: onFragmentResumed fr.free.nrw.commons.contributions.ContributionsListFragment
Device and Android version:
Google Pixel, Api 27
Commons app version:
2.10.2-debug
I'm going to take a look at this and see what I can find or fix
Thanks for taking this up @albendz :-)
To repro, just dismiss and reopen the app (don't end the app process).
My stack:
2019-07-16 18:53:50.754 7112-7112/fr.free.nrw.commons.beta E/DialogUtil: Could not show dialog.
java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
at android.view.ViewGroup.addViewInner(ViewGroup.java:4915)
at android.view.ViewGroup.addView(ViewGroup.java:4746)
at android.view.ViewGroup.addView(ViewGroup.java:4718)
at com.android.internal.app.AlertController.setupCustomContent(AlertController.java:606)
at com.android.internal.app.AlertController.setupView(AlertController.java:500)
at com.android.internal.app.AlertController.installContent(AlertController.java:258)
at android.app.AlertDialog.onCreate(AlertDialog.java:425)
at android.app.Dialog.dispatchOnCreate(Dialog.java:403)
at android.app.Dialog.show(Dialog.java:302)
at fr.free.nrw.commons.utils.DialogUtil.showSafely(DialogUtil.java:33)
at fr.free.nrw.commons.utils.DialogUtil.showAlertDialog(DialogUtil.java:140)
at fr.free.nrw.commons.utils.DialogUtil.showAlertDialog(DialogUtil.java:96)
at fr.free.nrw.commons.contributions.ContributionsFragment.showNearbyCardPermissionRationale(ContributionsFragment.java:444)
at fr.free.nrw.commons.contributions.ContributionsFragment.checkPermissionsAndShowNearbyCardView(ContributionsFragment.java:425)
at fr.free.nrw.commons.contributions.ContributionsFragment.onResume(ContributionsFragment.java:405)
at androidx.fragment.app.Fragment.performResume(Fragment.java:2499)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:926)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1229)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1295)
at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.java:2605)
at androidx.fragment.app.FragmentManagerImpl.dispatchResume(FragmentManagerImpl.java:2577)
at androidx.fragment.app.FragmentController.dispatchResume(FragmentController.java:267)
at androidx.fragment.app.FragmentActivity.onResumeFragments(FragmentActivity.java:463)
at androidx.fragment.app.FragmentActivity.onPostResume(FragmentActivity.java:453)
at androidx.appcompat.app.AppCompatActivity.onPostResume(AppCompatActivity.java:173)
at android.app.Activity.performResume(Activity.java:7103)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3620)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3685)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1643)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
The view that is throwing the exception is the customView being sent to the DialogUtils.showAlertDialog. This happens for onResume because Dialog1 (the dialog created before suspend) has the customView and a new dialog Dialog2 (the dialog created after suspend) uses the same customView (who already has Dialog1 as a parent).
A few options I'm considering:
The primary example I'm looking at is the location permissions dialog.
Dismiss alert dialogs on suspend because it is being recreated on resume
Figure out if a dialog has already been created and don't create another on resume
These two will require considerable changes, the DialogUtils is used from many places. The third option would solve the issue for now and IMO we can create another issue to refactor the DialogUtils to make sure multiple instances are not created.
Most helpful comment
I'm going to take a look at this and see what I can find or fix