// Path: tweakable/src/main/java/com/jackwink/tweakable/binders/ActionBinder.java
// public class ActionBinder extends AbstractValueBinder<Method> {
// 
//     protected Method mMethod;
// 
//     public ActionBinder(Method method) {
//         mMethod = method;
//     }
// 
//     @Override
//     public Class<Method> getType() {
//         return Method.class;
//     }
// 
//     @Override
//     public void bindValue(SharedPreferences preferences, String key) {
//         try {
//             mMethod.invoke(null);
//         } catch (Exception e) {
//             e.printStackTrace();
//         }
//     }
// 
//     @Override
//     public Method getValue() {
//         return mMethod;
//     }
// }
// 
// Path: tweakable/src/main/java/com/jackwink/tweakable/binders/ValueBinder.java
// public interface ValueBinder<T> {
// 
//     void bindValue(SharedPreferences preferences, String key);
// 
//     Class<T> getType();
// 
//     T getValue();
// 
//     @SuppressWarnings({ "rawtypes" })
//     enum DeclaredTypes {
//         BOOL(new Class[] {Boolean.class, boolean.class }),
//         INT(new Class[] {Integer.class, int.class }),
//         FLOAT(new Class[] {Float.class, float.class }),
//         STRING(new Class[] {String.class }),
//         ACTION(new Class[] {Method.class });
// 
//         private Class[] mHandledTypes;
// 
//         DeclaredTypes(Class[] types) {
//             mHandledTypes = types;
//         }
// 
//         public boolean contains(Class cls) {
//             for (Class clazz : mHandledTypes) {
//                 if (clazz.equals(cls)) {
//                     return true;
//                 }
//             }
//             return false;
//         }
// 
//         public ValueBinder getBinder(Object fieldOrMethod) {
//             switch (this) {
//                 case BOOL:
//                     return new BooleanValueBinder((Field) fieldOrMethod);
//                 case INT:
//                     return new IntegerValueBinder((Field) fieldOrMethod);
//                 case FLOAT:
//                     return new FloatValueBinder((Field) fieldOrMethod);
//                 case STRING:
//                     return new StringValueBinder((Field) fieldOrMethod);
//                 case ACTION:
//                     return new ActionBinder((Method) fieldOrMethod);
//                 default:
//                     return null;
//             }
//         }
//     }
// }
// 
// Path: tweakable-annotations/src/main/java/com/jackwink/tweakable/exceptions/FailedToBuildPreferenceException.java
// public class FailedToBuildPreferenceException extends RuntimeException {
//     public static final long serialVersionUID = 0L;
// 
//     public FailedToBuildPreferenceException(String reason) {
//         super(reason);
//     }
// 
//     public FailedToBuildPreferenceException(String reason, Throwable rootCause) {
//         super(reason, rootCause);
//     }
// }
// 
// Path: tweakable-annotations/src/main/java/com/jackwink/tweakable/types/AbstractTweakableValue.java
// public abstract class AbstractTweakableValue<T> implements TweakableValue<T> {
//     public static final String BUNDLE_KEYATTR_KEY = "key";
//     public static final String BUNDLE_TITLE_KEY = "title";
//     public static final String BUNDLE_SUMMARY_KEY = "summary";
// 
//     public static final String BUNDLE_CATEGORY_KEY = "category";
//     public static final String BUNDLE_SCREEN_KEY = "screen";
// 
//     public static final String ROOT_SCREEN_KEY = "tweakable-values-root-screen";
//     public static final String ROOT_CATEGORY_KEY = "tweakable-values-root-category";
// 
// 
//     protected String mTitle;
//     protected String mKey;
//     protected String mSummary;
//     protected String mCategory;
//     protected String mScreen;
// 
//     @Override
//     public String getKey() {
//         return mKey;
//     }
// 
//     @Override
//     public String getTitle() {
//         return mTitle == null ? "ERROR" : mTitle;
//     }
// 
//     @Override
//     public String getSummary() {
//         return mSummary;
//     }
// 
//     @Override
//     public String getCategory() {
//         return mCategory;
//     }
// 
//     @Override
//     public String getScreen() {
//         return mScreen;
//     }
// 
//     public static String getDefaultString(String value, String defaultValue) {
//         if (value == null || value.isEmpty()) {
//             return defaultValue;
//         }
//         return value;
//     }
// }


import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import com.jackwink.tweakable.binders.ActionBinder;
import com.jackwink.tweakable.binders.ValueBinder;
import com.jackwink.tweakable.exceptions.FailedToBuildPreferenceException;
import com.jackwink.tweakable.types.AbstractTweakableValue;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;
package com.jackwink.tweakable;




/**
 * Tweakable values and Feature Flags for Android.
 *
 * <h2>Usage Instructions</h2>
 *
 * <p>Call {@link Tweakable#init(Context)} to inject the default values
 * (or saved values from Preferences) on the start of your application or main activity.</p>
 *
 * <p>Shake your phone to pull up the generated settings!</p>
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public class Tweakable {
    private static final String TAG = Tweakable.class.getSimpleName();

    private static String mSharedPreferencesName;
    private static SharedPreferences mSharedPreferences;

    private static TweakableShakeDetector mShakeDetector;
    private static boolean mOnShakeEnabled;

// Path: tweakable/src/main/java/com/jackwink/tweakable/binders/ActionBinder.java
// public class ActionBinder extends AbstractValueBinder<Method> {
// 
//     protected Method mMethod;
// 
//     public ActionBinder(Method method) {
//         mMethod = method;
//     }
// 
//     @Override
//     public Class<Method> getType() {
//         return Method.class;
//     }
// 
//     @Override
//     public void bindValue(SharedPreferences preferences, String key) {
//         try {
//             mMethod.invoke(null);
//         } catch (Exception e) {
//             e.printStackTrace();
//         }
//     }
// 
//     @Override
//     public Method getValue() {
//         return mMethod;
//     }
// }
// 
// Path: tweakable/src/main/java/com/jackwink/tweakable/binders/ValueBinder.java
// public interface ValueBinder<T> {
// 
//     void bindValue(SharedPreferences preferences, String key);
// 
//     Class<T> getType();
// 
//     T getValue();
// 
//     @SuppressWarnings({ "rawtypes" })
//     enum DeclaredTypes {
//         BOOL(new Class[] {Boolean.class, boolean.class }),
//         INT(new Class[] {Integer.class, int.class }),
//         FLOAT(new Class[] {Float.class, float.class }),
//         STRING(new Class[] {String.class }),
//         ACTION(new Class[] {Method.class });
// 
//         private Class[] mHandledTypes;
// 
//         DeclaredTypes(Class[] types) {
//             mHandledTypes = types;
//         }
// 
//         public boolean contains(Class cls) {
//             for (Class clazz : mHandledTypes) {
//                 if (clazz.equals(cls)) {
//                     return true;
//                 }
//             }
//             return false;
//         }
// 
//         public ValueBinder getBinder(Object fieldOrMethod) {
//             switch (this) {
//                 case BOOL:
//                     return new BooleanValueBinder((Field) fieldOrMethod);
//                 case INT:
//                     return new IntegerValueBinder((Field) fieldOrMethod);
//                 case FLOAT:
//                     return new FloatValueBinder((Field) fieldOrMethod);
//                 case STRING:
//                     return new StringValueBinder((Field) fieldOrMethod);
//                 case ACTION:
//                     return new ActionBinder((Method) fieldOrMethod);
//                 default:
//                     return null;
//             }
//         }
//     }
// }
// 
// Path: tweakable-annotations/src/main/java/com/jackwink/tweakable/exceptions/FailedToBuildPreferenceException.java
// public class FailedToBuildPreferenceException extends RuntimeException {
//     public static final long serialVersionUID = 0L;
// 
//     public FailedToBuildPreferenceException(String reason) {
//         super(reason);
//     }
// 
//     public FailedToBuildPreferenceException(String reason, Throwable rootCause) {
//         super(reason, rootCause);
//     }
// }
// 
// Path: tweakable-annotations/src/main/java/com/jackwink/tweakable/types/AbstractTweakableValue.java
// public abstract class AbstractTweakableValue<T> implements TweakableValue<T> {
//     public static final String BUNDLE_KEYATTR_KEY = "key";
//     public static final String BUNDLE_TITLE_KEY = "title";
//     public static final String BUNDLE_SUMMARY_KEY = "summary";
// 
//     public static final String BUNDLE_CATEGORY_KEY = "category";
//     public static final String BUNDLE_SCREEN_KEY = "screen";
// 
//     public static final String ROOT_SCREEN_KEY = "tweakable-values-root-screen";
//     public static final String ROOT_CATEGORY_KEY = "tweakable-values-root-category";
// 
// 
//     protected String mTitle;
//     protected String mKey;
//     protected String mSummary;
//     protected String mCategory;
//     protected String mScreen;
// 
//     @Override
//     public String getKey() {
//         return mKey;
//     }
// 
//     @Override
//     public String getTitle() {
//         return mTitle == null ? "ERROR" : mTitle;
//     }
// 
//     @Override
//     public String getSummary() {
//         return mSummary;
//     }
// 
//     @Override
//     public String getCategory() {
//         return mCategory;
//     }
// 
//     @Override
//     public String getScreen() {
//         return mScreen;
//     }
// 
//     public static String getDefaultString(String value, String defaultValue) {
//         if (value == null || value.isEmpty()) {
//             return defaultValue;
//         }
//         return value;
//     }
// }


// Path: tweakable/src/main/java/com/jackwink/tweakable/Tweakable.java
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;
import com.jackwink.tweakable.binders.ActionBinder;
import com.jackwink.tweakable.binders.ValueBinder;
import com.jackwink.tweakable.exceptions.FailedToBuildPreferenceException;
import com.jackwink.tweakable.types.AbstractTweakableValue;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;

package com.jackwink.tweakable;




/**
 * Tweakable values and Feature Flags for Android.
 *
 * <h2>Usage Instructions</h2>
 *
 * <p>Call {@link Tweakable#init(Context)} to inject the default values
 * (or saved values from Preferences) on the start of your application or main activity.</p>
 *
 * <p>Shake your phone to pull up the generated settings!</p>
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public class Tweakable {
    private static final String TAG = Tweakable.class.getSimpleName();

    private static String mSharedPreferencesName;
    private static SharedPreferences mSharedPreferences;

    private static TweakableShakeDetector mShakeDetector;
    private static boolean mOnShakeEnabled;

    private static LinkedHashMap<String, ValueBinder> mValueBinders =