package com.aokp.romcontrol.settings;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.aokp.romcontrol.R;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
/**
* Base class from which all other layouts inherit from. Subclasses must
* <p/>
* <ul><b>Supported attributes (all are optional)</b>
* <li>android:key - the key to look up the value
* <li>android:title - a @string reference to display as the title
* <li>android:summary - a @string reference to display as the summary
* <li>android:defaultValue - a string (NOT a reference) which is stored as the default value.
* <li>table - refers to which table the setting key/value are referenced in. Currently only two tables are
* supported: "aokp", and "system". Defaults to "aokp" if none is specified. Note that there is no namespace on this attribute.
* </ul>
* <p/>
* Sub classes' implementation of setValue() should eventually call {@link #setValue(String)},
* which will actually set the key and call the registered listener, if one exists.
* <p/>
*
* @see OnSettingChangedListener OnSettingChangedListener
* an interface which will allow the callback receiver to see any changes in this setting.
*/
public class BaseSetting extends LinearLayout {
public static final String TAG = BaseSetting.class.getSimpleName();
public static final String NAMESPACE_ANDROID = "http://schemas.android.com/apk/res/android";
public static final String NAMESPACE_RC = "http://schemas.android.com/apk/res/res-auto";
// values obtained from attributes
private String aKey, aTable, aTitle, aSummary, aDefaultValue;
// separate in case we want to query whether one was supplied
private String mSummary;
protected TextView mTitleTextView, mDescriptionTextView;
private OnSettingChangedListener mOnSettingChangedListener;
/**
* Sub classes should attach their inflated views to this view.
*/
protected ViewGroup mRootView;
private final ArrayList<OnClickListener> mRegisteredClickListeners = new ArrayList<OnClickListener>();
private final OnClickListener mOnClickListener = new OnClickListener() {
@Override
public void onClick(View view) {
for (OnClickListener clickListener : mRegisteredClickListeners) {
clickListener.onClick(view);
}
}
};
public final void setOnClickListener(OnClickListener listener) {
mRegisteredClickListeners.add(listener);
}
/**
* Interface to allow classes to receive callbacks when the user has modified the value of the setting.
*/
public interface OnSettingChangedListener {
public void onSettingChanged(String table, String key, String oldValue, String value);
}
public BaseSetting(Context context) {
this(context, null);
}
public BaseSetting(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BaseSetting(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (attrs != null) {
aKey = attrs.getAttributeValue(NAMESPACE_ANDROID, "key");
aDefaultValue = attrs.getAttributeValue(NAMESPACE_ANDROID, "defaultValue");
Resources r = context.getResources();
aTitle = readAttrStringResource(r, attrs.getAttributeResourceValue(NAMESPACE_ANDROID, "title", 0));
aSummary = readAttrStringResource(r, attrs.getAttributeResourceValue(NAMESPACE_ANDROID, "summary", 0));
aTable = attrs.getAttributeValue(null, "table");
if (aTable == null) {
aTable = "aokp";
}
}
mRootView = (ViewGroup) View.inflate(context, R.layout.setting_base, null);
mTitleTextView = (TextView) mRootView.findViewById(R.id.title);
mDescriptionTextView = (TextView) mRootView.findViewById(R.id.summary);
setTitle(aTitle);
setSummary(aSummary);
super.setOnClickListener(mOnClickListener);
}
/**
* @param s the new setting to apply to this table/key. Null strings are considered empty strings.
* @throws UnsupportedOperationException if no key is set.
*/
protected final void setValue(String s) {
if (aKey == null) {
// assume it's handled some other way
return;
}
// accept null strings - just set them to empty
if (s == null) {
s = "";
}
String currentVal;
try {
currentVal = getValue();
} catch (Exception e) {
currentVal = "";
}
String key = getKey();
// Log.d(TAG, "Attempting to set key " + key + " to value: " + s + ", in table: " + getTable());
// dirty dirty! use reflection to allow compilation via gradle/android studio
try {
String className = "android.provider.Settings$";
if ("system".equalsIgnoreCase(getTable())) {
className += "System";
} else {
className += "AOKP";
}
Class<?> clazz = Class.forName(className);
Class[] params = new Class[3];
params[0] = ContentResolver.class;
params[1] = String.class;
params[2] = String.class;
Object[] paramObjects = new Object[3];
paramObjects[0] = getContext().getContentResolver();
paramObjects[1] = getKey();
paramObjects[2] = s;
Method method = clazz.getDeclaredMethod("putString", params);
method.setAccessible(true);
Boolean result = (Boolean) method.invoke(null, paramObjects);
// Log.d(TAG, "result: " + result.toString());
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
}
if (mOnSettingChangedListener != null) {
mOnSettingChangedListener.onSettingChanged(getTable(), key, currentVal, s);
}
}
/**
* @return the string value of the setting.
*/
protected String getValue() {
if (aKey == null) {
return null;
}
// dirty dirty! use reflection to allow compilation via gradle/android studio
try {
String className = "android.provider.Settings$";
if ("system".equalsIgnoreCase(getTable())) {
className += "System";
} else {
className += "AOKP";
}
Class<?> clazz = Class.forName(className);
Class[] params = new Class[2];
params[0] = ContentResolver.class;
params[1] = String.class;
Object[] paramObjects = new Object[2];
paramObjects[0] = getContext().getContentResolver();
paramObjects[1] = getKey();
Method method = clazz.getDeclaredMethod("getString", params);
method.setAccessible(true);
Object result = method.invoke(null, paramObjects);
//Log.d(TAG, "result: " + result != null ? result : "null");
return (String) result;
} catch (NoSuchMethodException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
} catch (InvocationTargetException e1) {
e1.printStackTrace();
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
}
return null;
}
/**
* @return the table which the setting will be saved to. Currently only 'aokp' and 'system' are supported
*/
protected final String getTable() {
return aTable;
}
/**
* @return the key value which this preference is supposed to represent
*/
public final String getKey() {
return aKey;
}
/**
* Used to assign or change a key value
*/
public final void setKey(String key) {
aKey = key;
}
public void setDefaultValue(String defaultValue) {
aDefaultValue = defaultValue;
}
/**
* @return returns the supplied default value. null if none was provided.
*/
protected final String getDefaultValue() {
return aDefaultValue;
}
/**
* @return returns the current summary;
*/
protected final String getCurrentSummary() {
return mSummary;
}
protected final String getDefaultSummary() {
return aSummary;
}
protected void setSummary(String summary) {
mSummary = summary;
if (mDescriptionTextView != null) {
mDescriptionTextView.setText(summary);
if (summary == null) {
mDescriptionTextView.setVisibility(View.GONE);
} else {
mDescriptionTextView.setVisibility(View.VISIBLE);
}
}
}
protected final String getTitle() {
return aTitle;
}
protected void setTitle(String title) {
aTitle = title;
if (mTitleTextView != null) {
mTitleTextView.setText(title);
}
}
public void setOnSettingChangedListener(OnSettingChangedListener listener) {
this.mOnSettingChangedListener = listener;
if(listener != null) {
// set initial value
listener.onSettingChanged(getTable(), getKey(), null, getValue());
}
}
/**
* Helper method which attempts to read in a String resource, and get its value.
*
* @param r Resources from which to do the lookup
* @param resource R.string identifier
* @return the looked-up String, or null if it wasn't found
*/
public static String readAttrStringResource(Resources r, int resource) {
try {
String string = r.getString(resource);
return string;
} catch (NotFoundException e) {
return null;
}
}
}