Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to open or simulate a click on an android Preference, created with XML, programmatically?

I've an android application with preferences declared in XML, loaded with addPreferencesFromResource. The user can open preferences, click on each item and edit them, all works.

One preference I have is:

        <ListPreference android:key="abc"
            android:title="@string/abc"
            android:summary="@string/cde"
            android:persistent="true"/>

How can I show the preference dialog to a user automatically (without the need for the user to go to the preference screen and click on it?).

I tried ( (android.preference.DialogPreference) prefMgr.findPreference( "abc" )).showDialog(null), but is says it is a protected method...? Called it from my main activity (which is a PreferenceActivity), that's why it obviously cannot work. But how else?

EDIT

I just found two threads (1, and 2) with the idea to use findViewById to access the preference, but with no success. It always returns null (does for me, too).

It looks like there is really no possibility to do this from code.

like image 441
Markus Avatar asked Jan 26 '11 14:01

Markus


5 Answers

See the new accepted answer for a much cleaner approach! This was working, but not really the clean way of doing it.


Damn it, it got me several hours, but it finally works.

The solution is the undocumented call public void onItemClick (...). It takes several arguments, and as pointed out by this question it can be used to simulate a click according to the index of the element you want to call.

My problem was the item I want to call is deeply nested in an XML-structure. But the solution is very easy: add a key to the PreferenceScreen the item you want to open is in:

<PreferenceScreen
    android:key="pref_key"
    ....
    />
    <ListPreference android:key="abc"
        android:title="@string/abc"
        android:summary="@string/cde"
        android:persistent="true"/>

</PreferenceScreen>

And the you can just to the following:

// the preference screen your item is in must be known
PreferenceScreen screen = (PreferenceScreen) findPreference("pref_key");

// the position of your item inside the preference screen above
int pos = findPreference("abc").getOrder();

// simulate a click / call it!!
screen.onItemClick( null, null, pos, 0 ); 

And the Dialog pops up!

It would be nice to get the PreferenceScreen a Preference is in (so you would not have to know where your Preference is in), because moving the preference/changing the XML could break the automatic dialog silently and might not get noticed (if not tested).

For this I wrote a function which will search through all preferences and return the PreferenceScreen your preference is on, so you don't need to have your PreferenceScreen a key!

private PreferenceScreen findPreferenceScreenForPreference( String key, PreferenceScreen screen ) {
    if( screen == null ) {
        screen = getPreferenceScreen();
    }

    PreferenceScreen result = null;

    android.widget.Adapter ada = screen.getRootAdapter();
    for( int i = 0; i < ada.getCount(); i++ ) {
        String prefKey = ((Preference)ada.getItem(i)).getKey();
        if( prefKey != null && prefKey.equals( key ) ) {
            return screen;
        }
        if( ada.getItem(i).getClass().equals(android.preference.PreferenceScreen.class) ) {
            result = findPreferenceScreenForPreference( key, (PreferenceScreen) ada.getItem(i) );
            if( result != null ) {
                return result;
            }
        }
    }

    return null;
}

private void openPreference( String key ) {
    PreferenceScreen screen = findPreferenceScreenForPreference( key, null );
    if( screen != null ) {
        screen.onItemClick(null, null, findPreference(key).getOrder(), 0);
    }
}

// With this, you can call your `Preference` like this from code, you do
// not even have to give your PreferenceScreen a key!
openPreference( "abc" );
like image 163
Markus Avatar answered Nov 12 '22 14:11

Markus


You could have extended ListPreference to create your dialog, then included your own public method that calls the protected showDialog method of ListPreference. Something like:

public void show()
{
    showDialog(null);
}

This way you won't run into the issue of getOrder() not working when there are PreferenceGroups as several people have pointed out in the comments your answer.

This can be done with any preference types that has a protected showDialog method.

like image 23
Jabari Avatar answered Nov 12 '22 15:11

Jabari


If you use the support library you can open a dialog easily with PreferenceManager.showDialog(Preference).

In your PreferenceFragmentCompat:

getPreferenceManager().showDialog(findPreference("pref_name"));

Note that support preference package has many issues: non-material styling and it crashes when rotated with an open dialog.

like image 10
headsvk Avatar answered Nov 12 '22 16:11

headsvk


 PreferenceScreen preferenceScreen  = (PreferenceScreen) findPreference("pref_key");
    final ListAdapter listAdapter = preferenceScreen.getRootAdapter();
         EditTextPreference editPreference = (EditTextPreference)   findPreference("set_password_preference");

    final int itemsCount = listAdapter.getCount();
    int itemNumber;
    for (itemNumber = 0; itemNumber < itemsCount; ++itemNumber) {
        if (listAdapter.getItem(itemNumber).equals(editPreference)) {
            preferenceScreen.onItemClick(null, null, itemNumber, 0);
            break;
        }
    }
     }
 }  
like image 8
Deepak Goel Avatar answered Nov 12 '22 14:11

Deepak Goel


Improving deepak goel's answer:

private void openPreference(String key) {
    PreferenceScreen preferenceScreen = getPreferenceScreen();
    final ListAdapter listAdapter = preferenceScreen.getRootAdapter();

    final int itemsCount = listAdapter.getCount();
    int itemNumber;
    for (itemNumber = 0; itemNumber < itemsCount; ++itemNumber) {
        if (listAdapter.getItem(itemNumber).equals(findPreference(key))) {
            preferenceScreen.onItemClick(null, null, itemNumber, 0);
            break;
        }
    }
}
like image 4
azendh Avatar answered Nov 12 '22 15:11

azendh