I am facing a problem while trying to consume click event of a preference. There's a preference, and on clicking it, I open a sub screen with different preference categories. What I want to achieve is that if a certain condition is false, a toast should popup, and the sub screen shouldn't open. In case it's true, it should work normally and open the sub screen. For this, I tried the following piece of code :
mPref = (Preference) findPreference("abc");
mPref.setOnPreferenceClickListener(this);
#Override
public boolean onPreferenceClick(Preference preference) {
// TODO Auto-generated method stub
if (!condition) {
Toast.makeText(getActivity(), "Error", Toast.LENGTH_SHORT).show();
return true; // Consume click event.
}
return false;
}
The relevant part of xml is as follows:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
android:key="abc"
android:summary="#string/string_turn_on"
android:textColor="#android:color/white"
android:title="#string/string_turn_on">
<PreferenceCategory
android:key="asa"
android:title="a" >
<com.example.gaurav.CustomPref
android:defaultValue="0"
android:key="st"
android:dependency="e"
android:showDefault="true"
android:summary="summary"
android:title="t" />
<com.example.gaurav.CustomPref
android:defaultValue="0"
android:key="st"
android:dependency="e"
android:showDefault="true"
android:summary="so"
android:title="so" />
</PreferenceCategory>
<PreferenceCategory
android:title="other" >
<CheckBoxPreference
android:defaultValue="false"
android:key="e"
android:title="eb" />
</PreferenceCategory>
</PreferenceScreen>
I have changed the strings etc, but I don't think they cause this error, so it won't matter. It's the preference with key "abc" which launches a sub screen which I want to prevent from launching. Any help regarding this would be appreciated.
try adding this line in the onCreate method
addPreferencesFromResource(R.xml.preferences);
edit:
#Override
public boolean onPreferenceClick(Preference preference) {
if (condition) {
return true; // Consume click event.
}
Toast.makeText(getActivity(), "Error", Toast.LENGTH_SHORT).show();
return false;
}
I've just had this problem and I solved it creating a custom Preference class which overrides onClick event and setOnPreferenceClickListener
This is the custom class:
public class InterceptableEditTextPreference extends EditTextPreference {
private OnPreferenceClickListener customOnPreferenceClickListener;
public InterceptableEditTextPreference(Context context) {
super(context);
}
public InterceptableEditTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public InterceptableEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onClick() {
if (customOnPreferenceClickListener != null) {
boolean handled = customOnPreferenceClickListener.onPreferenceClick(this);
if (handled) {
return;
}
}
super.onClick();
}
#Override
public void setOnPreferenceClickListener(OnPreferenceClickListener onPreferenceClickListener) {
customOnPreferenceClickListener = onPreferenceClickListener;
}
}
This way when you set the listener, the returned value is taken into account to continue with the default click behaviour (show the dialog) or not:
editTextPreference.setOnPreferenceClickListener(preference -> {
if(someCondition) {
return true; // This prevent the PreferenceDialog to appear
// To manually show the dialog you can call:
// getPreferenceManager().showDialog(preference);
}
return false;
});
Explanation
The previous "workaround" should be the default behaviour but for some reason, analyzing the SDK Preference class we find this:
Which means onClick() is always called (if the preference is enabled and selectable) and not depend on the boolean value returned by mOnClickListener.onPreferenceClick
Related
I have some preferences in my preference screen:
<PreferenceCategory
android:key="category"
android:summary="Category"
android:title="Category">
<Preference
android:key="pref1"
android:summary="desc"
android:title="Pref 1" />
<Preference
android:key="pref2"
android:summary="desc"
android:title="Pref 2" />
</PreferenceCategory>
Finding them in PreferenceActivity:
Preference pref1, pref2;
#Override
protected void onCreate(final Bundle savedInstanceState) {
pref1 = findPreference("pref1");
pref2 = findPreference("pref2");
}
And set some OnPreferenceClickListener to them. How do I correctly define which preference was clicked? I'd like to do it in case-switch style, but I cannot figure out which types should I use:
Preference.OnPreferenceClickListener listener = new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
switch (???){ //I guess, here goes the "preference"?
case ???: //getting error with pref1 or pref2
}
return false;
}
}
If I put preference from onPreferenceClick in switch(), I will get errors with case.
You can get the corresponding preference like
#Override
public boolean onPreferenceClick (Preference preference)
{
String key = preference.getKey();
// do what ever you want with this key
}
ref: Preference Activity on Preference Click Listener
hope this helps :)
You can use the field key of Preference
public boolean onPreferenceClick(Preference preference) {
if (preference.getKey().equals("pref1")) {
... do something ...
} else if (preference.getKey().equals("pref2")) {
... do something ...
}
return true;
}
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).
I am building a Preference Activity where most of the preferences in the list will be executing code and not modifying a SharedPreference directly. My preferences.xml file looks like this.
<PreferenceCategory
android:title="Connection" >
<Preference
android:id="#+id/settings_connectToNewComputer"
android:key="connectToNewComputer"
android:summary="Currently connected to:"
android:title="Connect to new computer" />
<Preference
android:id="#+id/removeDevice"
android:key="removeDevice"
android:summary="Remove this device from the computer's whitelist"
android:title="Remove this device from computer" />
</PreferenceCategory>
<PreferenceCategory
android:title="About" >
<Preference
android:id="#+id/settings_About"
android:key="about"
android:summary="About me and my thanks to those who made this app great"
android:title="About Hue Pro" />
<Preference
android:id="#+id/contact"
android:key="contact"
android:summary="Contact me with comments, bugs, and suggestions for updates"
android:title="Contact me" />
</PreferenceCategory>
My goal is to have a block of code executed when a one of these preferences are clicked. Similar to the "Clear search history" in the Google Play settings preference menu. (http://i.imgur.com/qnHbJX9.png)
Does anyone know how to make this possible?
I have to add that I have tried using findPreference("KeyNameHere") but it always returns null.
Thank you!
Edit:
I added in this code and implemented OnPreferenceClickListener:
#Override
public boolean onPreferenceClick(Preference preference) {
return false;
}
But this method never gets called. Is there another way to do this?
Edit 2:
I have found that if I take out the PreferenceCategory tags so I am left with this:
<Preference
android:id="#+id/settings_connectToNewComputer"
android:key="connectToNewComputer"
android:summary="Currently connected to:"
android:title="Connect to new computer" />
<Preference
android:id="#+id/removeDevice"
android:key="removeDevice"
android:summary="Remove this device from the computer's whitelist"
android:title="Remove this device from computer" />
<Preference
android:id="#+id/settings_About"
android:key="about"
android:summary="About me and my thanks to those who made this app great"
android:title="About Hue Pro" />
<Preference
android:id="#+id/contact"
android:key="contact"
android:summary="Contact me with comments, bugs, and suggestions for updates"
android:title="Contact me" />
and call this:
getPreferenceScreen().setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
return false;
}
});
then I actually get a response from the click event. The only down side is I have to remove the preference grouping. Anyone know why this is and any way to fix it?
Implement OnPreferenceClickListener and in the onPreferenceClick
#Override
public boolean onPreferenceClick (Preference preference)
{
String key = preference.getKey();
// do what ever you want with this key
}
Maybe this could not be useful for OP, but could be useful for someone else.
I'd like to write a sort of summary; in general, you can follow mainly three ways:
1) you can find your preference somewhere in your code with
Preference examplePreference = findPreference(KEY_EXAMPLE_PREFERENCE);
and then you can add a click listener and override its on click method with
examplePreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
// handle click here
}
});
This has to be done for every preference whose clicks you want to listen to
2) You can implement Preference.OnPreferenceClickListener interface in your settings fragment/activity and override onPreferenceClick just once, by using a switch construct or a if-else if-else if-... construct and merging all the single handlings; it should be something like:
#Override
public boolean onPreferenceClick(Preference preference) {
switch (preference.getKey()) {
case KEY_EXAMPLE_PREFERENCE: {
// handle click here
}
break;
case ...
}
}
Then, you still have to find each preference but you can simply call on each of them
setOnPreferenceClickListener(this);
(I think the OP's implementation didn't work (his method wasn't called) because of this last part)
we pass "this" as parameter because we implemented the click listener interface
3) (which I think is the easiest) you can override
onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)
in your preference fragment/activity without implementing any other interface and there you can copy the switch of the if-else if-... construct of option 2); the main advantage in that you shouldn't need to find each preference and to call on them setOnPreferenceClickListener.
Hope this will be useful for someone!
Just override:
#Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
String key = preference.getKey();
...
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
You could also find the preference and set the click listener.
Preference connectToNewComputer= findPreference("connectToNewComputer");
connectToNewComputer.setOnPreferenceClickListener(this);
For Androidx in Feb 2020
Others answers were not worked in Androidx for me. I implemented Settings from Android Developers guides
See below guide for implementing click listener
1) Implement PreferenceManager.OnPreferenceTreeClickListener in your settings fragment, like below code
import androidx.preference.PreferenceManager;
class SettingsFragment extends PreferenceFragmentCompat implements PreferenceManager.OnPreferenceTreeClickListener {
2) Override onPreferenceTreeClick inside your SettingsFragment
#Override
public boolean onPreferenceTreeClick(Preference preference) {
String key = preference.getKey();
switch (key) {
case "key1":
return true;
case "key2":
return true;
//codes
}
}
I came up with my own (what I believe is really messed up) solution; but it works.
for(int x = 0; x < getPreferenceScreen().getPreferenceCount(); x++){
PreferenceCategory lol = (PreferenceCategory) getPreferenceScreen().getPreference(x);
for(int y = 0; y < lol.getPreferenceCount(); y++){
Preference pref = lol.getPreference(y);
pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener(){
#Override
public boolean onPreferenceClick(Preference preference) {
return false;
}
});
}
}
So what I have learned is there is a hierarchical system that works like: PreferenceScreen has children PreferenceCategory has children Preference, as you can see in the XML file. My problem was I could not set the preferences' onClickListeners directly from the PreferenceScreen. So I made two for loops that will get down to each Preference and set an OnPreferenceClickListener for each and every one of them. Messy, but works finally.
Your Preference object wont get null if you will find followings
(copypasting from the project):
public class ImePreferences extends PreferenceActivity {
.....
#Override
protected boolean isValidFragment(String fragmentName) {
return Settings.class.getName().equals(fragmentName);
}
.....
public static class Settings extends InputMethodSettingsFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setInputMethodSettingsCategoryTitle(R.string.language_selection_title);
setSubtypeEnablerTitle(R.string.select_language);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.ime_preferences);
Preference pLcl = getPreferenceScreen().findPreference(getResources().getString(
R.string.dictionary_button));
pLcl.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
// handle click here
l.a("this is the click");
return true;
}
});
if(pLcl != null)
l.a(6576);
}
}
.....
}
For Kotlin
your xml should look like this
<Preference
app:title="Contact me"
app:key="contact"/>
do not forget the key.
Then in your Settings Activity find this class
class SettingsFragment : PreferenceFragmentCompat()
and add this code
override fun onPreferenceTreeClick(preference: Preference): Boolean {
val key = preference.key
return super.onPreferenceTreeClick(preference)
}
When you are done your code should look like this
class SettingsFragment : PreferenceFragmentCompat() {
override fun onPreferenceTreeClick(preference: Preference): Boolean {
val key = preference.key
return super.onPreferenceTreeClick(preference)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
}
}
I've been trying to get a switch preference working in Android whereby I can intercept and handle differently, in certain cases, when they switch it on/off vs when they click the whole preference.
This is what I'm trying to accomplish:
User goes into preferences tags are off and no tags are stored (ie: tag preference is empty)
User turns on preference for tags, and since no tags are stored currently it launches a tag search activity for user to find the tag. - works fine.
If tag already exists, and they change the state ONLY then update the value as normal. - works fine
Here's my issue:
If they click the preference though and they already have a tag saved, don't change the state (regardless if it's enabled or disabled), launch the tag search activity. - this DOESN'T work.
What I've found so far is that in the final scenario above, I get a call to onPreferenceChanged, followed by a call to onPreferenceClicked, followed by a subsequent call to onPreferenceChanged. This seems to be my problem. The first call to onPreferenceChanged causes my listener on my SharedPreferences to be called telling it that it's now enabled.
If I didn't receive the first call to onPreferenceChanged then I wouldn't have an issue.
Here is the relevant parts where I'm setting the listeners
SwitchPreference tagPref = (SwitchPreference) findPreference(PreferencesConstants.PREFERENCE_TAG_ENABLED);
tagPref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
Log.e("BLAH", "onPrefChanged....is it handled by OnClick?" + Boolean.toString(handledByClick));
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
boolean enabled = prefs.getBoolean(PreferencesConstants.PREFERENCE_TAG_ENABLED, false);
Log.e("BLAH", "value stored in prefs? " + Boolean.toString(enabled));
if (newValue instanceof Boolean) {
enabled = (Boolean) newValue;
}
Log.e("BLAH", "New value? " + Boolean.toString(enabled));
if (!handledByClick) {
if (enabled && (currentTag == null || currentTag.isEmpty())) {
Log.e("BLAH", "Enabled and CurrentTag empty!");
Intent intent = new Intent(getActivity(), TagSearchActivity.class);
startActivityForResult(intent, 0);
return false; // always return false, we'll handle
// updating
// this value manually.
} else {
return true;
}
}
Log.e("BLAH", "returning false (AS IN WE HANDLED IT).");
return false;
}
});
tagPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
handledByClick = true;
Log.e("BLAH", "onprefClick");
Intent intent = new Intent(getActivity(), TagSearchActivity.class);
startActivityForResult(intent, 0);
return true;
}
});
Here are the relevant log lines after running it with a saved tag, and clicking the preference.
01-18 15:55:05.593: E/BLAH(13261): onPrefChanged....is it handled by OnClick?false
01-18 15:55:05.593: E/BLAH(13261): value stored in prefs? true
01-18 15:55:05.593: E/BLAH(13261): New value? false
01-18 15:55:05.613: E/DifferentClass(13261): On Shared Preferences Changed - tagEnabled
01-18 15:55:05.652: E/DifferentClass(13261): disabled TAG in cancelAlarmService
01-18 15:55:05.662: E/AnotherClass(13261): Updating Feed List. Old Size: 33, New Size: 14
01-18 15:55:05.682: E/BLAH(13261): onprefClick
01-18 15:55:05.812: E/BLAH(13261): onPrefChanged....is it handled by OnClick?true
01-18 15:55:05.812: E/BLAH(13261): value stored in prefs? false
01-18 15:55:05.822: E/BLAH(13261): New value? false
01-18 15:55:05.822: E/BLAH(13261): returning false (AS IN WE HANDLED IT).
I have been working with the same issue for ages now and you can go about it two ways.
Implementing a switchpreference with custom actions for every event:
forevercrashed made some good points. I tried follow them, but for me they didn't do it. I bet they work, but I needed more functionallity in an easier way. Xgouchet (second Link) uses Headers and custom xml layouts which uses custom placements and measurements (height, witdth, padding etc.). I needed a solution without altering Googles built in auto-generated layout.
The super easy and powerful way: implement your own SwitchPreference!
Just make a class extend SwitchPreference and then implement/override like so:
public class AutoUploadSwitchPreference extends SwitchPreference {
public AutoUploadSwitchPreference(Context context) {
super(context);
}
public AutoUploadSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AutoUploadSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onClick() {
//super.onClick(); THIS IS THE IMPORTANT PART!
}
By overriding onClick() and commenting out / deleting super.onClick() makes the SwitchPreference NOT call callChangeListener(Object newValue). Now you can click the preference and nothing happens, not until you want it to.
(One bug that would occur otherwise was having multiple calls to onPreferenceChange in the fragment)
Now! To make things happen: Here is the structure I have used.
Create a SettingsActivity
In it make sure you fetch preferences, resources etc.
in onCreate() in your Activity - launch a PreferenceFragment
This needs to be a custom class extending PreferenceFragment, see how here : PreferenceFragment
In your custom Fragment, get hold of your custom-preference. You can use findPreference("custom_switch_key").
add an OnPreferenceChangeListener on the preference
I personally make my fragment implement the listener and pass this as argument.
The return statement is important. This is what makes the actual change in the switch. If you return true the switch will change into the newValue. If you return false, it will not. If you use return false; you can change the value with setChecked(true|false) on the switchpreference.
when you implement onPreferenceChange(Preference preference, Object newValue) you can add whatever functionality you want from pressing the switch-slider only
the functionality from clicking the preference can be done in three ways:
Implement the onClick() further in the custom SwitchPreference class
Implement the method onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) in the fragment
Implement an onPreferenceClickListener like you did for the ChangeListener.
Sorry if this is a long post. It is my first and I have been through so many stackoverflow-pages about this and no one was accurate, just wanted to get it right ;)
After searching for hours more I came across a couple posts that will be helpful to others in this situation.
This one was the solution I opted for given my problem: How do I create one Preference with an EditTextPreference and a Togglebutton?
It's a very detailed answer and is very helpful in understanding preferences.
The other post I came across was this one: http://xgouchet.fr/android/index.php?article4/master-on-off-preferences-with-ice-cream-sandwich
It will give you pretty much the same look and feel as the one above, but requires more work and because of my requirements wouldn't work for me.
i think you are asking about a feature that doesn't exist.
however , since the preference activity uses a listView , you can use some tricks to customize it and handle it however you wish .
here's a post i've made about customizing it , based on this website . what i've asked there is how to add a listView , but i didn't know that a preference activity actually uses a listview .
This took me ages, and none of the answers here worked. I finally found the simplest answer, no custom layout required, in a Github Gist, which I'll preserve here, but I have modified it to work with SwitchPreferenceCompat instead of SwitchPreference.
First, create the custom preference.
package com.mendhak.gpslogger.ui.components;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import androidx.appcompat.widget.SwitchCompat;
import androidx.preference.PreferenceViewHolder;
import androidx.preference.SwitchPreferenceCompat;
/**
* Custom preference for handling a switch with a clickable preference area as well
*/
public class SwitchPlusClickPreference extends SwitchPreferenceCompat {
//
// Public interface
//
/**
* Sets listeners for the switch and the background container preference view cell
* #param listener A valid SwitchPlusClickListener
*/
public void setSwitchClickListener(SwitchPlusClickListener listener){
this.listener = listener;
}
private SwitchPlusClickListener listener = null;
/**
* Interface gives callbacks in to both parts of the preference
*/
public interface SwitchPlusClickListener {
/**
* Called when the switch is switched
* #param buttonView
* #param isChecked
*/
public void onCheckedChanged(SwitchCompat buttonView, boolean isChecked);
/**
* Called when the preference view is clicked
* #param view
*/
public void onClick(View view);
}
public SwitchPlusClickPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public SwitchPlusClickPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SwitchPlusClickPreference(Context context) {
super(context);
}
//
// Internal Functions
//
/**
* Recursively go through view tree until we find an android.widget.Switch
* #param view Root view to start searching
* #return A Switch class or null
*/
private SwitchCompat findSwitchWidget(View view){
if (view instanceof SwitchCompat){
return (SwitchCompat)view;
}
if (view instanceof ViewGroup){
ViewGroup viewGroup = (ViewGroup)view;
for (int i = 0; i < viewGroup.getChildCount();i++){
View child = viewGroup.getChildAt(i);
if (child instanceof ViewGroup){
SwitchCompat result = findSwitchWidget(child);
if (result!=null) return result;
}
if (child instanceof SwitchCompat){
return (SwitchCompat)child;
}
}
}
return null;
}
#Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
final SwitchCompat switchView = findSwitchWidget(holder.itemView);
if (switchView!=null){
switchView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener != null)
listener.onCheckedChanged((SwitchCompat) v, ((SwitchCompat)v).isChecked());
}
});
switchView.setChecked(getSharedPreferences().getBoolean(getKey(),false));
switchView.setFocusable(true);
switchView.setEnabled(true);
//Set the thumb drawable here if you need to. Seems like this code makes it not respect thumb_drawable in the xml.
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener!=null) listener.onClick(v);
}
});
}
// //Get a handle on the 2 parts of the switch preference and assign handlers to them
// #Override
// protected void onBindView (View view){
// super.onBindView(view);
//
// final Switch switchView = findSwitchWidget(view);
// if (switchView!=null){
// switchView.setOnClickListener(new View.OnClickListener() {
// #Override
// public void onClick(View v) {
// if (listener != null)
// listener.onCheckedChanged((Switch) v, ((Switch)v).isChecked());
// }
// });
// switchView.setChecked(getSharedPreferences().getBoolean(getKey(),false));
// switchView.setFocusable(true);
// switchView.setEnabled(true);
// //Set the thumb drawable here if you need to. Seems like this code makes it not respect thumb_drawable in the xml.
// }
//
// view.setOnClickListener(new View.OnClickListener() {
// #Override
// public void onClick(View v) {
// if (listener!=null) listener.onClick(v);
// }
// });
// }
}
Next in your preference XML, add an entry:
<com.mendhak.gpslogger.ui.components.SwitchPlusClickPreference
android:key="google_drive_enabled"
android:title="#string/google_drive_setup_title"
android:icon="#drawable/googledrive"/>
And then in the code for your Preference Activity class, the real magic is that you use the built-in callbacks for changed, and clicked.
((SwitchPlusClickPreference)findPreference(PreferenceNames.AUTOSEND_GOOGLE_DRIVE_ENABLED)).setSwitchClickListener(new SwitchPlusClickPreference.SwitchPlusClickListener() {
#Override
public void onCheckedChanged(SwitchCompat buttonView, boolean isChecked) {
//The switch bit changed. handle it.
}
#Override
public void onClick(View view) {
// The text bit was clicked on, handle it
}
});
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;
}
});