/** * */ package org.odk.collect.android.utilities; import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import org.javarosa.core.util.PrefixTree; import org.javarosa.core.util.externalizable.Externalizable; import org.javarosa.core.util.externalizable.PrototypeFactory; import android.content.Context; import dalvik.system.DexFile; /** * @author ctsims * */ public class ApkUtils { private static PrototypeFactory factory; public static PrototypeFactory getPrototypeFactory(Context c) { if(factory != null) { return factory; } PrefixTree tree = new PrefixTree(); try { List<String> classes = getClasses("org.javarosa", c); for(String cl : classes) { //Log.i("CLASS", cl); tree.addString(cl); } //TODO: This was pulled from the source, should probably have a better //way to extend this utility classes = getClasses("org.commcare", c); for(String cl : classes) { //Log.i("CLASS", cl); tree.addString(cl); } } catch(Exception e) { throw new RuntimeException(e); } factory = new PrototypeFactory(tree); return factory; } /* Scans all classes accessible from the context class loader which belong to the given package and subpackages. * * @param packageName The base package * @return The classes * @throws ClassNotFoundException * @throws IOException */ @SuppressWarnings("unchecked") private static List<String> getClasses(String packageName, Context c) throws IOException { ArrayList<String> classNames = new ArrayList<String>(); String zpath = c.getApplicationInfo().sourceDir; if(zpath == null) { zpath = "/data/app/org.odk.collect.apk"; } DexFile df = new DexFile(new File(zpath)); for(Enumeration<String> en = df.entries() ; en.hasMoreElements() ;) { String cn = en.nextElement(); if(cn.startsWith(packageName) && !cn.contains(".test.")) { try{ Class prototype = Class.forName(cn); if(prototype.isInterface()) { continue; } boolean emptyc = false; for(Constructor<?> cons : prototype.getConstructors()) { if(cons.getParameterTypes().length == 0){ emptyc = true; } } if(!emptyc) { continue; } if(Externalizable.class.isAssignableFrom(prototype)) { classNames.add(cn); } } catch(Throwable e) { //nothing should every make this crash } } } return classNames; } }