changeset 4989:3e59deb21105

Android: Create abstraction layer for application launcher to better support alternative VMs.
author tb115823 <Tomas.Brandalik@oracle.com>
date Fri, 06 Sep 2013 13:15:02 +0200
parents 655f1ead4bc8
children 73c7426d2a0b
files modules/graphics/src/android/java/com/oracle/dalvik/DalvikLauncher.java modules/graphics/src/android/java/com/oracle/dalvik/FXActivity.java modules/graphics/src/android/java/com/oracle/dalvik/FXActivity.java.jfx78 modules/graphics/src/android/java/com/oracle/dalvik/JavaSELauncher.java modules/graphics/src/android/java/com/oracle/dalvik/Launcher.java modules/graphics/src/main/native-glass/lens/android/android.c modules/web/src/android/native/android_webview.c
diffstat 7 files changed, 466 insertions(+), 549 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/graphics/src/android/java/com/oracle/dalvik/DalvikLauncher.java	Fri Sep 06 13:15:02 2013 +0200
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.dalvik;
+
+import android.app.Activity;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.util.Log;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+public class DalvikLauncher implements Launcher {
+
+    private static final String TAG                                     = "DalvikLauncher";
+    private static final String JAVAFX_APPLICATION_APPLICATION          = "javafx.application.Application";
+	private static final String COM_SUN_JAVAFX_APPLICATION_LAUNCHERIMPL = "com.sun.javafx.application.LauncherImpl";
+	private static final String LAUNCH_APPLICATION_METHOD               = "launchApplication";
+	private static final String MAIN_METHOD                             = "main";
+    private static final String META_DATA_MAIN_CLASS                    = "main.class";
+	private static final String META_DATA_PRELOADER_CLASS               = "preloader.class";    
+    private static final String ANDROID_PROPERTY_PREFIX                 = "android.";
+    
+    private static final Class[] LAUNCH_APPLICATION_ARGS = new Class[] {
+			Class.class, Class.class, (new String[0]).getClass() };
+
+	private static final Class[] MAIN_METHOD_ARGS = new Class[] { 
+			(new String[0]).getClass() };
+    
+    private static boolean fxApplicationLaunched = false;
+	private static boolean fxApplicationLaunching = false;
+    
+    private Activity    activity;
+    private Bundle      metadata;
+    
+    public void launchApp(Activity a, Bundle metadata) {
+        this.activity = a;
+        this.metadata = metadata;
+        Properties userProperties = new Properties();
+		try {
+			userProperties.load(DalvikLauncher.class.getResourceAsStream("/javafx.platform.properties"));
+			String key = null;
+            for(Entry<Object, Object> e:userProperties.entrySet()) {
+                key = (String)e.getKey();
+                System.setProperty(key.startsWith(ANDROID_PROPERTY_PREFIX) ?
+                    key.substring(ANDROID_PROPERTY_PREFIX.length()) : key,
+                    (String)e.getValue());
+			}
+			System.getProperties().list(System.out);
+			
+		} catch (IOException e) {
+			throw new RuntimeException("Can't load properties", e);
+		}
+        
+        Log.v(TAG, "Launch JavaFX application on dalvik vm.");
+        try {            
+			final Class applicationClass = resolveApplicationClass();
+			final Class preloaderClass = resolvePreloaderClass();
+			final Class javafxApplicationClass = Class.forName(JAVAFX_APPLICATION_APPLICATION);
+			final Class javafxLauncherClass = Class.forName(COM_SUN_JAVAFX_APPLICATION_LAUNCHERIMPL);
+	
+			final Method launchMethod = javafxLauncherClass.getMethod(
+					LAUNCH_APPLICATION_METHOD, LAUNCH_APPLICATION_ARGS);
+					
+            Log.v(TAG, String.format("application class: [%s]\n"
+                    + "preloader class: [%s]\n"
+                    + "javafx application class: [%s]\n"
+                    + "javafx launcher class: [%s]\n"
+                    + "launch application method: [%s]",
+                    applicationClass, 
+                    preloaderClass, 
+                    javafxApplicationClass, 
+                    javafxLauncherClass,
+                    launchMethod));
+			
+			new Thread(new Runnable() {
+				public void run() {
+					fxApplicationLaunching = true;					
+					try {
+						if (javafxApplicationClass.isAssignableFrom(applicationClass)) {
+							launchMethod.invoke(null, new Object[] {
+									applicationClass, preloaderClass,
+									new String[] {} });
+						} else {
+							Method mainMethod = applicationClass.getMethod(
+									MAIN_METHOD, MAIN_METHOD_ARGS);
+							mainMethod.invoke(null,
+									new Object[] { new String[] {} });
+						}
+					} catch (Exception e) {
+						e.printStackTrace();
+					}
+					fxApplicationLaunched = true;
+					fxApplicationLaunching = false;
+				}
+			}, "Prelauncher Thread").start();
+	
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+    }
+    
+    private Class resolveApplicationClass()
+			throws PackageManager.NameNotFoundException, ClassNotFoundException {
+
+		Class clazz = null;
+        String applicationClassName = metadata.getString(META_DATA_MAIN_CLASS);
+		if (applicationClassName != null && applicationClassName.length() > 0) {
+			clazz = Class.forName(applicationClassName);
+		}
+		return clazz;
+	}
+    
+    private Class resolvePreloaderClass()
+			throws PackageManager.NameNotFoundException, ClassNotFoundException {
+
+		Class clazz = null;
+        String className = metadata.getString(META_DATA_PRELOADER_CLASS);
+		if (className != null && className.length() > 0) {
+			clazz = Class.forName(className);
+		}
+		return clazz;
+	}
+    
+}
--- a/modules/graphics/src/android/java/com/oracle/dalvik/FXActivity.java	Tue Sep 03 09:47:27 2013 +0200
+++ b/modules/graphics/src/android/java/com/oracle/dalvik/FXActivity.java	Fri Sep 06 13:15:02 2013 +0200
@@ -24,10 +24,6 @@
  */
 package com.oracle.dalvik;
 
-import java.io.File;
-import java.io.FilenameFilter;
-import java.util.ArrayList;
-import java.util.List;
 
 import android.app.Activity;
 import android.content.Context;
@@ -35,7 +31,6 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.graphics.PixelFormat;
-import android.os.AsyncTask;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -53,28 +48,18 @@
         SurfaceHolder.Callback2 {
 	
     private static final String TAG     = "FXActivity";
-    private static final String TAG_JVM = "JVM";
-    private static final String JAR     = ".jar";
     
-    private static final String META_DATA_MAIN_CLASS = "main.class";
-    private static final String META_DATA_JVM_ARGS   = "jvm.args";
-    private static final String META_DATA_APP_ARGS   = "app.args";
-    private static final String META_DATA_DEBUG_PORT = "debug.port";
-    private static final String ANDROID_WEBVIEW = "android_webview";
-    private static final String GLASS_LENS_ANDROID = "glass_lens_android";
+    private static final String GLASS_LENS_ANDROID_LIB      = "glass_lens_android";
+    private static final String META_DATA_LAUNCHER_CLASS    = "launcher.class";
+    private static final String DEFAULT_LAUNCHER_CLASS      = "com.oracle.dalvik.JavaSELauncher";
+    
+    private static FXActivity   instance;
+    private static Launcher     launcher;
+    private static FrameLayout  mViewGroup;
+    private static SurfaceView  mView;
 
-    static {        
-        System.loadLibrary("vmlauncher");
-    }
-    private static FXActivity instance;
-    private static FrameLayout mViewGroup;
-    private static SurfaceView mView;
-
-    private String            appDataDir;
-    private String            storageDir;    
-    private NativePipeReader  reader;
-    private InputMethodManager imm;   
-    private String ldPath;
+    private String              appDataDir;
+    private InputMethodManager  imm;   
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -93,51 +78,71 @@
         mViewGroup = new FrameLayout(this);
         mViewGroup.addView(mView);
         setContentView(mViewGroup);
-        instance = this;
-        reader = NativePipeReader.getDefaultReader(textListener);
-        reader.start();
-        initDirInfo();
-        installJVMIfNeeded();
-        System.loadLibrary(GLASS_LENS_ANDROID);
-        System.loadLibrary(ANDROID_WEBVIEW);
+        instance = this;     
+        Log.v(TAG, "Loading glass native library.");
+        System.loadLibrary(GLASS_LENS_ANDROID_LIB);        
+    }
+    
+    private Bundle getMetadata() {
+        try {
+            ActivityInfo ai = FXActivity.this.getPackageManager().getActivityInfo(
+                    getIntent().getComponent(), PackageManager.GET_META_DATA);
+            return ai.metaData;
+
+        } catch(NameNotFoundException e) {
+            throw new RuntimeException("Error getting activity info", e);
+        }
     }
 
+    private void getLauncherAndLaunchApplication() {
+        Bundle metaData = getMetadata();
+        String launcherClass = metaData.getString(
+                META_DATA_LAUNCHER_CLASS,
+                DEFAULT_LAUNCHER_CLASS);
+        try {
+            Class clazz = Class.forName(launcherClass);
+            launcher = (Launcher)clazz.newInstance();
+            launcher.launchApp(this, metaData);
+            
+        } catch (Exception ex) {
+            throw new RuntimeException("Did not created correct launcher.", ex);
+        }
+    }
+    
     @Override
     protected void onDestroy() {
         android.os.Process.killProcess(android.os.Process.myPid());
         super.onDestroy();
     }
     
-    
-
     public static FXActivity getInstance() {
         return instance;
     }
 
-    public String getLDPath() {
+    public String getDataDir() {
         if (appDataDir == null) {
             appDataDir = this.getApplicationInfo().dataDir;
-        }
-        if (ldPath == null) {
-            ldPath = appDataDir + "/lib";
-        }
-        return ldPath;
+        }        
+        return appDataDir;
     }
-
+    
     public static ViewGroup getViewGroup() {
         return mViewGroup;
     }    
 	
     @Override
     public void surfaceCreated(SurfaceHolder holder) {
-            _surfaceChanged(holder.getSurface());
+        Log.v(TAG, "Surface created.");
+        _surfaceChanged(holder.getSurface());
+        if (launcher == null) {
+            getLauncherAndLaunchApplication();
+        }
     }
 
     @Override
     public void surfaceChanged(SurfaceHolder holder, int format, int width,
                     int height) {
             _surfaceChanged(holder.getSurface(), format, width, height);
-
     }
 
     @Override
@@ -170,162 +175,6 @@
         Log.e(TAG, "VM SHUTDOWN");
         finish();
     }
-
-    private void installJVMIfNeeded() {
-        new InstallerTask().execute();
-    }
-	
-    private void runJVM() {
-        Log.i(TAG, "Launch JVM + application");
-        JvmArgs args = new JvmArgs(appDataDir);
-        VMLauncher.initialize(args.getJavaHome());
-        VMLauncher.runOnDebugPort(args.getDebugPort(),
-                                  args.getArgArray());
-    }
-	
-    private class InstallerTask extends AsyncTask<Void, Void, Void> {
-        protected Void doInBackground(Void... args) {
-           Log.i(TAG, "Installing JVM");
-            AppDataInstaller installer = 
-                new AppDataInstaller(storageDir,
-                    FXActivity.this.getApplicationContext().getAssets());
-            installer.install();
-            return null;
-        }
-    protected void onPostExecute(Void result) {
-            runJVM();
-        }
-    }
-	
-    private NativePipeReader.OnTextReceivedListener textListener = 
-            new NativePipeReader.OnTextReceivedListener() {
-                public void onTextReceived(String text) {
-                    Log.v(TAG_JVM, text);
-                }
-            };
-
-    private void initDirInfo() {
-        if (appDataDir == null) {
-            appDataDir = this.getApplicationInfo().dataDir;
-        }
-        storageDir = appDataDir + "/storage";
-    }
-	
-    private class JvmArgs {
-        private List<String> argList = new ArrayList<String>();
-        private String javaHome;
-
-        public JvmArgs(String appDir) {
-            String jvmRunCommand =
-                   "-Djava.library.path="
-                     + appDir + "/lib|"
-                     + "-Djava.home="
-                     + appDir + "/storage/jvm|"
-                     + "-Dsun.boot.library.path="
-                     + appDir + "/storage/jvm/lib|"
-                     + "-cp|"
-                     + getClasspath(appDir)
-                     + "|"                                         
-                     + "-Djavafx.platform=android|"
-                     + "-Djavafx.runtime.path="
-                     + appDir +"/storage/lib|"
-                     + getCustomJVMArgs()
-                     + "|"
-                     + getMainClass()
-                     + "|"
-                     + getApplicationArgs();
-
-            createArgList(jvmRunCommand);
-        }
-
-        private String[] listFiles(String dir, final String suffix) {
-            File dirf = new File(dir);
-            if (!dirf.exists()) {
-                return new String[]{};
-            }
-            String[] files = dirf.list(new FilenameFilter() {           
-                @Override
-                public boolean accept(File dir, String filename) {      
-                    return filename.endsWith(suffix);
-                }
-            });
-            return files;
-        }
-
-        private String getClasspath(String appDir) {
-            final String libDir = appDir + "/storage/lib/";
-            String[] libfiles = listFiles(libDir, JAR);
-            if (libfiles.length == 0) {
-                return "";
-            }
-            StringBuilder sb = new StringBuilder();
-            for(String file: libfiles) {
-                sb.append(libDir);
-                sb.append(file);
-                sb.append(File.pathSeparatorChar);
-            }
-            int len = sb.length();
-            return sb.substring(0, len - 1);
-        }
-
-        private String getMainClass() {
-             return getMetadata().getString(META_DATA_MAIN_CLASS);
-        }
-
-        private String getCustomJVMArgs() {
-             return getMetadata().getString(META_DATA_JVM_ARGS);
-        }
-
-        private String getApplicationArgs() {
-             return getMetadata().getString(META_DATA_APP_ARGS);
-        }
-
-        private int getDebugPort() {            
-             return getMetadata().getInt(META_DATA_DEBUG_PORT, 0);
-        }
-
-        private Bundle getMetadata() {
-            try {
-                ActivityInfo ai = FXActivity.this.getPackageManager().getActivityInfo(
-                        getIntent().getComponent(), PackageManager.GET_META_DATA);
-                return ai.metaData;
-
-            } catch(NameNotFoundException e) {
-                throw new RuntimeException("Error getting activity info", e);
-            }
-        }
-
-        public void createArgList(String args) {
-            if (args != null) {
-                String sep = (args.contains("|")) ? "\\|" : " ";
-                for (String arg : args.split(sep)) {
-                    arg = arg.trim();
-                    if (arg.length() > 0) {
-                        this.argList.add(arg);
-                        if (javaHome == null) {
-                            String[] pair = arg.split("\\=");
-                            Log.v(TAG, "arg = " + arg);
-                            Log.v(TAG, "pair.length = " + pair.length);
-                            if (pair.length == 2) {
-                                if ("-Djava.home".equals(pair[0])) {
-                                    Log.v(TAG, "Setting javaHome to " + pair[1]);
-                                    javaHome = pair[1];
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-        
-        public String[] getArgArray() {
-            return argList.toArray(new String[0]);
-        }
-
-        public String getJavaHome() {
-           return javaHome;
-        }
-    }
 	
     class InternalSurfaceView extends SurfaceView {
 
--- a/modules/graphics/src/android/java/com/oracle/dalvik/FXActivity.java.jfx78	Tue Sep 03 09:47:27 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,333 +0,0 @@
-package com.oracle.dalvik;
-
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.util.Map.Entry;
-import java.util.Properties;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Configuration;
-import android.graphics.PixelFormat;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.FrameLayout;
-
-public class FXActivity extends Activity implements SurfaceHolder.Callback, SurfaceHolder.Callback2 {
-
-	private static final String TAG = "FXActivity";
-	
-	private static final String JAVAFX_APPLICATION_APPLICATION = "javafx.application.Application";
-
-	private static final String COM_SUN_JAVAFX_APPLICATION_LAUNCHERIMPL = "com.sun.javafx.application.LauncherImpl";
-
-	private static final String LAUNCH_APPLICATION_METHOD = "launchApplication";
-
-	private static final String MAIN_METHOD = "main";
-
-	private static final Class[] LAUNCH_APPLICATION_ARGS = new Class[] {
-			Class.class, Class.class, (new String[0]).getClass() };
-
-	private static final Class[] MAIN_METHOD_ARGS = new Class[] { 
-			(new String[0]).getClass() };
-
-//	private static final String JFX_APPLICATION_ATTRIBUTE = "JavaFX-Application-Class";
-    private static final String META_DATA_MAIN_CLASS = "main.class";
-	private static final String JFX_PRELOADER_ATTRIBUTE = "preloader.class";
-//	private static final String JFX_MAIN_ATTRIBUTE = "main.class";
-    private static final String GLASS_LENS_ANDROID = "glass_lens_android";
-	
-
-	private static int orientation;		
-//	private static FXActivity instance;
-	private static boolean fxApplicationLaunched = false;
-	private static boolean fxApplicationLaunching = false;
-	
-    private static FXActivity instance;
-    private static FrameLayout mViewGroup;
-    private static SurfaceView mView;
-
-    private String            appDataDir;
-    private String            storageDir;    
-    private NativePipeReader  reader;
-    private InputMethodManager imm;   
-    private String ldPath;
-    
-	public FXActivity() {
-		super();
-		
-		Properties userProperties = new Properties();
-//		try {
-//			userProperties.load(FXActivity.class.getResourceAsStream("/javafx.platform.properties"));
-//			for(Entry<Object, Object> e:userProperties.entrySet()) {
-//				System.setProperty((String)e.getKey(), (String)e.getValue());
-//			}
-//			System.getProperties().list(System.out);
-//			
-//		} catch (IOException e) {
-//			e.printStackTrace();
-//		}
-	}
-	
-//	public static FXActivity getInstance() {
-//		if (instance == null) {
-//			System.err.println("Activity not initialized.");
-//		}
-//		return instance;
-//	}
-	
-	@Override
-	public void onCreate(final Bundle savedInstanceState) {
-		super.onCreate(savedInstanceState);
-		
-		//DEBUGGING
-		//Debug.waitForDebugger();										
-		//DEBUGGING
-		
-//        FXActivity.instance = this;    
-        
-        getWindow().requestFeature(Window.FEATURE_NO_TITLE);
-        getWindow().setSoftInputMode(
-                WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED
-                | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
-        getWindow().setFormat(PixelFormat.RGBA_8888);
-
-        imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
-
-        mView = new FXActivity.InternalSurfaceView(this);
-        mView.getHolder().addCallback(this);        
-        mViewGroup = new FrameLayout(this);
-        mViewGroup.addView(mView);
-        setContentView(mViewGroup);
-        instance = this;        
-        System.loadLibrary(GLASS_LENS_ANDROID);
-//        System.loadLibrary(ANDROID_WEBVIEW);
-        
-        //AndroidViewGroup is FrameLayout and holds GLSurfaceView. 
-//        setContentView(AndroidViewGroup.getInstance());
-    	
-        //launch main class
-    	launchFXApplication();
-	}
-	
-    public static FXActivity getInstance() {
-        return instance;
-    }
-
-    public String getLDPath() {
-        if (appDataDir == null) {
-            appDataDir = this.getApplicationInfo().dataDir;
-        }
-        if (ldPath == null) {
-            ldPath = appDataDir + "/lib";
-        }
-        return ldPath;
-    }
-
-    public static ViewGroup getViewGroup() {
-        return mViewGroup;
-    }    
-	
-    @Override
-    public void surfaceCreated(SurfaceHolder holder) {
-            _surfaceChanged(holder.getSurface());
-    }
-
-    @Override
-    public void surfaceChanged(SurfaceHolder holder, int format, int width,
-                    int height) {
-            _surfaceChanged(holder.getSurface(), format, width, height);
-
-    }
-
-    @Override
-    public void surfaceDestroyed(SurfaceHolder holder) {
-            _surfaceChanged(null);
-    }
-
-    @Override
-    public void surfaceRedrawNeeded(SurfaceHolder holder) {
-            _surfaceRedrawNeeded(holder.getSurface());		
-    }
-
-    private native void _surfaceChanged(Surface surface);
-
-    private native void _surfaceChanged(Surface surface, int format, int width, int height);
-
-    private native void _surfaceRedrawNeeded(Surface surface);
-
-    private void showIME() {
-        mView.requestFocus();
-        imm.showSoftInput(mView, 0);
-    }
-
-    private void hideIME() {
-        mView.requestFocus();
-        imm.hideSoftInputFromWindow(mView.getWindowToken(), 0);
-    }
-    
-	@Override
-	public void onConfigurationChanged(Configuration newConfig) {
-		super.onConfigurationChanged(newConfig);
-//		if (newConfig.orientation != FXActivity.orientation) {
-//			Log.d(TAG, "orientation has changed");
-//			AndroidApplication.getInstance().notifyScreenSettingsChanged();
-//		}
-	}
-	
-	@Override
-	protected void onStart() {
-		super.onStart();
-		Log.d("onStart", "Activity started");
-//		Configuration startingConfiguration = getResources().getConfiguration();
-//		orientation = startingConfiguration.orientation;
-	}
-	
-	@Override
-	protected void onPause() {		
-		super.onPause();
-		Log.d("onPause", "Activity paused");
-	}
-	
-	@Override
-	protected void onResume() {
-		super.onResume();
-		Log.d("onResume", "Activity resumed");
-	}
-	
-	@Override
-	protected void onStop() {
-		super.onStop();
-		Log.d("onStop", "Activity stoped");
-	}
-	
-	@Override
-	protected void onRestart() {
-		super.onRestart();
-		Log.d("onRestart", "Activity re-started");
-	}
-	
-	public void launchFXApplication() {
-	    try {
-			final Class applicationClass = resolveApplicationClass();
-			final Class preloaderClass = resolvePreloaderClass();
-			final Class javafxApplicationClass = Class.forName(JAVAFX_APPLICATION_APPLICATION);
-			final Class javafxLauncherClass = Class.forName(COM_SUN_JAVAFX_APPLICATION_LAUNCHERIMPL);
-	
-			final Method launchMethod = javafxLauncherClass.getMethod(
-					LAUNCH_APPLICATION_METHOD, LAUNCH_APPLICATION_ARGS);
-						
-			
-			new Thread(new Runnable() {
-				public void run() {
-					fxApplicationLaunching = true;					
-					try {
-						if (javafxApplicationClass.isAssignableFrom(applicationClass)) {
-							launchMethod.invoke(null, new Object[] {
-									applicationClass, preloaderClass,
-									new String[] {} });
-						} else {
-							Method mainMethod = applicationClass.getMethod(
-									MAIN_METHOD, MAIN_METHOD_ARGS);
-							mainMethod.invoke(null,
-									new Object[] { new String[] {} });
-						}
-					} catch (Exception e) {
-						e.printStackTrace();
-					}
-					fxApplicationLaunched = true;
-					fxApplicationLaunching = false;
-				}
-			}, "Prelauncher Thread").start();
-	
-		} catch (Exception e) {
-			e.printStackTrace();
-		}
-    }
-    
-    private Bundle getMetadata() {
-        try {
-            ActivityInfo ai = FXActivity.this.getPackageManager().getActivityInfo(
-                    getIntent().getComponent(), PackageManager.GET_META_DATA);
-            return ai.metaData;
-
-        } catch(NameNotFoundException e) {
-            throw new RuntimeException("Error getting activity info", e);
-        }
-    }
-    
-    private Class resolveApplicationClass()
-			throws NameNotFoundException, ClassNotFoundException {
-
-		Class clazz = null;
-//		String applicationClassName = getPackageManager().getActivityInfo(
-//				new ComponentName(this, getClass()),
-//				PackageManager.GET_META_DATA).metaData
-//				.getString(JFX_APPLICATION_ATTRIBUTE);
-        String applicationClassName = getMetadata().getString(META_DATA_MAIN_CLASS);
-
-//		if (applicationClassName == null) {
-//			applicationClassName = getPackageManager().getActivityInfo(
-//					new ComponentName(this, getClass()),
-//					PackageManager.GET_META_DATA).metaData
-//					.getString(JFX_MAIN_ATTRIBUTE);
-//		}
-		if (applicationClassName != null && applicationClassName.length() > 0) {
-			clazz = Class.forName(applicationClassName);
-		}
-		return clazz;
-	}
-
-	private Class resolvePreloaderClass()
-			throws NameNotFoundException, ClassNotFoundException {
-
-		Class clazz = null;
-//		String className = getPackageManager().getActivityInfo(
-//				new ComponentName(this, getClass()),
-//				PackageManager.GET_META_DATA).metaData
-//				.getString(JFX_PRELOADER_ATTRIBUTE);
-
-        String className = getMetadata().getString(JFX_PRELOADER_ATTRIBUTE);
-		if (className != null && className.length() > 0) {
-			clazz = Class.forName(className);
-		}
-		return clazz;
-	}
-    
-    class InternalSurfaceView extends SurfaceView {
-
-        public InternalSurfaceView(Context context) {
-            super(context);
-            setFocusableInTouchMode(true);
-        }
-
-        @Override
-        public boolean dispatchTouchEvent(MotionEvent event) {
-            onTouchEventNative(event.getAction(), (int) event.getX(), (int) event.getY());
-            return true;
-        }
-
-        @Override
-        public boolean dispatchKeyEvent(KeyEvent event) {
-            onKeyEventNative(event.getAction(), event.getKeyCode(), event.getCharacters());
-            return true;
-        }
-
-        private native void onTouchEventNative(int action, int absx, int absy);
-
-        private native void onKeyEventNative(int action, int keycode, String characters);
-
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/graphics/src/android/java/com/oracle/dalvik/JavaSELauncher.java	Fri Sep 06 13:15:02 2013 +0200
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.dalvik;
+
+import android.app.Activity;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.util.Log;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.ArrayList;
+import java.util.List;
+
+public class JavaSELauncher implements Launcher, NativePipeReader.OnTextReceivedListener {
+
+    private static final String TAG                     = "JavaSELauncher";
+    private static final String TAG_JVM                 = "JavaSE";
+    
+    private static final String VMLAUNCHER_LIB          = "vmlauncher";
+    private static final String ANDROID_WEBVIEW_LIB     = "android_webview";
+    
+    private static final String META_DATA_MAIN_CLASS    = "main.class";
+    private static final String META_DATA_JVM_ARGS      = "jvm.args";
+    private static final String META_DATA_APP_ARGS      = "app.args";
+    private static final String META_DATA_DEBUG_PORT    = "debug.port";
+    private static final String JAR_EXT                 = ".jar";
+    
+    private Bundle              metaData;
+    private Activity            activity;
+    private NativePipeReader    reader;
+    private String              appDataDir;
+    private String              storageDir;
+    
+    public JavaSELauncher() {
+        System.loadLibrary(VMLAUNCHER_LIB);
+    }
+    
+    public void launchApp(Activity a, Bundle metadata) {
+        this.activity = a;
+        this.metaData = metadata;
+        reader = NativePipeReader.getDefaultReader(this);
+        reader.start();
+        appDataDir = activity.getApplicationInfo().dataDir;
+        storageDir = appDataDir + "/storage";
+        installJVMIfNeeded();
+        System.loadLibrary(ANDROID_WEBVIEW_LIB);
+    }
+
+    public void onTextReceived(String text) {
+        Log.v(TAG_JVM, text);
+    }
+    
+    private void installJVMIfNeeded() {
+        new InstallerTask().execute();
+    }
+    
+    private class InstallerTask extends AsyncTask<Void, Void, Void> {
+        protected Void doInBackground(Void... args) {
+           Log.i(TAG, "Installing JVM");
+            AppDataInstaller installer = 
+                new AppDataInstaller(storageDir,
+                    activity.getApplicationContext().getAssets());
+            installer.install();
+            return null;
+        }
+        
+        protected void onPostExecute(Void result) {
+            runJVM();
+        }
+    }
+    
+    private void runJVM() {
+        Log.i(TAG, "Launch JVM + application");
+        JvmArgs args = new JvmArgs(appDataDir);
+        VMLauncher.initialize(args.getJavaHome());
+        VMLauncher.runOnDebugPort(args.getDebugPort(),
+                                  args.getArgArray());
+    }
+    
+    private class JvmArgs {
+        private List<String> argList = new ArrayList<String>();
+        private String javaHome;
+
+        public JvmArgs(String appDir) {
+            String jvmRunCommand =
+                   "-Djava.library.path="
+                     + appDir + "/lib|"
+                     + "-Djava.home="
+                     + appDir + "/storage/jvm|"
+                     + "-Dsun.boot.library.path="
+                     + appDir + "/storage/jvm/lib|"
+                     + "-cp|"
+                     + getClasspath(appDir)
+                     + "|"                                         
+                     + "-Djavafx.platform=android|"
+                     + "-Djavafx.runtime.path="
+                     + appDir +"/storage/lib|"
+                     + getCustomJVMArgs()
+                     + "|"
+                     + getMainClass()
+                     + "|"
+                     + getApplicationArgs();
+
+            createArgList(jvmRunCommand);
+        }
+
+        private String[] listFiles(String dir, final String suffix) {
+            File dirf = new File(dir);
+            if (!dirf.exists()) {
+                return new String[]{};
+            }
+            String[] files = dirf.list(new FilenameFilter() {           
+                @Override
+                public boolean accept(File dir, String filename) {      
+                    return filename.endsWith(suffix);
+                }
+            });
+            return files;
+        }
+
+        private String getClasspath(String appDir) {
+            final String libDir = appDir + "/storage/lib/";
+            String[] libfiles = listFiles(libDir, JAR_EXT);
+            if (libfiles.length == 0) {
+                return "";
+            }
+            StringBuilder sb = new StringBuilder();
+            for(String file: libfiles) {
+                sb.append(libDir);
+                sb.append(file);
+                sb.append(File.pathSeparatorChar);
+            }
+            int len = sb.length();
+            return sb.substring(0, len - 1);
+        }
+
+        private String getMainClass() {
+             return metaData.getString(META_DATA_MAIN_CLASS);
+        }
+
+        private String getCustomJVMArgs() {
+             return metaData.getString(META_DATA_JVM_ARGS);
+        }
+
+        private String getApplicationArgs() {
+             return metaData.getString(META_DATA_APP_ARGS);
+        }
+
+        private int getDebugPort() {            
+             return metaData.getInt(META_DATA_DEBUG_PORT, 0);
+        }
+
+        public void createArgList(String args) {
+            if (args != null) {
+                String sep = (args.contains("|")) ? "\\|" : " ";
+                for (String arg : args.split(sep)) {
+                    arg = arg.trim();
+                    if (arg.length() > 0) {
+                        this.argList.add(arg);
+                        if (javaHome == null) {
+                            String[] pair = arg.split("\\=");
+                            Log.v(TAG, "arg = " + arg);
+                            Log.v(TAG, "pair.length = " + pair.length);
+                            if (pair.length == 2) {
+                                if ("-Djava.home".equals(pair[0])) {
+                                    Log.v(TAG, "Setting javaHome to " + pair[1]);
+                                    javaHome = pair[1];
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        
+        public String[] getArgArray() {
+            return argList.toArray(new String[0]);
+        }
+
+        public String getJavaHome() {
+           return javaHome;
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/graphics/src/android/java/com/oracle/dalvik/Launcher.java	Fri Sep 06 13:15:02 2013 +0200
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.oracle.dalvik;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public interface Launcher {
+    public void launchApp(Activity a, Bundle metadata);
+}
--- a/modules/graphics/src/main/native-glass/lens/android/android.c	Tue Sep 03 09:47:27 2013 +0200
+++ b/modules/graphics/src/main/native-glass/lens/android/android.c	Fri Sep 06 13:15:02 2013 +0200
@@ -105,7 +105,7 @@
 jobject jFXActivity;
 jclass jFXActivityClass;
 jmethodID jFXActivity_getInstance;
-jmethodID jFXActivity_getLDPath;
+jmethodID jFXActivity_getDataDir;
 jmethodID jFXActivity_showIME;
 jmethodID jFXActivity_hideIME;
 jmethodID jFXActivity_shutdown;
@@ -134,20 +134,27 @@
     jFXActivity = (*env)->CallStaticObjectMethod(env, jFXActivityClass, jFXActivity_getInstance);
     CHECK_EXCEPTION(env);
 
-    jFXActivity_getLDPath = (*env)->GetMethodID(env, jFXActivityClass,
-            "getLDPath", "()Ljava/lang/String;");
+    jFXActivity_getDataDir = (*env)->GetMethodID(env, jFXActivityClass,
+            "getDataDir", "()Ljava/lang/String;");
     CHECK_EXCEPTION(env);
 }
 
+#define LIB_DIR     "lib"
+#define PATH_SEP    "/"
+
 void init_functions(JNIEnv *env) {
     const char *libglass_name = "libglass_lens_eglfb.so";
-    jstring jldpath = (*env)->CallObjectMethod(env, jFXActivity, jFXActivity_getLDPath);
-    const char *cpath = (*env)->GetStringUTFChars(env, jldpath, 0);
-    int cpath_len = (*env)->GetStringUTFLength(env, jldpath);
+    jstring jdatadir = (*env)->CallObjectMethod(env, jFXActivity, jFXActivity_getDataDir);
+    
+    const char *cpath = (*env)->GetStringUTFChars(env, jdatadir, 0);
+    int cpath_len = (*env)->GetStringUTFLength(env, jdatadir);
 
-    char *fullpath = (char *) calloc(cpath_len + strlen(libglass_name) + 2, 1);
+    char *fullpath = (char *) calloc(cpath_len + strlen(libglass_name) + 
+                                     2 * strlen(PATH_SEP) + strlen(LIB_DIR) + 1, 1);
     strcpy(fullpath, cpath);
-    strcat(fullpath, "/");
+    strcat(fullpath, PATH_SEP);
+    strcat(fullpath, LIB_DIR);
+    strcat(fullpath, PATH_SEP);
     strcat(fullpath, libglass_name);
 
     void *libglass = dlopen(fullpath, RTLD_LAZY | RTLD_GLOBAL);
--- a/modules/web/src/android/native/android_webview.c	Tue Sep 03 09:47:27 2013 +0200
+++ b/modules/web/src/android/native/android_webview.c	Fri Sep 06 13:15:02 2013 +0200
@@ -19,7 +19,7 @@
 static jmethodID jInternalWebView_dispose;
 static jmethodID jInternalWebView_setEncoding;
 static jmethodID jFXActivity_getInstance;
-static jmethodID jFXActivity_getLDPath;
+static jmethodID jFXActivity_getDataDir;
 static JavaVM *jvm;
 
 static void (*_VM_fire_load_event)(int id, int frameId, int state,
@@ -85,22 +85,27 @@
             "getInstance", "()Lcom/oracle/dalvik/FXActivity;");
     CHECK_EXCEPTION(env);
 
-    jFXActivity_getLDPath = (*env)->GetMethodID(env, jFXActivityClass,
-            "getLDPath", "()Ljava/lang/String;");
+    jFXActivity_getDataDir = (*env)->GetMethodID(env, jFXActivityClass,
+            "getDataDir", "()Ljava/lang/String;");
     CHECK_EXCEPTION(env);
 }
 
 #define LIBWEBVIEW_SO "libwebview.so"
+#define LIB_DIR       "lib"
+#define PATH_SEP      "/"
 
 void init_functions(JNIEnv *env) {
     jobject fxactivity = (*env)->CallStaticObjectMethod(env, jFXActivityClass, jFXActivity_getInstance);
-    jstring jldpath = (*env)->CallObjectMethod(env, fxactivity, jFXActivity_getLDPath);
-    char *ld_path = (char*)(*env)->GetStringUTFChars(env, jldpath, 0);
-    int ld_path_len = (*env)->GetStringUTFLength(env, jldpath);
+    jstring jdatadir = (*env)->CallObjectMethod(env, fxactivity, jFXActivity_getDataDir);
+    char *cdatadir = (char*)(*env)->GetStringUTFChars(env, jdatadir, 0);
+    int cdatadir_len = (*env)->GetStringUTFLength(env, jdatadir);
 
-    char *fullpath = (char *) calloc(ld_path_len + strlen(LIBWEBVIEW_SO) + 2, 1);
-    strcpy(fullpath, ld_path);
-    strcat(fullpath, "/");    
+    char *fullpath = (char *) calloc(cdatadir_len + strlen(LIBWEBVIEW_SO) + 
+                                2 * strlen(PATH_SEP) + strlen(LIB_DIR) + 1, 1);
+    strcpy(fullpath, cdatadir);
+    strcat(fullpath, PATH_SEP);    
+    strcat(fullpath, LIB_DIR);
+    strcat(fullpath, PATH_SEP);
     strcat(fullpath, LIBWEBVIEW_SO);
 
     void *libwebview = dlopen(fullpath, RTLD_LAZY | RTLD_GLOBAL);