diff options
Diffstat (limited to 'src')
4 files changed, 153 insertions, 61 deletions
diff --git a/src/java/jogamp/android/launcher/ActivityLauncher.java b/src/java/jogamp/android/launcher/ActivityLauncher.java index 0ac940e..6e2f261 100644 --- a/src/java/jogamp/android/launcher/ActivityLauncher.java +++ b/src/java/jogamp/android/launcher/ActivityLauncher.java @@ -55,7 +55,7 @@ public class ActivityLauncher extends Activity { data = LauncherUtil.DataSet.create(uri); data.setSystemProperties(); - ClassLoader cl = ClassLoaderUtil.createClassLoader(this, data.getPackages(), false, null); + ClassLoader cl = ClassLoaderUtil.createClassLoader(this, data.getSysPackages(), data.getUsrPackages(), null); if(null != cl) { try { activityClazz = Class.forName(data.getActivityName(), true, cl); @@ -135,8 +135,18 @@ public class ActivityLauncher extends Activity { Log.d(TAG, "onDestroy - S"); callMethod(activityObject, mOnDestroy); if(null != data) { + activityObject=null; + mOnCreate=null; + mOnDestroy=null; + mOnPause=null; + mOnRestart=null; + mOnResume=null; + mOnStart=null; + mOnStop=null; + mSetRootActivity=null; + activityClazz = null; data.clearSystemProperties(); - data = null; + data = null; } super.onDestroy(); Log.d(TAG, "onDestroy - X"); diff --git a/src/java/jogamp/android/launcher/ClassLoaderUtil.java b/src/java/jogamp/android/launcher/ClassLoaderUtil.java index ae2918f..76dbf53 100644 --- a/src/java/jogamp/android/launcher/ClassLoaderUtil.java +++ b/src/java/jogamp/android/launcher/ClassLoaderUtil.java @@ -29,7 +29,7 @@ package jogamp.android.launcher; import java.io.File; -import java.util.Arrays; +import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -41,15 +41,13 @@ import android.util.Log; public class ClassLoaderUtil { private static final String TAG = "JogampClassLoader"; - // FIXME: Need to generalize this .. (Note: native lib resources must be cached!) - private static final String[] packagesJogAmp = { "com.jogamp.common", "javax.media.opengl" }; - private static ClassLoader jogAmpClassLoader = null; + private static HashMap<String, ClassLoader> cachedClassLoader = new HashMap<String, ClassLoader>(); // location where optimized dex files will be written private static final String dexPathName= "jogampDex"; private static File dexPath = null; - private static LauncherTempFileCache tmpFileCache = null; + private static LauncherTempFileCache tmpFileCache = null; private static final String PATH_SEP = "/"; private static final String ELEM_SEP = ":"; @@ -69,45 +67,69 @@ public class ClassLoaderUtil { } } - public static synchronized ClassLoader createClassLoader(Context ctx, List<String> userPackageNames, boolean addUserLibPath, - List<String> apkNames) { - return createClassLoader(ctx, userPackageNames, addUserLibPath, apkNames, null); + /** + * @param ctx + * @param cachedPackageName list of package names w/ native libraries for which a ClassLoader shall be cached, i.e. persistence. + * This is usually required for native libraries. + * @param userPackageNames list of user package names w/o native libraries, the last entry shall reflect the Activity. + * @param userAPKNames optional non-cached user APKs + * @return + */ + public static synchronized ClassLoader createClassLoader(Context ctx, List<String> cachedPackageName, + List<String> userPackageNames, List<String> userAPKNames) { + return createClassLoader(ctx, cachedPackageName, userPackageNames, userAPKNames, null); } - public static synchronized ClassLoader createClassLoader(Context ctx, List<String> userPackageNames, boolean addUserLibPath, - List<String> apkNames, ClassLoader parent) { + /** + * @param ctx + * @param cachedPackageNames list of package names w/ native libraries for which a ClassLoader shall be cached, i.e. persistence. + * This is usually required for native libraries. + * @param userPackageNames list of user package names w/o native libraries, the last entry shall reflect the Activity. + * @param userAPKNames optional non-cached user APKs + * @param parent + * @return + */ + public static synchronized ClassLoader createClassLoader(Context ctx, List<String> cachedPackageNames, + List<String> userPackageNames, List<String> userAPKNames, + ClassLoader parent) { init(ctx); - if(null==jogAmpClassLoader) { - jogAmpClassLoader = createClassLoaderImpl(ctx, Arrays.asList(packagesJogAmp), true, null, - (null != parent ) ? parent : ctx.getClassLoader()); + final String cacheKey = cachedPackageNames.toString(); + ClassLoader clCached = cachedClassLoader.get(cacheKey); + if( null == clCached ) { + clCached = createClassLoaderImpl(ctx, cachedPackageNames, true, null, (null != parent ) ? parent : ctx.getClassLoader()); + cachedClassLoader.put(cacheKey, clCached); + Log.d(TAG, "NEW cached-CL: cachedPackageNames: "+cacheKey); + } else { + Log.d(TAG, "REUSE cached-CL: cachedPackageNames: "+cacheKey); } - parent = jogAmpClassLoader; - return createClassLoaderImpl(ctx, userPackageNames, addUserLibPath, apkNames, jogAmpClassLoader); + return createClassLoaderImpl(ctx, userPackageNames, false, userAPKNames, clCached); } /** - * * @param ctx - * @param userPackageNames list of user package names, the last entry shall reflect the Activity + * @param packageNames list of package names + * @param addLibPath + * @param apkNames + * @param parent * @return */ - private static synchronized ClassLoader createClassLoaderImpl(Context ctx, List<String> userPackageNames, boolean addUserLibPath, + private static synchronized ClassLoader createClassLoaderImpl(Context ctx, List<String> packageNames, boolean addLibPath, List<String> apkNames, ClassLoader parent) { final ApplicationInfo appInfoLauncher= ctx.getApplicationInfo(); final String appDirLauncher = new File(appInfoLauncher.dataDir).getParent(); final String libSubDef = "lib"; - Log.d(TAG, "S: userPackageNames: "+userPackageNames+"; Launcher: appDir "+appDirLauncher+", dataDir: "+appInfoLauncher.dataDir+", nativeLibraryDir "+appInfoLauncher.nativeLibraryDir); + Log.d(TAG, "S: userPackageNames: "+packageNames+"; Launcher: appDir "+appDirLauncher+", dataDir: "+appInfoLauncher.dataDir+", nativeLibraryDir "+appInfoLauncher.nativeLibraryDir); final StringBuilder apks = new StringBuilder(); final StringBuilder libs = new StringBuilder(); int apkCount = 0; String lastUserPackageName = null; // the very last one reflects the Activity - if( null != userPackageNames ) { - for(Iterator<String> i=userPackageNames.iterator(); i.hasNext(); ) { + if( null != packageNames ) { + for(Iterator<String> i=packageNames.iterator(); i.hasNext(); ) { lastUserPackageName = i.next(); String userAPK = null; @@ -125,14 +147,14 @@ public class ClassLoaderUtil { if(null != userAPK) { if(apkCount>0) { apks.append(ELEM_SEP); - if(addUserLibPath) { + if(addLibPath) { libs.append(ELEM_SEP); } } apks.append(userAPK); Log.d(TAG, "APK["+apkCount+"] found: <"+lastUserPackageName+"> -> <"+userAPK+">"); Log.d(TAG, "APK["+apkCount+"] apks: <"+apks.toString()+">"); - if(addUserLibPath) { + if(addLibPath) { if(null != nativeLibraryDir && nativeLibraryDir.length()>0 ) { libs.append(nativeLibraryDir).append(PATH_SEP); } else { @@ -145,7 +167,7 @@ public class ClassLoaderUtil { Log.d(TAG, "APK not found: <"+lastUserPackageName+">"); } } - if( userPackageNames.size() != apkCount ) { + if( packageNames.size() != apkCount ) { Log.d(TAG, "User APKs incomplete, abort (1)"); return null; } diff --git a/src/java/jogamp/android/launcher/LauncherUtil.java b/src/java/jogamp/android/launcher/LauncherUtil.java index b68768b..1dfc218 100644 --- a/src/java/jogamp/android/launcher/LauncherUtil.java +++ b/src/java/jogamp/android/launcher/LauncherUtil.java @@ -65,7 +65,9 @@ public class LauncherUtil { /** The host <code>jogamp.org</code> */ public static final String HOST = "jogamp.org"; - static final String PKG = "pkg"; + static final String SYS_PKG = "sys"; + + static final String USR_PKG = "pkg"; static final String ARG = "arg"; @@ -105,8 +107,11 @@ public class LauncherUtil { /** Must return the downstream Activity class name */ public abstract String getActivityName(); - /** Must return a list of required packages, at least one. */ - public abstract List<String> getPackages(); + /** Must return a list of required user packages, at least one containing the activity. */ + public abstract List<String> getUsrPackages(); + + /** Return a list of required system packages w/ native libraries, may return null or a zero sized list. */ + public abstract List<String> getSysPackages(); @Override public void onCreate(Bundle savedInstanceState) { @@ -116,7 +121,8 @@ public class LauncherUtil { final DataSet data = new DataSet(); data.setActivityName(getActivityName()); - data.addAllPackages(getPackages()); + data.addAllSysPackages(getSysPackages()); + data.addAllUsrPackages(getUsrPackages()); data.addAllProperties(props); data.addAllArguments(args); @@ -135,8 +141,11 @@ public class LauncherUtil { ArrayList<String> keyList = new ArrayList<String>(); public final void setProperty(String key, String value) { - if(key.equals(PKG)) { - throw new IllegalArgumentException("Illegal property key, '"+PKG+"' is reserved"); + if(key.equals(SYS_PKG)) { + throw new IllegalArgumentException("Illegal property key, '"+SYS_PKG+"' is reserved"); + } + if(key.equals(USR_PKG)) { + throw new IllegalArgumentException("Illegal property key, '"+USR_PKG+"' is reserved"); } if(key.equals(ARG)) { throw new IllegalArgumentException("Illegal property key, '"+ARG+"' is reserved"); @@ -178,6 +187,17 @@ public class LauncherUtil { public final List<String> getPropertyKeys() { return keyList; } } + /** + * Data set to transfer from and to launch URI consisting out of: + * <ul> + * <li>system packages w/ native libraries used on Android, which may use a cached ClassLoader, see {@link DataSet#getSysPackages()}.</li> + * <li>user packages w/o native libraries used on Android, which do not use a cached ClassLoader, see {@link DataSet#getUsrPackages()}.</li> + * <li>activity name, used to launch an Android activity, see {@link DataSet#getActivityName()}.</li> + * <li>properties, which will be added to the system properties, see {@link DataSet#getProperties()}.</li> + * <li>arguments, used to launch a class main-entry, see {@link DataSet#getArguments()}.</li> + * </ul> + * {@link DataSet#getUri()} returns a URI representation of all components. + */ public static class DataSet { static final char SLASH = '/'; static final char QMARK = '?'; @@ -187,20 +207,29 @@ public class LauncherUtil { static final String EMPTY = ""; String activityName = null; - ArrayList<String> packages = new ArrayList<String>(); + ArrayList<String> sysPackages = new ArrayList<String>(); + ArrayList<String> usrPackages = new ArrayList<String>(); OrderedProperties properties = new OrderedProperties(); ArrayList<String> arguments = new ArrayList<String>(); public final void setActivityName(String name) { activityName = name; } public final String getActivityName() { return activityName; } + + public final void addSysPackage(String p) { + sysPackages.add(p); + } + public final void addAllSysPackages(List<String> plist) { + sysPackages.addAll(plist); + } + public final List<String> getSysPackages() { return sysPackages; } - public final void addPackage(String p) { - packages.add(p); + public final void addUsrPackage(String p) { + usrPackages.add(p); } - public final void addAllPackages(List<String> plist) { - packages.addAll(plist); + public final void addAllUsrPackages(List<String> plist) { + usrPackages.addAll(plist); } - public final List<String> getPackages() { return packages; } + public final List<String> getUsrPackages() { return usrPackages; } public final void setProperty(String key, String value) { properties.setProperty(key, value); @@ -227,33 +256,58 @@ public class LauncherUtil { public final Uri getUri() { StringBuilder sb = new StringBuilder(); sb.append(SCHEME).append(COLSLASH2).append(HOST).append(SLASH).append(getActivityName()); + boolean needsQMark = true; boolean needsSep = false; - if(packages.size()>0) { - sb.append(QMARK); - for(int i=0; i<packages.size(); i++) { + if(sysPackages.size()>0) { + if( needsQMark ) { + sb.append(QMARK); + needsQMark = false; + } + for(int i=0; i<sysPackages.size(); i++) { if(needsSep) { sb.append(AMPER); } - sb.append(PKG).append(ASSIG).append(packages.get(i)); + sb.append(SYS_PKG).append(ASSIG).append(sysPackages.get(i)); needsSep = true; } } - Iterator<String> propKeys = properties.keyList.iterator(); - while(propKeys.hasNext()) { + if(usrPackages.size()>0) { + if( needsQMark ) { + sb.append(QMARK); + needsQMark = false; + } + for(int i=0; i<usrPackages.size(); i++) { if(needsSep) { sb.append(AMPER); } - final String key = propKeys.next(); - sb.append(key).append(ASSIG).append(properties.map.get(key)); + sb.append(USR_PKG).append(ASSIG).append(usrPackages.get(i)); needsSep = true; + } + } + Iterator<String> propKeys = properties.keyList.iterator(); + while(propKeys.hasNext()) { + if( needsQMark ) { + sb.append(QMARK); + needsQMark = false; + } + if(needsSep) { + sb.append(AMPER); + } + final String key = propKeys.next(); + sb.append(key).append(ASSIG).append(properties.map.get(key)); + needsSep = true; } Iterator<String> args = arguments.iterator(); while(args.hasNext()) { - if(needsSep) { - sb.append(AMPER); - } - sb.append(ARG).append(ASSIG).append(args.next()); - needsSep = true; + if( needsQMark ) { + sb.append(QMARK); + needsQMark = false; + } + if(needsSep) { + sb.append(AMPER); + } + sb.append(ARG).append(ASSIG).append(args.next()); + needsSep = true; } return Uri.parse(sb.toString()); } @@ -298,11 +352,16 @@ public class LauncherUtil { // assignment final String k = part.substring(0, assignment); final String v = part.substring(assignment+1); - if(k.equals(PKG)) { + if(k.equals(SYS_PKG)) { + if(v.length()==0) { + throw new IllegalArgumentException("Empty package name: part <"+part+">, query <"+q+"> of "+uri); + } + data.addSysPackage(v); + } else if(k.equals(USR_PKG)) { if(v.length()==0) { throw new IllegalArgumentException("Empty package name: part <"+part+">, query <"+q+"> of "+uri); } - data.addPackage(v); + data.addUsrPackage(v); } else if(k.equals(ARG)) { if(v.length()==0) { throw new IllegalArgumentException("Empty argument name: part <"+part+">, query <"+q+"> of "+uri); @@ -313,7 +372,7 @@ public class LauncherUtil { } } else { // property key only - if( part.equals(PKG) || part.equals(ARG) ) { + if( part.equals(USR_PKG) || part.equals(ARG) ) { throw new IllegalArgumentException("Reserved key <"+part+"> in query <"+q+"> of "+uri); } data.setProperty(part, EMPTY); @@ -338,12 +397,13 @@ public class LauncherUtil { public static void main(String[] args) { if(args.length==0) { args = new String[] { - SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+PKG+"=jogamp.pack1&"+PKG+"=javax.pack2&"+PKG+"=com.jogamp.pack3&jogamp.common.debug=true&com.jogamp.test=false", - SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+PKG+"=jogamp.pack1&jogamp.common.debug=true&com.jogamp.test=false", - SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+PKG+"=jogamp.pack1", - SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+PKG+"=jogamp.pack1&"+PKG+"=javax.pack2&"+PKG+"=com.jogamp.pack3&jogamp.common.debug=true&com.jogamp.test=false&"+ARG+"=arg1&"+ARG+"=arg2=arg2value&"+ARG+"=arg3", - SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+PKG+"=jogamp.pack1&jogamp.common.debug=true&com.jogamp.test=false&"+ARG+"=arg1&"+ARG+"=arg2=arg2value&"+ARG+"=arg3", - SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+PKG+"=jogamp.pack1&"+ARG+"=arg1&"+ARG+"=arg2=arg2value&"+ARG+"=arg3" + SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+SYS_PKG+"=jogamp.pack1&"+SYS_PKG+"=javax.pack2&"+USR_PKG+"=com.jogamp.pack3&"+USR_PKG+"=com.jogamp.pack4&jogamp.common.debug=true&com.jogamp.test=false", + SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+SYS_PKG+"=jogamp.pack1&jogamp.common.debug=true&com.jogamp.test=false", + SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+USR_PKG+"=jogamp.pack1&jogamp.common.debug=true&com.jogamp.test=false", + SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+USR_PKG+"=jogamp.pack1&"+USR_PKG+"=com.jogamp.pack2", + SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+USR_PKG+"=jogamp.pack1&"+USR_PKG+"=javax.pack2&"+USR_PKG+"=com.jogamp.pack3&jogamp.common.debug=true&com.jogamp.test=false&"+ARG+"=arg1&"+ARG+"=arg2=arg2value&"+ARG+"=arg3", + SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+USR_PKG+"=jogamp.pack1&jogamp.common.debug=true&com.jogamp.test=false&"+ARG+"=arg1&"+ARG+"=arg2=arg2value&"+ARG+"=arg3", + SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+USR_PKG+"=jogamp.pack1&"+ARG+"=arg1&"+ARG+"=arg2=arg2value&"+ARG+"=arg3" }; } int errors = 0; diff --git a/src/java/jogamp/android/launcher/MainLauncher.java b/src/java/jogamp/android/launcher/MainLauncher.java index d4ac4ca..f37fa57 100644 --- a/src/java/jogamp/android/launcher/MainLauncher.java +++ b/src/java/jogamp/android/launcher/MainLauncher.java @@ -64,7 +64,7 @@ public class MainLauncher extends Activity { data = LauncherUtil.DataSet.create(uri); data.setSystemProperties(); - ClassLoader cl = ClassLoaderUtil.createClassLoader(this, data.getPackages(), false, Arrays.asList(frameworkAPKs)); + ClassLoader cl = ClassLoaderUtil.createClassLoader(this, data.getSysPackages(), data.getUsrPackages(), Arrays.asList(frameworkAPKs)); if(null != cl) { try { staticContextClazz = Class.forName("jogamp.common.os.android.StaticContext", true, cl); |