Modifying a preference value in a PreferenceScreen by code

427 views Asked by At

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.

2

There are 2 answers

1
Tyler V On BEST ANSWER

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)
0
Ton On

Similar answer in Java based on Tyler V answer:

    SwitchPreferenceCompat oSwitchPreferenceCompat = findPreference("MyKey");
    oSwitchPreferenceCompat.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            if((boolean) newValue == false){
                return true; //If the check is disabled we do not need to ask the user. In this case we allow the normal flow and let the system disable it. Returning "true" allows the System to disable it.
            }
            //Here the user is enabling the check, so we prompt to confirm it:
            AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
            builder.setMessage("Are you sure you want to enable this?");
            builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    oSwitchPreferenceCompat.setChecked(true);
                }
            });
            builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int which) {
                    oSwitchPreferenceCompat.setChecked(false);
                }
            });
            builder.setCancelable(false);
            Dialog d = builder.create();
            d.show();
            return false;//returning false we are telling the System to not modify the check yet.
        }
    });