content: package mobi.acpm.inspeckage.hooks;
  
  import com.google.gson.Gson;
  import com.google.gson.GsonBuilder;
  import com.google.gson.JsonSyntaxException;
  
  import org.json.JSONArray;
  import org.json.JSONObject;
  
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Method;
  import java.lang.reflect.Modifier;
  import java.util.List;
  
  import de.robv.android.xposed.XC_MethodHook;
  import de.robv.android.xposed.XSharedPreferences;
  import de.robv.android.xposed.XposedBridge;
  import de.robv.android.xposed.callbacks.XC_LoadPackage;
  import mobi.acpm.inspeckage.Module;
  import mobi.acpm.inspeckage.util.Config;
  import mobi.acpm.inspeckage.util.Replacement;
  import mobi.acpm.inspeckage.util.Util;
  
  import static de.robv.android.xposed.XposedBridge.log;
  import static de.robv.android.xposed.XposedHelpers.findClass;
  
  /**
   * Created by acpm on 19/04/16.
   */
  public class UserHooks extends XC_MethodHook {
  
      public static final String TAG = "Inspeckage_UserHooks:";
      private static Gson gson = new GsonBuilder().disableHtmlEscaping().create();//new Gson();
      private static XSharedPreferences sPrefs;
      private static XC_LoadPackage.LoadPackageParam lpp;
  
      public static void loadPrefs() {
          sPrefs = new XSharedPreferences(Module.class.getPackage().getName(), Module.PREFS);
          sPrefs.makeWorldReadable();
      }
  
      public static void initAllHooks(final XC_LoadPackage.LoadPackageParam loadPackageParam) {
          loadPrefs();
          lpp = loadPackageParam;
          String json = "{\"hookJson\": " + sPrefs.getString(Config.SP_USER_HOOKS, "") + "}";
          try {
  
              if(!json.trim().equals("{\"hookJson\":}")) {
                  HookList hookList = gson.fromJson(json, HookList.class);
                  for (HookItem hookItem : hookList.hookJson) {
                      if(hookItem.state) {
                          hook(hookItem, loadPackageParam.classLoader);
                      }
                  }
              }
          } catch (JsonSyntaxException ex) { }
      }
  
      static void hook(HookItem item, ClassLoader classLoader) {
          try {
              Class<?> hookClass = findClass(item.className, classLoader);
  
              if (hookClass != null) {
  
                  if (item.method != null && !item.method.equals("")) {
                      for (Method method : hookClass.getDeclaredMethods()) {
                          if (method.getName().equals(item.method) && !Modifier.isAbstract(method.getModifiers())) {
                              XposedBridge.hookMethod(method, methodHook);
                          }
                      }
                  } else {
                      for (Method method : hookClass.getDeclaredMethods()) {
                          if(!Modifier.isAbstract(method.getModifiers())) {
                              XposedBridge.hookMethod(method, methodHook);
                          }
                      }
                  }
  
                  if (item.constructor) {
                      for (Constructor<?> constructor : hookClass.getDeclaredConstructors()) {
                          XposedBridge.hookMethod(constructor, methodHook);
                      }
                  }
  
              } else {
                  log(TAG + "class not found.");
              }
          } catch (Error e) {
              Module.logError(e);
          }
      }
  
      static XC_MethodHook methodHook = new XC_MethodHook() {
  
          protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
              loadPrefs();
              Replacement.parameterReplace(param, sPrefs);
          }
  
          protected void afterHookedMethod(MethodHookParam param) throws Throwable {
              loadPrefs();
              Replacement.resultReplace(param, sPrefs);
              parseParam(param);
          }
      };
  
      static void parseParam(XC_MethodHook.MethodHookParam param) {
          try {
              JSONObject hookData = new JSONObject();
              hookData.put("class", param.method.getDeclaringClass().getName());
  
              if(param.method!=null)
                  hookData.put("method", param.method.getName());
  
              JSONArray args = new JSONArray();
  
              if(param.args!=null) {
                  for (Object object : (Object[]) param.args) {
  
                      if (object != null) {
                          if(object.getClass().equals(byte[].class)){
                              String result = Util.byteArrayToString((byte[])object);
                              args.put(gson.toJson(result));
                          }else{
                              args.put(gson.toJson(object));
                          }
                      }
                  }
                  hookData.put("args", args);
              }
  
              if(param.getResult()!=null){
                  String result = "";
                  if(param.getResult().getClass().equals(byte[].class)){
                      result = Util.byteArrayToString((byte[])param.getResult());
                      hookData.put("result", gson.toJson(result));
                  }else{
                      hookData.put("result", gson.toJson(param.getResult()));
                  }
  
              }
  
              log(TAG + hookData.toString());
  
          } catch (Exception e) {
              e.getMessage();
          }
      }
  }
  
  class HookList {
      public List<HookItem> hookJson;
  }
  
  class HookItem {
      protected int id;
      protected String className;
      protected String method;
      protected boolean constructor;
      protected boolean state;
  }
  