From 235f8b1cbff8ed13071d5c19c0be492c0b25cb78 Mon Sep 17 00:00:00 2001
From: Sven Gothel
+ * asset resource location protocol connection.
+ *
+ * See {@link AssetURLContext#resolve(String)} how resources are being resolved.
+ *
+ * The sub protocol URL of the resolved asset
+ * Example:
+ *
+ * Assuming the plain asset entry test/lala.txt
is being resolved by
+ * a class test.LaLaTest
, ie. using the asset aware ClassLoader,
+ * one would use the following asset aware filesystem layout:
+ *
+ *
+ * test/LaLaTest.class
+ * assets/test/lala.txt
+ *
+ *
+ * The above maybe on a plain filesystem, or within a JAR or an APK file,
+ * e.g. jogamp.test.apk
.
+ *
+ * The above would result in the following possible URLs
+ * reflecting the plain and resolved state of the asset URL:
+ *
+ * 0 Entry test/lala.txt
+ * 1 Plain asset:test/lala.txt
+ * 2 Resolved asset:jar:file:/data/app/jogamp.test.apk!/assets/test/lala.txt
+ *
+ *
+ *
+ * 3 Sub-URL jar:file:/data/app/jogamp.test.apk!/assets/test/lala.txt
+ *
+ * can be retrieved using {@link #getSubProtocol()}.
+ *
test/lala.txt
,
+ * which can be retrieved via {@link #getEntryName()}.
+ *
+ * + *
+ *
+ * The Android ClassLoader {@link jogamp.android.launcher.AssetDexClassLoader} + * resolves the resource as an asset URL in it's {@link ClassLoader#findResource(String)} implementation.
+ *+ * Currently we attach our asset {@link java.net.URLStreamHandlerFactory} + * to allow {@link java.net.URL} to handle asset URLs via our asset {@link java.net.URLStreamHandler} implementation. + *
+ */ +public class AssetURLConnection extends PiggybackURLConnectionasset
*/
+ public static final String asset_protocol = "asset";
+
+ /** The asset URL protocol prefix asset:
*/
+ public static final String asset_protocol_prefix = "asset:";
+
+ /**
+ * The optional asset folder name with ending slash assets/
.
+ * + * Note that the asset folder is not used on all platforms using the asset protocol + * and you should not rely on it, use {@link AssetURLConnection#getEntryName()}. + *
+ **/ + public static final String assets_folder = "assets/"; + + public static AssetURLContext create(final ClassLoader cl) { + return new AssetURLContext() { + @Override + public ClassLoader getClassLoader() { + return cl; + } + }; + } + + public static AssetURLStreamHandler createHandler(final ClassLoader cl) { + return new AssetURLStreamHandler(create(cl)); + } + + /** + * Create an asset URL, suitable even w/o the registered asset URLStreamHandler. + *+ * This is equivalent with: + *
+ * return new URL(null, path.startsWith("asset:") ? path : "asset:" + path, new AssetURLStreamHandler(cl)); + *+ * + * @param path resource path, with or w/o
asset:
prefix
+ * @param cl the ClassLoader used to resolve the location, see {@link #getClassLoader()}.
+ * @return
+ * @throws MalformedURLException
+ */
+ public static URL createURL(String path, ClassLoader cl) throws MalformedURLException {
+ return new URL(null, path.startsWith(asset_protocol_prefix) ? path : asset_protocol_prefix + path, createHandler(cl));
+ }
+
+ /**
+ * Create an asset URL, suitable only with the registered asset URLStreamHandler.
+ * + * This is equivalent with: + *
+ * return new URL(path.startsWith("asset:") ? path : "asset:" + path); + *+ * + * @param path resource path, with or w/o
asset:
prefix
+ * @return
+ * @throws MalformedURLException
+ */
+ public static URL createURL(String path) throws MalformedURLException {
+ return new URL(path.startsWith(asset_protocol_prefix) ? path : asset_protocol_prefix + path);
+ }
+
+ /**
+ * Returns the asset handler previously set via {@link #registerHandler(ClassLoader)},
+ * or null if none was set.
+ */
+ public static URLStreamHandler getRegisteredHandler() {
+ final GenericURLStreamHandlerFactory f = GenericURLStreamHandlerFactory.register();
+ return ( null != f ) ? f.getHandler(asset_protocol) : null;
+ }
+
+ /**
+ * Registers the generic URLStreamHandlerFactory via {@link GenericURLStreamHandlerFactory#register()}
+ * and if successful sets the asset handler
for the given ClassLoader cl
.
+ *
+ * @return true if successful, otherwise false
+ */
+ public static boolean registerHandler(ClassLoader cl) {
+ final GenericURLStreamHandlerFactory f = GenericURLStreamHandlerFactory.register();
+ if( null != f ) {
+ f.setHandler(asset_protocol, createHandler(cl));
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Returns an asset aware ClassLoader.
+ *
+ * The ClassLoader is required to find the asset resource
+ * via it's URL findResource(String)
implementation.
+ *
+ * It's URL findResource(String)
implementation shall return either
+ * an asset URL asset:sub-protocol
or just the sub-protocol URL.
+ *
+ * For example, on Android, we redirect all path
request to assets/path
.
+ *
+ * This implementation attempts to resolve path
in the following order:
+ *
new URL(path)
, use sub-protocol if asset URLnew File(path).toURI().toURL()
+ *
+ * In case of using the ClassLoader (2) and if running on Android,
+ * the {@link #assets_folder} is being prepended to path
if missing.
+ *
+ * This is the asset URLStreamHandler variation + * for manual use. + *
+ *+ * It requires passing a valid {@link AssetURLContext} + * for construction, hence it's not suitable for the pkg factory model. + *
+ */ +public class AssetURLStreamHandler extends URLStreamHandler { + AssetURLContext ctx; + + public AssetURLStreamHandler(AssetURLContext ctx) { + this.ctx = ctx; + } + + @Override + protected URLConnection openConnection(URL u) throws IOException { + final AssetURLConnection c = new AssetURLConnection(u, ctx); + c.connect(); + return c; + } + + +} diff --git a/src/java/com/jogamp/common/net/GenericURLStreamHandlerFactory.java b/src/java/com/jogamp/common/net/GenericURLStreamHandlerFactory.java new file mode 100644 index 0000000..79d7f71 --- /dev/null +++ b/src/java/com/jogamp/common/net/GenericURLStreamHandlerFactory.java @@ -0,0 +1,66 @@ +package com.jogamp.common.net; + +import java.net.URL; +import java.net.URLStreamHandler; +import java.net.URLStreamHandlerFactory; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.Map; + +public class GenericURLStreamHandlerFactory implements URLStreamHandlerFactory { + private static GenericURLStreamHandlerFactory factory = null; + + private final Maphandler
for protocol
.
+ *
+ * @return the previous set handler
, or null if none was set.
+ */
+ public synchronized final URLStreamHandler setHandler(String protocol, URLStreamHandler handler) {
+ return protocolHandlers.put(protocol, handler);
+ }
+
+ /**
+ * Returns the protocol
handler previously set via {@link #setHandler(String, URLStreamHandler)},
+ * or null if none was set.
+ */
+ public synchronized final URLStreamHandler getHandler(String protocol) {
+ return protocolHandlers.get(protocol);
+ }
+
+ @Override
+ public synchronized final URLStreamHandler createURLStreamHandler(String protocol) {
+ return getHandler(protocol);
+ }
+
+ /**
+ * Returns the singleton instance of the registered GenericURLStreamHandlerFactory
+ * or null if registration was not successful.
+ * + * Registration is only performed once. + *
+ */ + public synchronized static GenericURLStreamHandlerFactory register() { + if(null == factory) { + factory = AccessController.doPrivileged(new PrivilegedAction+ * The details of the sub-protocol can be queried using {@link #getSubProtocol()}. + *
+ *+ * See example in {@link AssetURLConnection}. + *
+ */ +public abstract class PiggybackURLConnection extends URLConnection { + protected URL subUrl; + protected URLConnection subConn; + protected I context; + + /** + * @param url the specific URL for this instance + * @param context the piggyback context, defining state independent code and constants + */ + protected PiggybackURLConnection(URL url, I context) { + super(url); + this.context = context; + } + + /** + *+ * Resolves the URL via {@link PiggybackURLContext#resolve(String)}, + * see {@link AssetURLContext#resolve(String)} for an example. + *
+ * + * {@inheritDoc} + */ + @Override + public synchronized void connect() throws IOException { + if(!connected) { + subConn = context.resolve(url.getPath()); + subUrl = subConn.getURL(); + connected = true; + } + } + + @Override + public InputStream getInputStream() throws IOException { + if(!connected) { + throw new IOException("not connected"); + } + return subConn.getInputStream(); + } + + /** + * Returns the entry name of the asset. + *+ * Plain asset:test/lala.txt + * Resolved asset:jar:file:/data/app/jogamp.test.apk!/assets/test/lala.txt + * Result test/lala.txt + *+ * @throws IOException is not connected + **/ + public abstract String getEntryName() throws IOException; + + /** + * Returns the resolved sub protocol of the asset or null, ie: + *
+ * Plain asset:test/lala.txt + * Resolved asset:jar:file:/data/app/jogamp.test.apk!/assets/test/lala.txt + * Result jar:file:/data/app/jogamp.test.apk!/assets/test/lala.txt + *+ * + * @throws IOException is not connected + */ + public URL getSubProtocol() throws IOException { + if(!connected) { + throw new IOException("not connected"); + } + return subUrl; + } +} diff --git a/src/java/com/jogamp/common/net/PiggybackURLContext.java b/src/java/com/jogamp/common/net/PiggybackURLContext.java new file mode 100644 index 0000000..2cb48b5 --- /dev/null +++ b/src/java/com/jogamp/common/net/PiggybackURLContext.java @@ -0,0 +1,18 @@ +package com.jogamp.common.net; + +import java.io.IOException; +import java.net.URLConnection; + +/** + * See {@link PiggybackURLConnection} for description and examples. + */ +public interface PiggybackURLContext { + + /** Returns the specific protocol, constant for this implementation. */ + public String getImplementedProtocol(); + + /** + * Resolving path to a URL sub protocol and return it's open URLConnection + **/ + public URLConnection resolve(String path) throws IOException; +} diff --git a/src/java/com/jogamp/common/net/asset/Handler.java b/src/java/com/jogamp/common/net/asset/Handler.java new file mode 100644 index 0000000..1063797 --- /dev/null +++ b/src/java/com/jogamp/common/net/asset/Handler.java @@ -0,0 +1,38 @@ +package com.jogamp.common.net.asset; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +import com.jogamp.common.net.AssetURLConnection; +import com.jogamp.common.net.AssetURLContext; + +/** + * {@link URLStreamHandler} to handle the asset protocol. + * + *
+ * This is the asset URLStreamHandler variation + * using this class ClassLoader for the pkg factory model. + *
+ */ +public class Handler extends URLStreamHandler { + static final AssetURLContext localCL = new AssetURLContext() { + @Override + public ClassLoader getClassLoader() { + return Handler.class.getClassLoader(); + } + }; + + public Handler() { + super(); + } + + @Override + protected URLConnection openConnection(URL u) throws IOException { + final AssetURLConnection c = new AssetURLConnection(u, localCL); + c.connect(); + return c; + } + +} diff --git a/src/java/com/jogamp/common/nio/AbstractBuffer.java b/src/java/com/jogamp/common/nio/AbstractBuffer.java index 322a617..985ba4f 100644 --- a/src/java/com/jogamp/common/nio/AbstractBuffer.java +++ b/src/java/com/jogamp/common/nio/AbstractBuffer.java @@ -39,6 +39,7 @@ import java.nio.Buffer; * @author Sven Gothel * @author Michael Bien */ +@SuppressWarnings("rawtypes") public abstract class AbstractBuffer implements NativeBuffer { protected final int elementSize; diff --git a/src/java/com/jogamp/common/os/AndroidVersion.java b/src/java/com/jogamp/common/os/AndroidVersion.java index b577631..8886273 100644 --- a/src/java/com/jogamp/common/os/AndroidVersion.java +++ b/src/java/com/jogamp/common/os/AndroidVersion.java @@ -32,9 +32,9 @@ public class AndroidVersion { static { final ClassLoader cl = AndroidVersion.class.getClassLoader(); - Class abvClass = null; + Class> abvClass = null; Object abvObject= null; - Class abvcClass = null; + Class> abvcClass = null; Object abvcObject= null; try { abvClass = ReflectionUtil.getClass(androidBuildVersion, true, cl); @@ -50,7 +50,7 @@ public class AndroidVersion { SDK_INT = getInt(abvClass, abvObject, "SDK_INT"); VERSION_CODES = getVersionCodes(abvcClass, abvcObject); String sdk_name = VERSION_CODES.get(new Integer(SDK_INT)); - SDK_NAME = ( null != sdk_name ) ? sdk_name : "SDK_"+SDK_INT ; + SDK_NAME = ( null != sdk_name ) ? sdk_name : "SDK_"+SDK_INT ; } else { CODENAME = null; INCREMENTAL = null; @@ -61,7 +61,7 @@ public class AndroidVersion { } } - private static final Mapcontext
's package name-path plus resourcePath
via context
's ClassLoader. This allows locations relative to JAR- and other URLs. context
's ClassLoader and the resourcePath
as is (filesystem)+ * Returns the resolved and open URLConnection or null if not found. + *
+ * * @see #getResource(String, ClassLoader) + * @see ClassLoader#getResource(String) + * @see ClassLoader#getSystemResource(String) */ - public static URL getResource(Class> context, String resourcePath) { + public static URLConnection getResource(Class> context, String resourcePath) { if(null == resourcePath) { return null; } - ClassLoader contextCL = (null!=context)?context.getClassLoader():null; - URL url = null; + ClassLoader contextCL = (null!=context)?context.getClassLoader():IOUtil.class.getClassLoader(); + URLConnection conn = null; if(null != context) { // scoping the path within the class's package String className = context.getName().replace('.', '/'); int lastSlash = className.lastIndexOf('/'); if (lastSlash >= 0) { String tmpPath = className.substring(0, lastSlash + 1) + resourcePath; - url = getResource(tmpPath, contextCL); + conn = getResource(tmpPath, contextCL); } if(DEBUG) { - System.err.println("IOUtil: found <"+resourcePath+"> within class package: "+(null!=url)); + System.err.println("IOUtil: found <"+resourcePath+"> within class package: "+(null!=conn)); } } else if(DEBUG) { System.err.println("IOUtil: null context"); } - if(null == url) { - url = getResource(resourcePath, contextCL); + if(null == conn) { + conn = getResource(resourcePath, contextCL); if(DEBUG) { - System.err.println("IOUtil: found <"+resourcePath+"> by classloader: "+(null!=url)); + System.err.println("IOUtil: found <"+resourcePath+"> by classloader: "+(null!=conn)); } } - return url; + return conn; } /** - * Locating a resource using the ClassLoader's facility if not null, - * the absolute URL and absolute file. + * Locating a resource using the ClassLoader's facilities. + *+ * Returns the resolved and connected URLConnection or null if not found. + *
* * @see ClassLoader#getResource(String) * @see ClassLoader#getSystemResource(String) * @see URL#URL(String) * @see File#File(String) */ - public static URL getResource(String resourcePath, ClassLoader cl) { + public static URLConnection getResource(String resourcePath, ClassLoader cl) { if(null == resourcePath) { return null; } if(DEBUG) { System.err.println("IOUtil: locating <"+resourcePath+">, has cl: "+(null!=cl)); } - URL url = null; - if (cl != null) { - url = cl.getResource(resourcePath); - if(!urlExists(url, "cl.getResource()")) { - url = null; - } - } - if(null == url) { - url = ClassLoader.getSystemResource(resourcePath); - if(!urlExists(url, "cl.getSystemResource()")) { - url = null; - } - } - if(null == url) { + if(resourcePath.startsWith(AssetURLContext.asset_protocol_prefix)) { try { - url = new URL(resourcePath); - if(!urlExists(url, "new URL()")) { - url = null; - } - } catch (Throwable e) { + return AssetURLContext.createURL(resourcePath, cl).openConnection(); + } catch (IOException ioe) { if(DEBUG) { System.err.println("IOUtil: Catched Exception:"); - e.printStackTrace(); - } + ioe.printStackTrace(); + } + return null; } - } - if(null == url) { + } else { try { - File file = new File(resourcePath); - if(file.exists()) { - url = toURLSimple(file); - } - } catch (Throwable e) { + return AssetURLContext.resolve(resourcePath, cl); + } catch (IOException ioe) { if(DEBUG) { System.err.println("IOUtil: Catched Exception:"); - e.printStackTrace(); + ioe.printStackTrace(); } } - if(DEBUG) { - System.err.println("IOUtil: file.exists("+resourcePath+") - "+(null!=url)); - } } - return url; + return null; } /** @@ -411,11 +415,11 @@ public class IOUtil { return null; } - while (baseLocation != null && relativeFile.startsWith("../")) { - baseLocation = baseLocation.getParentFile(); - relativeFile = relativeFile.substring(3); - } if (baseLocation != null) { + while (relativeFile.startsWith("../")) { + baseLocation = baseLocation.getParentFile(); + relativeFile = relativeFile.substring(3); + } final File file = new File(baseLocation, relativeFile); // Handle things on Windows return slashify(file.getPath(), false, false); @@ -424,55 +428,119 @@ public class IOUtil { } /** - * Generates a path for the 'relativeFile' relative to the 'baseLocation'. + * @param path assuming a slashified path beginning with "/" as it's root directory, either denotes a file or directory. + * @return parent of path + * @throws MalformedURLException if path is empty or has parent directory available + */ + public static String getParentOf(String path) throws MalformedURLException { + final int pl = null!=path ? path.length() : 0; + if(pl == 0) { + throw new MalformedURLException("path is empty <"+path+">"); + } + + final int e = path.lastIndexOf("/"); + if( e < 0 ) { + throw new MalformedURLException("path contains no '/' <"+path+">"); + } + if( e == 0 ) { + // path is root directory + throw new MalformedURLException("path has no parents <"+path+">"); + } + if( e < pl - 1 ) { + // path is file, return it's parent directory + return path.substring(0, e+1); + } + final int j = path.lastIndexOf("!") + 1; // '!' Separates JARFile entry -> local start of path + // path is a directory .. + final int p = path.lastIndexOf("/", e-1); + if( p >= j) { + return path.substring(0, p+1); + } + throw new MalformedURLException("parent of path contains no '/' <"+path+">"); + } + + /** + * Generates a path for the 'relativeFile' relative to the 'baseLocation', + * hence the result is a absolute location. * - * @param baseLocation denotes a URL to a file + * @param baseLocation denotes a URL to a directory if ending w/ '/', otherwise we assume a file * @param relativeFile denotes a relative file to the baseLocation's parent directory + * @throws MalformedURLException */ - public static String getRelativeOf(URL baseLocation, String relativeFile) { - String urlPath = baseLocation.getPath(); + public static URL getRelativeOf(URL baseLocation, String relativeFile) throws MalformedURLException { + final String scheme = baseLocation.getProtocol(); + final String auth = baseLocation.getAuthority(); + String path = baseLocation.getPath(); + String query = baseLocation.getQuery(); + String fragment = baseLocation.getRef(); - if ( baseLocation.toString().startsWith("jar") ) { - JarURLConnection jarConnection; - try { - jarConnection = (JarURLConnection) baseLocation.openConnection(); - urlPath = jarConnection.getEntryName(); - } catch (IOException e) { - e.printStackTrace(); - return null; - } + if(!path.endsWith("/")) { + path = getParentOf(path); } - - // Try relative path first - return getRelativeOf(new File(urlPath).getParentFile(), relativeFile); + while (relativeFile.startsWith("../")) { + path = getParentOf(path); + relativeFile = relativeFile.substring(3); + } + return compose(scheme, auth, path, relativeFile, query, fragment); } + public static URL compose(String scheme, String auth, String path1, String path2, String query, String fragment) throws MalformedURLException { + StringBuffer sb = new StringBuffer(); + if(null!=scheme) { + sb.append(scheme); + sb.append(":"); + } + if(null!=auth) { + sb.append("//"); + sb.append(auth); + } + if(null!=path1) { + sb.append(path1); + } + if(null!=path2) { + sb.append(path2); + } + if(null!=query) { + sb.append("?"); + sb.append(query); + } + if(null!=fragment) { + sb.append("#"); + sb.append(fragment); + } + return new URL(sb.toString()); + } + /** - * Returns true, if the URL exists and a connection could be opened. + * Returns the connected URLConnection, or null if not url is not available */ - public static boolean urlExists(URL url) { - return urlExists(url, "."); + public static URLConnection openURL(URL url) { + return openURL(url, "."); } - public static boolean urlExists(URL url, String dbgmsg) { - boolean v = false; + /** + * Returns the connected URLConnection, or null if not url is not available + */ + public static URLConnection openURL(URL url, String dbgmsg) { if(null!=url) { try { - url.openConnection(); - v = true; + final URLConnection c = url.openConnection(); + c.connect(); // redundant if(DEBUG) { System.err.println("IOUtil: urlExists("+url+") ["+dbgmsg+"] - true"); } + return c; } catch (IOException ioe) { if(DEBUG) { - System.err.println("IOUtil: urlExists("+url+") ["+dbgmsg+"] - false: "+ioe.getMessage()); + System.err.println("IOUtil: urlExists("+url+") ["+dbgmsg+"] - false - "+ioe.getClass().getSimpleName()+": "+ioe.getMessage()); + ioe.printStackTrace(); } } } else if(DEBUG) { System.err.println("IOUtil: no url - urlExists(null) ["+dbgmsg+"]"); } - return v; + return null; } /** @@ -507,7 +575,7 @@ public class IOUtil { * On Android atemp
folder relative to the applications local folder
* (see {@link Context#getDir(String, int)}) is returned, if
* the Android application/activity has registered it's Application Context
- * via {@link StaticContext#setContext(Context)}.
+ * via {@link StaticContext#init(Context, ClassLoader)}.
* This allows using the temp folder w/o the need for sdcard
* access, which would be the java.io.tempdir
location on Android!
*
@@ -517,7 +585,7 @@ public class IOUtil {
* @throws RuntimeException is the property java.io.tmpdir
or the resulting temp directory is invalid
*
* @see PropertyAccess#getProperty(String, boolean, java.security.AccessControlContext)
- * @see StaticContext#setContext(Context)
+ * @see StaticContext#init(Context, ClassLoader)
* @see Context#getDir(String, int)
*/
public static File getTempRoot(AccessControlContext acc)
diff --git a/src/java/jogamp/android/launcher/ActivityLauncher.java b/src/java/jogamp/android/launcher/ActivityLauncher.java
index 04c898e..7e2d86d 100644
--- a/src/java/jogamp/android/launcher/ActivityLauncher.java
+++ b/src/java/jogamp/android/launcher/ActivityLauncher.java
@@ -32,7 +32,6 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.app.Activity;
-import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.widget.TextView;
@@ -42,7 +41,7 @@ public class ActivityLauncher extends Activity {
static final String TAG = "NEWTLauncherActivity";
TextView tv = null;
Method mOnCreate, mOnDestroy, mOnPause, mOnRestart, mOnResume,
- mOnStart, mOnStop, mSetIsInvokedByExternalActivity;
+ mOnStart, mOnStop, mSetRootActivity;
Class> activityClazz = null;
Object activityObject = null;
@@ -55,7 +54,7 @@ public class ActivityLauncher extends Activity {
final LauncherUtil.DataSet data = LauncherUtil.DataSet.create(uri);
data.setSystemProperties();
- ClassLoader cl = ClassLoaderUtil.createJogampClassLoaderSingleton(this, data.getPackages());
+ ClassLoader cl = ClassLoaderUtil.createClassLoader(this, data.getPackages(), false);
if(null != cl) {
try {
activityClazz = Class.forName(data.getActivityName(), true, cl);
@@ -69,7 +68,7 @@ public class ActivityLauncher extends Activity {
mOnResume = activityClazz.getMethod("onResume");
mOnStart = activityClazz.getMethod("onStart");
mOnStop = activityClazz.getMethod("onStop");
- mSetIsInvokedByExternalActivity = activityClazz.getMethod("setIsInvokedByExternalActivity", Activity.class);
+ mSetRootActivity = activityClazz.getMethod("setRootActivity", Activity.class);
} catch (Exception e) {
Log.d(TAG, "error: "+e, e);
throw new RuntimeException(e);
@@ -78,13 +77,13 @@ public class ActivityLauncher extends Activity {
if( null == mOnCreate || null == mOnDestroy || null == mOnPause ||
null == mOnRestart || null == mOnResume ||
- null == mSetIsInvokedByExternalActivity ) {
+ null == mSetRootActivity ) {
RuntimeException e = new RuntimeException("XXX - incomplete method set");
Log.d(TAG, "error: "+e, e);
throw e;
}
- callMethod(activityObject, mSetIsInvokedByExternalActivity, this);
+ callMethod(activityObject, mSetRootActivity, this);
callMethod(activityObject, mOnCreate, savedInstanceState);
Log.d(TAG, "onCreate - X");
diff --git a/src/java/jogamp/android/launcher/AssetDexClassLoader.java b/src/java/jogamp/android/launcher/AssetDexClassLoader.java
new file mode 100644
index 0000000..ec3ae6c
--- /dev/null
+++ b/src/java/jogamp/android/launcher/AssetDexClassLoader.java
@@ -0,0 +1,29 @@
+package jogamp.android.launcher;
+
+import java.net.URL;
+
+import android.util.Log;
+
+import dalvik.system.DexClassLoader;
+
+public class AssetDexClassLoader extends DexClassLoader {
+ private static final boolean DEBUG = false;
+ private static final String assets_folder = "assets/";
+
+ public AssetDexClassLoader(String dexPath, String dexOutputDir, String libPath, ClassLoader parent) {
+ super(dexPath, dexOutputDir, libPath, parent);
+ if(DEBUG) {
+ Log.d(AssetDexClassLoader.class.getSimpleName(), "ctor: dexPath " + dexPath + ", dexOutputDir " + dexOutputDir + ", libPath " + libPath + ", parent " + parent);
+ }
+ }
+
+ @Override
+ public URL findResource(String name) {
+ final String assetName = name.startsWith(assets_folder) ? name : assets_folder + name ;
+ URL url = super.findResource(assetName);
+ if(DEBUG) {
+ Log.d(AssetDexClassLoader.class.getSimpleName(), "findResource: " + name + " -> " + assetName + " -> " + url);
+ }
+ return url;
+ }
+}
diff --git a/src/java/jogamp/android/launcher/ClassLoaderUtil.java b/src/java/jogamp/android/launcher/ClassLoaderUtil.java
index 319a0fd..85c0b94 100644
--- a/src/java/jogamp/android/launcher/ClassLoaderUtil.java
+++ b/src/java/jogamp/android/launcher/ClassLoaderUtil.java
@@ -29,89 +29,83 @@
package jogamp.android.launcher;
import java.io.File;
-import java.lang.ref.WeakReference;
-import java.lang.reflect.Field;
-import java.util.HashMap;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
-import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.util.Log;
-import dalvik.system.DexClassLoader;
public class ClassLoaderUtil {
private static final String TAG = "JogampClassLoader";
- public static final String packageGlueGen = "com.jogamp.common";
- public static final String packageJogl = "javax.media.opengl"; // FIXME: a 'performance' hack
+ // 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;
- public static final String dexPathName= "jogampDex";
+ // 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 ClassLoader jogAmpClassLoader = null;
- /**
- *
- * @param ctx
- * @param userPackageNames list of user package names, the last entry shall reflect the Activity
- * @return
- */
- public static synchronized ClassLoader createJogampClassLoaderSingleton(Context ctx, List