I'm trying to add the possibility to call Intents from a Preference Item.
The Problem I have is that the B4APreference class implements Serializeable and since I want to store an Intent in there this is not possible. Then I tried to change Serializeable to Parcelable since Intents are parcelable Objects. Unfortunately for this you have to implement some additional Methods and I don't know if I have done it correctly.
The class compiles correctly but if I try to use the Library I get a NullPointerException. I think this is because I don't have implemented the CREATOR methods correctly because of the createPreference() abstract method.
I think my Java skills are too bad to solve this. I provide the full source of the class here.
Any Ideas on this? Or is there another way to do this?
The Problem I have is that the B4APreference class implements Serializeable and since I want to store an Intent in there this is not possible. Then I tried to change Serializeable to Parcelable since Intents are parcelable Objects. Unfortunately for this you have to implement some additional Methods and I don't know if I have done it correctly.
The class compiles correctly but if I try to use the Library I get a NullPointerException. I think this is because I don't have implemented the CREATOR methods correctly because of the createPreference() abstract method.
I think my Java skills are too bad to solve this. I provide the full source of the class here.
Any Ideas on this? Or is there another way to do this?
B4X:
// Changes to original PreferencesActivity by Erel:
// v1.0
// - Checkbox can show On and Off summary
// - Dependencies to other entries
// - Second Listview type with Map as key/entry pairs
// - AddPassword()
// - AddRingtone()
//
// v1.01
// - Bugfix for FC with nested PreferencesScreens
// - Trying to add support for custom Intents
package anywheresoftware.b4a.objects;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map.Entry;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceGroup;
import android.preference.PreferenceScreen;
import android.preference.RingtonePreference;
import android.text.method.PasswordTransformationMethod;
import android.widget.EditText;
import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.Author;
import anywheresoftware.b4a.BA.Hide;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.BA.Version;
import anywheresoftware.b4a.keywords.Common;
import anywheresoftware.b4a.objects.collections.List;
import anywheresoftware.b4a.objects.collections.Map;
@Version(1.01f)
@Author("Erel Uziel / Markus Stipp")
public class preferenceactivity extends PreferenceActivity{
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent in = getIntent();
if (in == null || in.hasExtra("preferences") == false) {
Common.Log("Intent missing root node.");
return;
}
PreferenceScreenWrapper p = (PreferenceScreenWrapper) in.getParcelableExtra("preferences");
Common.Log("Nach GetExtra");
PreferenceScreen ps = (PreferenceScreen) p.createPreference(this);
Common.Log("Nach PreferenceScreen");
this.setPreferenceScreen(ps);
Common.Log("Nach SetPreferenceScreen");
setDependency(ps, p.childs);
}
private void setDependency(PreferenceScreen ps, ArrayList<B4APreference> childs) {
for (B4APreference b : childs) {
if (b instanceof PreferenceCategoryWrapper) {
setDependency(ps, ((PreferenceCategoryWrapper) b).childs);
}
else if (b instanceof PreferenceScreenWrapper) {
setDependency(ps, ((PreferenceScreenWrapper) b).childs);
}
else {
if (b.dependency.length() > 0 && ps.findPreference(b.dependency) == null)
Common.Log("Dependency key does not exist: " + b.dependency);
else
ps.findPreference(b.key).setDependency(b.dependency);
}
}
}
/**
* Provides access to the saved settings. Using PreferenceManager you can get the stored values and modify them.
*/
@ShortName("AHPreferenceManager")
public static class PreferenceManager {
private SharedPreferences sp = android.preference.PreferenceManager.getDefaultSharedPreferences(BA.applicationContext);
private HashSet<String> updatedKeys = new HashSet<String>();
public PreferenceManager() {
sp.registerOnSharedPreferenceChangeListener(new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(
SharedPreferences sharedPreferences, String key) {
updatedKeys.add(key);
}
});
}
/**
* PreferenceActivity library allows you to show the standard settings interface and provides an easy way to handle applications settings.
*This library requires you to modify AndroidManifest.xml. See the <link>tutorial|http://www.b4x.com/forum/basic4android-getting-started-tutorials/10608-preferenceactivity-tutorial.html</link> for more information.
*/
public static void LIBRARY_DOC() {
}
/**
* Returns a list with the keys that were updated since the last call to GetUpdatedKeys.
*Note that the updated keys may include keys with unchanged values.
*/
public List GetUpdatedKeys() {
List l = new List();
l.Initialize();
for (String s : updatedKeys) {
l.Add(s);
}
updatedKeys.clear();
return l;
}
/**
* Returns the String value mapped to the given key. Returns an empty string if the key is not found.
*/
public String GetString(String Key) {
return sp.getString(Key, "");
}
/**
* Returns the Boolean value mapped to the given key. Returns False is the key is not found.
*/
public boolean GetBoolean(String Key) {
return sp.getBoolean(Key, false);
}
/**
* Returns a Map with all the Keys and Values. Note that changes to this map will not affect the stored values.
*/
public Map GetAll() {
Map m = new Map();
m.Initialize();
for (Entry<String, ?> e : sp.getAll().entrySet()) {
m.Put(e.getKey(), e.getValue());
}
return m;
}
/**
* Maps the given key to the given String value.
*/
public void SetString(String Key, String Value) {
Editor e = sp.edit();
e.putString(Key, Value);
e.commit();
}
/**
* Maps the given key to the given Boolean value.
*/
public void SetBoolean(String Key, boolean Value) {
Editor e = sp.edit();
e.putBoolean(Key, Value);
e.commit();
}
/**
* Clears all stored entries.
*/
public void ClearAll() {
Editor e = sp.edit();
e.clear();
e.commit();
}
}
/**
*
*/
@ShortName("AHPreferenceScreen")
public static class PreferenceScreenWrapper extends B4APreference {
protected ArrayList<B4APreference> childs;
protected static int randomKey;
public PreferenceScreenWrapper() {
this("PreferenceScreen" + Integer.toString(++randomKey));
}
protected PreferenceScreenWrapper(String key) {
super(key, null, null, null, null);
}
public PreferenceScreenWrapper(Parcel source) {
super(source);
source.readTypedList(childs, B4APreference.CREATOR);
randomKey = source.readInt();
}
/**
* Initializes the object and sets the title that will show. The summary will show for secondary PreferenceScreens.
*/
public void Initialize(String Title, String Summary) {
childs = new ArrayList<B4APreference>();
this.title = Title;
this.summary = Summary;
}
/**
* Creates the Intent object that is required for showing the PreferencesActivity.
*Example:<code>StartActivity(PreferenceScreen1.CreateIntent)</code>
*/
public Intent CreateIntent() {
Intent in = new Intent();
in.setClass(BA.applicationContext, preferenceactivity.class);
in.putExtra("preferences", this);
return in;
}
@Override
Preference createPreference(PreferenceActivity c) {
PreferenceScreen ps = c.getPreferenceManager().createPreferenceScreen(c);
handleDefaults(ps);
for (B4APreference b : childs) {
if (b instanceof PreferenceCategoryWrapper) {
((PreferenceCategoryWrapper)b).parent = ps;
b.createPreference(c);
}
else {
ps.addPreference(b.createPreference(c));
}
}
return ps;
}
/**
* Adds a preference entry with a check box. The entry values can be either True or False.
*Key - The preference key associated with the value.
*Title - Entry title.
*SummaryOn - Entry summary (second row).
*SummaryOff - Entry summary if checkbox is not checked (Set to empty string to always show SummaryOn text)
*DefaultValue - The default value of this preference entry if the key does not already exist.
*Dependency - A key of a preference this preference entry depends on.
*/
public void AddCheckBox(String Key, String Title, final String SummaryOn, final String SummaryOff, boolean DefaultValue, String Dependency) {
childs.add(new B4APreference(Key, Title, SummaryOn, DefaultValue, Dependency) {
@Override
Preference createPreference(PreferenceActivity c) {
CheckBoxPreference cbp = new CheckBoxPreference(c);
handleDefaults(cbp);
if (SummaryOff.length() > 0) {
cbp.setSummaryOn(SummaryOn);
cbp.setSummaryOff(SummaryOff);
}
return cbp;
}
});
}
/**
* Adds a preference entry which allows the user to choose a single item out of a list.
*Key - The preference key associated with the value.
*Title - Entry title.
*Summary - Entry summary (second row).
*DefaultValue - The default value of this preference entry if the key does not already exist. Should match one of the values.
*Dependency - A key of a preference this preference entry depends on.
*Values - A list of strings with the possible values.
*/
public void AddList(String Key, String Title, String Summary, String DefaultValue, String Dependency, List Values) {
final CharSequence[] values = new String[Values.getSize()];
for (int i = 0;i < values.length;i++) {
values[i] = String.valueOf(Values.Get(i));
}
childs.add(new B4APreference(Key, Title, Summary, DefaultValue, Dependency) {
@Override
Preference createPreference(PreferenceActivity c) {
ListPreference list = new ListPreference(c);
handleDefaults(list);
list.setDialogTitle(title);
list.setEntries(values);
list.setEntryValues(values);
return list;
}
});
}
/**
* Adds a preference entry which allows the user to choose a single item out of a list.
*Key - The preference key associated with the value.
*Title - Entry title.
*Summary - Entry summary (second row).
*DefaultValue - The default value of this preference entry if the key does not already exist. Should match one of the value keys.
*Dependency - A key of a preference this preference entry depends on.
*Values - A map with the possible values. The key of the map is used as the value for the preference and the value is displayed in the list.
*/
public void AddList2(String Key, String Title, String Summary, String DefaultValue, String Dependency, Map Values) {
final CharSequence[] values = new String[Values.getSize()];
final CharSequence[] keys = new String[Values.getSize()];
for (int i = 0;i < values.length;i++) {
values[i] = String.valueOf(Values.GetValueAt(i));
keys[i] = String.valueOf(Values.GetKeyAt(i));
}
childs.add(new B4APreference(Key, Title, Summary, DefaultValue, Dependency) {
@Override
Preference createPreference(PreferenceActivity c) {
ListPreference list = new ListPreference(c);
handleDefaults(list);
list.setDialogTitle(title);
list.setEntries(values);
list.setEntryValues(keys);
return list;
}
});
}
public int RT_RINGTONE = 1;
public int RT_NOTIFICATION = 2;
public int RT_ALARM = 4;
/**
* Adds a preference entry which allows the user to choose a ring tone out of a list.
*Key - The preference key associated with the value.
*Title - Entry title.
*Summary - Entry summary (second row).
*DefaultValue - The default value of this preference entry if the key does not already exist. Should match one of the value keys.
*Dependency - A key of a preference this preference entry depends on.
*RingToneType - Type of the Ringtone. Use RT_RINGTONE, RT_NOTIFICATION, RT_ALARM.
*/
public void AddRingtone(String Key, String Title, String Summary, String DefaultValue, String Dependency, final int RingToneType) {
childs.add(new B4APreference(Key, Title, Summary, DefaultValue, Dependency) {
@Override
Preference createPreference(PreferenceActivity c) {
RingtonePreference ring = new RingtonePreference(c);
handleDefaults(ring);
ring.setRingtoneType(RingToneType);
return ring;
}
});
}
/**
* Adds a preference entry which allows the user to enter free text.
*Key - The preference key associated with the value.
*Title - Entry title.
*Summary - Entry summary (second row).
*DefaultValue - The default value of this preference entry if the key does not already exist.
*Dependency - A key of a preference this preference entry depends on.
*/
public void AddEditText(String Key, final String Title, final String Summary, final String DefaultValue, final String Dependency) {
childs.add(new B4APreference(Key, Title, Summary, DefaultValue, Dependency) {
@Override
Preference createPreference(PreferenceActivity c) {
EditTextPreference e = new EditTextPreference(c);
e.setDialogTitle(title);
handleDefaults(e);
return e;
}
});
}
/**
* Adds a preference entry which allows the user to enter a password. Be aware that the password is saved uncrypted in the preferences file!
*Key - The preference key associated with the value.
*Title - Entry title.
*Summary - Entry summary (second row).
*DefaultValue - The default value of this preference entry if the key does not already exist.
*Dependency - A key of a preference this preference entry depends on.
*/
public void AddPassword(String Key, final String Title, final String Summary, final String DefaultValue, final String Dependency) {
childs.add(new B4APreference(Key, Title, Summary, DefaultValue, Dependency) {
@Override
Preference createPreference(PreferenceActivity c) {
EditTextPreference e = new EditTextPreference(c);
e.setDialogTitle(title);
EditText et = e.getEditText();
et.setTransformationMethod(new PasswordTransformationMethod());
handleDefaults(e);
return e;
}
});
}
/**
* Adds a secondary PreferenceScreen. When the user presses on this entry the second screen will appear.
*/
public void AddPreferenceScreen(PreferenceScreenWrapper PreferenceScreen) {
childs.add(PreferenceScreen);
}
/**
* Calls the given Intent
*/
public void AddIntent(String Title, String Summary, final Intent Intent) {
childs.add(new B4APreference(Title, Summary, Intent) {
@Override
Preference createPreference(PreferenceActivity c) {
PreferenceScreen ps = c.getPreferenceManager().createPreferenceScreen(c);
handleDefaults(ps);
return ps;
}
});
}
/**
* Adds a PreferenceCategory. A preference category is made of a title and a group of entries.
*Note that a PreferenceCategory cannot hold other PreferenceCategories.
*/
public void AddPreferenceCategory(PreferenceCategoryWrapper PreferenceCategory) {
childs.add(PreferenceCategory);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeTypedList(childs);
dest.writeInt(randomKey);
}
public static final Parcelable.Creator CREATOR =
new Parcelable.Creator() {
public PreferenceScreenWrapper createFromParcel(Parcel source) {
return new PreferenceScreenWrapper(source);
}
@Override
public B4APreference[] newArray(int size) {
return new B4APreference[size];
}
};
}
/**
* PreferenceCategory holds a group of other preferences.
*/
@ShortName("AHPreferenceCategory")
public static class PreferenceCategoryWrapper extends PreferenceScreenWrapper {
PreferenceGroup parent;
public PreferenceCategoryWrapper() {
super("PreferenceCategory" + Integer.toString(++randomKey));
}
/**
* Initializes the object and sets the category title.
*/
public void Initialize(String Title) {
childs = new ArrayList<B4APreference>();
this.title = Title;
}
@Override
Preference createPreference(PreferenceActivity c) {
PreferenceCategory pc = new PreferenceCategory(c);
handleDefaults(pc);
if (parent == null) {
Common.Log("Error: PreferenceCategories cannot be nested!");
}
parent.addPreference(pc);
for (B4APreference b : childs) {
pc.addPreference(b.createPreference(c));
}
return pc;
}
@Override
@Hide
public Intent CreateIntent() {
return null;
}
}
static abstract class B4APreference implements Parcelable{
String key;
Serializable defaultValue;
String dependency;
String title, summary;
Intent intent;
public B4APreference(String key, String title, String summary, Serializable defaultValue, String dependency) {
this.key = key;
this.defaultValue = defaultValue;
this.summary = summary;
this.title = title;
this.dependency = dependency;
}
public B4APreference(String title, String summary, Intent intent) {
this.summary = summary;
this.title = title;
this.intent = intent;
}
abstract Preference createPreference(PreferenceActivity c) ;
protected void handleDefaults(Preference p) {
p.setKey(key);
p.setDefaultValue(defaultValue);
p.setTitle(title);
p.setSummary(summary);
}
@Override
public int describeContents() {
return this.hashCode();
}
public B4APreference(Parcel source) {
key = source.readString();
defaultValue = source.readSerializable();
dependency = source.readString();
title = source.readString();
summary = source.readString();
intent = source.readParcelable(Intent.class.getClassLoader());
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(key);
dest.writeSerializable(defaultValue);
dest.writeString(dependency);
dest.writeString(title);
dest.writeString(summary);
dest.writeParcelable(intent, flags);
}
public static final Parcelable.Creator CREATOR =
new Parcelable.Creator() {
public B4APreference createFromParcel(Parcel source) {
return new B4APreference(source) {
@Override
public Preference createPreference(PreferenceActivity c) {
// TODO Auto-generated method stub
return null;
}
};
}
@Override
public B4APreference[] newArray(int size) {
return new B4APreference[size];
}
};
}
}