javaandroiddialogpreferencescreen

How to setCancelable(false) for standard dialog PreferenceFragmentCompat


I'm using PreferenceFragmentCompat to display and set SharedPreferences. This all works fine. However, I keep getting "W/InputEventReceiver: Attempted to finish an input event but the input event receiver has already been disposed." in my logs, because the standard dialog used by PreferencesFragmentCompat does not seem to use the .setCancelable(false) in its showDialog method. I guess I could build my own custom dialog, but that seems a bit of an overkill just to solve this one small problem. Is there any way to simply overwrite the method?

Update:

It was enough to add this to my PreferencesFragmet (removed MultiSelectListPreferenceDialogFragmentCompat, as I don't use it)

@Override
public void onDisplayPreferenceDialog(Preference pref) {
    DialogFragment dialogFragment = null;
    String DIALOG_FRAGMENT_TAG = "androidx.preference.PreferenceFragment.DIALOG";

    if (pref instanceof EditTextPreference) {
        dialogFragment = EditTextPreferenceDialogFragmentCompat.newInstance(pref.getKey());
    } else if (pref instanceof ListPreference) {
        dialogFragment = ListPreferenceDialogFragmentCompat.newInstance(pref.getKey());
    }

    if (dialogFragment != null) {
        dialogFragment.setTargetFragment(this, 0);
        dialogFragment.setCancelable(false); //adding this!
        if (this.getFragmentManager() != null) {
            dialogFragment.show(this.getFragmentManager(), DIALOG_FRAGMENT_TAG);
        }
    } else {
        super.onDisplayPreferenceDialog(pref);
    }
}

Solution

  • I sorted though PreferenceFramgnetCompat source code to solve this issue.

    Unfortunately, you can't execute '.setCancelable(false)' to dialog without callback or override.

    I'll explain it with callback.

    You should implement 'PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback' interface on activity which contains PreferenceFragmentCompat fragment.

    When user press a preference one of EditTextPreference, ListPreference or AbstractMultiSelectListPreference, the onPreferenceDisplayDialog method will be executed.

    When onPreferenceDisplayDialog method is executed, you should open dialog. Fortunately, there are three type dialog and Google provide it by public so you don't need to make a custom dialog for them.

    Just create instance of dialog and call setCancelable(false) and show it!

    Please refer below codes.


    class SettingsActivity : FragmentActivity(), PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback {
            private val DIALOG_FRAGMENT_TAG = "android.support.v7.preference.PreferenceFragment.DIALOG"
    
            override fun onCreate(savedInstanceState: Bundle?) {
                    super.onCreate(savedInstanceState)
    
                    supportFragmentManager.beginTransaction()
                                    .replace(android.R.id.content, SettingsFragment(), "setting_fragment").commit()
            }
    
            override fun onPreferenceDisplayDialog(caller: PreferenceFragmentCompat, preference: Preference?): Boolean {
                    // check if dialog is already showing
                    if (supportFragmentManager!!.findFragmentByTag(DIALOG_FRAGMENT_TAG) != null) {
                            return true
                    }
    
                    val f: DialogFragment
                    if (preference is EditTextPreference) {
                            f = EditTextPreferenceDialogFragmentCompat.newInstance(preference.getKey())
                    } else if (preference is ListPreference) {
                            f = ListPreferenceDialogFragmentCompat.newInstance(preference.getKey())
                    } else if (preference is AbstractMultiSelectListPreference) {
                            f = MultiSelectListPreferenceDialogFragmentCompat.newInstance(preference.getKey())
                    } else {
                            throw IllegalArgumentException("Tried to display dialog for unknown " + "preference type. Did you forget to override onDisplayPreferenceDialog()?")
                    }
    
                    f.setTargetFragment(supportFragmentManager.findFragmentByTag("setting_fragment"), 0)
    
                    f.isCancelable = false // !! HERE !!
    
                    f.show(supportFragmentManager!!, DIALOG_FRAGMENT_TAG)
    
                    return true
            }
    }