RingtonePreference not firing onSharedPreferenceChanged - android

My Preferences all trigger the onSharedPreferenceChanged event upon a change. It works for all preferences: Checkbox, List, custom, etc. But it won't be called if I select a ringtone from the RingtonePreference. I have this code:
<CheckBoxPreference android:title="#string/pref_notification"
android:defaultValue="true" android:summary="#string/pref_notification_summary"
android:key="prefNotification" />
<RingtonePreference android:title="#string/pref_ringtone"
android:key="prefRingtone"
android:summary="#string/pref_ringtone_summary" android:ringtoneType="all" />
<CheckBoxPreference android:title="#string/pref_vibrate"
android:defaultValue="true" android:summary="#string/pref_vibrate_summary"
android:key="prefVibrationOn" />
<ListPreference android:title="#string/pref_notification_interval"
android:summary="#string/pref_notification_interval_summary"
android:key="prefNotificationInterval" android:defaultValue="60"
android:entries="#array/prefs_interval" android:entryValues="#array/prefs_interval_values" />
And my class:
public class TimePrefsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
addPreferencesFromResource(R.layout.preferences);
Preference dbPref = (Preference) findPreference("prefDeleteDb");
dbPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference)
{
showWipeDbDialog();
return true;
}
});
}
#Override
public void onResume() {
super.onResume();
prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.registerOnSharedPreferenceChangeListener(this);
toggleEnableList();
}
#Override
public void onPause() {
prefs.unregisterOnSharedPreferenceChangeListener(this);
super.onPause();
}
#Override
public void onSharedPreferenceChanged(SharedPreferences arg0, String arg1)
{
boolean enabled = toggleEnableList();
if (enabled)
{
OnBootReceiver.setAlarm(TimePrefsActivity.this);
}
else
{
OnBootReceiver.cancelAlarm(TimePrefsActivity.this);
}
}
}
All the preferences, except the RingtonePreference, reach method onSharedPreferenceChanged. Does anyone have an idea? Thanks.

I struggled with the same problem which seems to be a bug in the android system.
After debugging the code I noticed the listener is not added to our RingtonePreference listeners map, unlike other classes like ListPreference.
I opened a ticket, but for now I found a way to overcome it using OnPreferenceChangeListener.
My code sets the preference summary to the selected ringtone, you can use your logic instead.
First make your activity implement OnPreferenceChangeListener and write the onPreferenceChange method
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
updateRingtoneSummary((RingtonePreference) preference, Uri.parse((String) newValue));
return true;
}
private void updateRingtoneSummary(RingtonePreference preference, Uri ringtoneUri) {
Ringtone ringtone = RingtoneManager.getRingtone(this, ringtoneUri);
if (ringtone != null)
preference.setSummary(ringtone.getTitle(this));
else
preference.setSummary("Silent");
}
Notice that unlike onSharedPreferenceChanged, onPreferenceChange is called before the preference is updated, so you must use the newValue parameter to get the selected data instead of getting it from the preference.
Then, set the listener on OnResume:
#Override
protected void onResume() {
super.onResume();
// A patch to overcome OnSharedPreferenceChange not being called by RingtonePreference bug
RingtonePreference pref = (RingtonePreference) findPreference(getString(R.string.pref_ringtone));
pref.setOnPreferenceChangeListener(this);
}
Hope this helps.

I also thought this was a bug in the system at first, but the issue is actually more subtle. RingtonePreference launches a new activity via an intent. This means that your PreferenceActivity gets paused. And you're unregistering your listener in onPause(). If you don't do this, it'll work fine (at least it did for me).
But naturally, you can't have your handler stay registered forever. I compromised by using onStart()/onStop() instead of onResume()/onPause().

I had to manually set the OnPreferenceChangeListener myself on my SettingsFragment:
Preference notificationSoundPref = findPreference(Constants.PREFS_NOTIFICATION_SOUND);
notificationSoundPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
// do what you need here
return true;
}
});

Related

setDefaultNightMode() only works after second call in PreferenceFragment

I am working to implement a dark mode into my app. Right now I try to switch the UI mode between light and dark using a PreferenceFragment nested inside an AppCompatActivity. The App behaves like this, starting from the light theme as a default value:
If I select 'dark' in the ListPreference, the summary of the
preference changes, but the UI stays light in this and all the other activities.
If I select 'dark' a second time, the activity switches to dark theme, as well as the other activities in the backstack.
The same thing happens in reverse, when I want to switch back to the light theme.
So basically everything works, but you have to select the desired value in the ListPreference twice. The code for the ListPreference:
final Preference listPreferenceDesign = findPreference(PREF_DESIGN);
listPreferenceDesign.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object o) {
if (((ListPreference) preference).getValue().equals("light")) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
} else if (((ListPreference) preference).getValue().equals("dark")) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
}
return true;
}
});
What I tried so far:
Call getActivity.recreate()before the return true; statement
Call getActivity.recreate()after a short delay using a Handler
Call this.recreate() in the onResume() method of the parent Activity when a boolean changedDesignSetting was true
I am thankful for further help.
I finally get it to work using an OnSharedPreferenceChangeListener in the parent activity. Now the code in the parent activity goes like this:
getFragmentManager().beginTransaction().replace(R.id.settingsPlaceholderID, preferenceFragment).commit();
SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(PREF_DESIGN)) {
if (sharedPreferences.getString(key, "light").equals("light")) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
}
}
}
};
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
And in the PreferenceFragment I only have:
final Preference listPreferenceDesign = findPreference(PREF_DESIGN);
listPreferenceDesign.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object o) {
return true;
}
});

Android: SettingsActivity, confirm password?

I have a settingsactivity and I have a edittext with a passwordfield.
I only contains 4 numbers and numbers only.
How, when the user clicks this, can I make the user be forced to confirm the old password before entering a new one?
Activity:
addPreferencesFromResource( R.xml.pref_general );
res/xml/pref_general.xml
<PreferenceCategory android:title="#string/settings_general">
<EditTextPreference
android:title="#string/settings_password"
android:key="example_password"
android:summary="****"
android:textColor="#color/textColor"
android:textColorHint="#color/hintColor"
android:inputType="number"
android:maxLength="4"
/>
</PreferenceCategory>
How can I find the items so that I can put my own onClickListener's on them?
Edit: I found this method, currently trying to figure this out..
private static Preference.OnPreferenceClickListener onPreferenceClickListener = new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick( Preference preference ) {
return false;
}
};
You can register a listener within your PreferenceActivity:
#Override
public void onResume() {
super.onResume();
getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
#Override
public void onPause() {
getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
super.onPause();
}
#Override
public void onSharedPreferenceChanged( SharedPreferences sharedPreferences, String key) {
Log.i("onSharedPreferenceChanged", "preference changed: " + key);
}
I noticed this from another question from searching a bit more.
Preference myPref = ( Preference ) findPreference( "password" );
myPref.setOnPreferenceClickListener( new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick( Preference preference ) {
Log.e("App", "password clicked!");
return true;
}
} );
Works!
Edit: This would probably have to be in the onPostCreate() method because it needs to be initialized before you can set any sort of listeners to it (or even find the object).

Enable and disable option in PreferenceActivity

I am new to creating PreferenceActivity. My question is how to enable and disable option in preference screen by changing other preference?
My prefs.xml:
<ListPreference
android:entries="#array/units"
android:entryValues="#array/lunits"
android:key="listUnits"
android:summary="Units schosssing"
android:title="Units" android:defaultValue="C"/>
<ListPreference
android:entries="#array/palette"
android:entryValues="#array/lpalette"
android:key="listpalette"
android:summary="Palette schosssing"
android:title="Palette"
android:defaultValue="1"/>
In the listUnits there are 2 options, Celsius and Fahrenheit, so if user selects Celsius the listpalette should get enabled, and if user selects Fahrenheit becomes disabled, how can I do this?
My settings activity:
public class SettingsActivity extends PreferenceActivity
{
#Override
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment()).commit();
}
public static class MyPreferenceFragment extends PreferenceFragment
{
#Override
public void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.prefs);
}
}
}
This code may be useful to you. Can take as reference.
First take instance of both of the ListPreference and apply this method.
ListPreference mlistUnits, mlistPalette;
mlistUnits= (ListPreference)findPreference("listUnits");
mlistPalette= (ListPreference)findPreference("listpalette");
mlistUnits.setEnable(false);
mlistPalette.setEnabled(true);
and use below listner
OnPreferenceChangeListener listener = new OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
// newValue is the value you choose
return false;
}
};
apply listener to ListPreference
mlistPalette.setOnPreferenceChangeListener(listener);
Firstly you can set default value for your listUnits listpreference to celcius or Fahrenheit ,according this you can make enable-disable your second listpreference.
Now when changing your Preference by selecting anyone of them you can follow below procedure.
1) implement OnSharedPreferenceChangeListener in your MyPreferenceFragment class and override the method onSharedPreferenceChanged
2) Code like below in your method
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
// TODO Auto-generated method stub
if (key.equals("listUnits")) {
final String value = sharedPreferences.getString(key, "");
Preference Pref_cec=findPreference("listpalette");
if (value.equals("celcius")) {
wallpaperPref_admin.setEnabled(true);
}else{
wallpaperPref_admin.setEnabled(false);
}
}
}
Hope it will Help. Let me know if anything missing in my post.
As your second list is evaluated on basic of first list, what you may do
Look for preference click on the First list, get the value of preference clicked.
Using this value simply enable/disable your second list.

Android: Updating sharedPreferences Summary via listener

I am having a few issues with updating the summary line in the SharedPreferences as a preference changes. I have a registered OnSharePreferenceChangeListener in the onResume(), and an unregister of the same in the onPause().
The listener is functioning, and I am able to use the onSharedPreferenceChanges() method. The issue I am having is being able to retrieve the preference there so that I can call setSummary(). I am in Ice Cream Sandwich, and it appears as though the findPreference(key) method is deprecated. So:
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Preference pref = findPreference(key);}
is not functioning, and actually returns null for pref. From the examples I have seen, you need to get a preference to call setSummary() on it, and ideas?
You shouldn't use an onSharedPreferenceChangedListener for this.
Instead, use something similar to this.
ListPreference myPreference = (ListPreference) findPreference("preference_key");
myPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (((String)newValue).equals("some_value")) {
preference.setSummary("my summary");
}
}
});
findPreference is not deprecated, but rather you shouldn't be using a PreferenceActivity (that is deprecated). If you only need to support Android 3.0+ then you should switch to PreferenceFragment's, the new method. If you need to support Android 2.1+ then it is fine and you can ignore the warnings.
I have been trying to use PreferenceFragment in my code, and I was also seeing findPreference(key) return null. The sample code on the Settings documentation page for using OnSharedPreferenceChangeListener hasn't been fully updated for PreferenceFragment and you'll crash with NullPointerException if you use it verbatim.
I finally figured it out: You have to find the Preference via the PreferenceFragment because of course that's where the preferences are now. Obvious in hindsight. Something like this:
public class SettingsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener
{
protected SettingsFragment settingsFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
settingsFragment = new SettingsFragment();
getFragmentManager().beginTransaction().replace(android.R.id.content, settingsFragment).commit();
}
// ...
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals("your_key")) {
String newValue = sharedPreferences.getString(key, "");
settingsFragment.findPreference(key).setSummary(newValue);
}
}
}

OnPreferenceChangeListener for every setting

I know that I can do something like this:
Preference pref = findPreference(getString(R.string.pref_vibrate_on_key));
pref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference,
Object newValue) {
LogUtil.d("Working!");
return true;
}
});
But I would like to add a Listener to every preference.
I tried doing:
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
sp.registerOnSharedPreferenceChangeListener(new OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged(
SharedPreferences sharedPreferences, String key) {
LogUtil.d("working!");
}
});
but it doesn't work.
Is this possible? If so, what am I doing wrong?
Assuming you want the same listener called each time, this might be a simpler solution:
Preference.OnPreferenceChangeListener changeListener = new Preference.OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
// Code goes here
return true;
}
};
EditTextPreference pref = (EditTextPreference)findPreference(getString(R.string.pref1));
pref1.setOnPreferenceChangeListener(changeListener);
EditTextPreference pref2 = (EditTextPreference)findPreference(getString(R.string.pref2));
pref2.setOnPreferenceChangeListener(changeListener);
I think that onSharedPrefererenceChanged is fired upon saving the preference (when you click BACK or HOME in PreferenceActivity). I think that the easiest way is to create single class implementing OnPreferenceChangeListener and switch through Preference.getKey(); and set it as OnPreferenceChangeListener for each Preference.

Categories

Resources