androidandroidxpreferencescreen

Modifying a preference value in a PreferenceScreen by code


I have a PreferenceScreen following the docs here and here.

One of the options is a SwitchPreferenceCompat that does some risky work in my app, for example, to send sensitive information periodically. This is the simple switch:

<SwitchPreferenceCompat
            app:key="SendInfoToServer"
            app:title="Send information on your device to our servers" />

What I need, is to ask the user with a question like this:

This will periodically send sensitive information of your device to our servers. Are you sure you want to enable this option?

If the user answer YES then I want the SwitchPreferenceCompat to get activated, otherwise not.

I have investigated a bit a I found this code:

    findPreference("SendInfoToServer").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            if((boolean) newValue == true){
                Toast("Activating this function will safe sensitive information");
            }
            return true;
        }
    });

But this message is just a warning message being displayed to the user. What I am trying to achieve is to prompt a question. If the user agrees then the switch should be turned ON, if the user doesn't agree then the switch should remain OFF.

Any ideas on how to do that.


Solution

  • You can modify it using the isChecked method. Here is an example doing that with a popup dialog like you described. This uses the onPreferenceChangeListener, and if the option is being disabled it shows a dialog and returns false for the listener (so the preference not immediately updated).

    If the user selects the right option in the dialog then it gets disabled using the isChecked method. The dialog would not be shown if the option is being re-enabled, only when it gets disabled.

    Some of the logic might be reversed if you wanted to show the dialog when the option is enabled, but the concept overall is the same. The key is to return false when showing the dialog so it doesn't change, then change it later with isChecked if the user confirms they want to change it.

    // replace this with getting the switch if you defined it in the XML
    val enableChecks = SwitchPreference(context)
    enableChecks.key = Constants.ENABLE_CHECKS
    enableChecks.title = getString(R.string.enable_checks)
    enableChecks.isPersistent = true
    
    
    enableChecks.onPreferenceChangeListener =
        Preference.OnPreferenceChangeListener { _, value ->
    
            val disabling = !(value as Boolean)
            if( disabling ) {
                SimpleDialogs.twoButton(
                    context,
                    title = getString(R.string.confirm_disable_check),
                    message = getString(R.string.confirm_disable_check_msg),
                    posButton = getString(R.string.disable),
                    negButton = getString(R.string.cancel),
                    onPos = {
                        // user confirmed they want to disable it, set to false
                        enableChecks.isChecked = false
                    },
                    onNeg = {
                        // user changed their mind, keep it true
                        enableChecks.isChecked = true
                    },
                    icon = SimpleDialogs.ICON_WARNING
                )
    
                // return false so the change isn't applied here if showing a dialog
                false
            }
            else {
                true
            }
        }
    
    appearanceCat.addPreference(enableChecks)