diff options
Diffstat (limited to 'src/java/jogamp/android/launcher/LauncherUtil.java')
-rw-r--r-- | src/java/jogamp/android/launcher/LauncherUtil.java | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/src/java/jogamp/android/launcher/LauncherUtil.java b/src/java/jogamp/android/launcher/LauncherUtil.java new file mode 100644 index 0000000..63452b7 --- /dev/null +++ b/src/java/jogamp/android/launcher/LauncherUtil.java @@ -0,0 +1,320 @@ +/** + * Copyright 2012 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.android.launcher; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; + +/** + * Helper class to parse Uri's and programmatically add package names and properties to create an Uri or Intend. + * <p> + * The order of the Uri segments (any arguments) is preserved. + * </p> + */ +public class LauncherUtil { + + /** Default launch mode. */ + public static final String LAUNCH_ACTIVITY_NORMAL = "org.jogamp.launcher.action.LAUNCH_ACTIVITY_NORMAL"; + + /** Transparent launch mode. Note: This seems to be required to achieve translucency, since setTheme(..) doesn't work. */ + public static final String LAUNCH_ACTIVITY_TRANSPARENT = "org.jogamp.launcher.action.LAUNCH_ACTIVITY_TRANSPARENT"; + + /** FIXME: TODO */ + public static final String LAUNCH_MAIN = "org.jogamp.launcher.action.LAUNCH_MAIN"; + + /** FIXME: TODO */ + public static final String LAUNCH_JUNIT = "org.jogamp.launcher.action.LAUNCH_JUNIT"; + + /** The protocol <code>launch</code> */ + public static final String SCHEME = "launch"; + + /** The host <code>jogamp.org</code> */ + public static final String HOST = "jogamp.org"; + + static final String PKG = "pkg"; + + public static abstract class BaseActivityLauncher extends Activity { + final OrderedProperties props = new OrderedProperties(); + + /** + * Returns the default {@link LauncherUtil#LAUNCH_ACTIVITY_NORMAL} action. + * <p> + * Should be overridden for other action, eg. {@link LauncherUtil#LAUNCH_ACTIVITY_TRANSPARENT}. + * </p> + */ + public String getAction() { return LAUNCH_ACTIVITY_NORMAL; } + + /** + * Returns the properties, which are being propagated to the target activity. + * <p> + * Maybe be used to set custom properties. + * </p> + */ + public final OrderedProperties getProperties() { return props; } + + /** Custom initialization hook which can be overriden to setup data, e.g. fill the properties retrieved by {@link #getProperties()}. */ + public void init() { } + + /** Returns true if this launcher activity shall end after starting the downstream activity. Defaults to <code>true</code>, override to change behavior. */ + public boolean finishAfterDelegate() { return true; } + + /** 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(); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + init(); + + final DataSet data = new DataSet(); + data.setActivityName(getActivityName()); + data.addAllPackages(getPackages()); + data.addAllProperties(props); + + final Intent intent = LauncherUtil.getIntent(getAction(), data); + Log.d(getClass().getSimpleName(), "Launching Activity: "+intent); + startActivity (intent); + + if(finishAfterDelegate()) { + finish(); // done + } + } + } + + public static class OrderedProperties { + HashMap<String, String> map = new HashMap<String, String>(); + 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"); + } + final String oval = map.put(key, value); + if(null != oval) { + map.put(key, oval); // restore + throw new IllegalArgumentException("Property overwriting not allowed: "+key+": "+oval+" -> "+value); + } + keyList.add(key); // new key + } + + public final void addAll(OrderedProperties props) { + Iterator<String> argKeys = props.keyList.iterator(); + while(argKeys.hasNext()) { + final String key = argKeys.next(); + setProperty(key, props.map.get(key)); + } + } + + public final void setSystemProperties() { + Iterator<String> argKeys = keyList.iterator(); + while(argKeys.hasNext()) { + final String key = argKeys.next(); + System.setProperty(key, map.get(key)); + } + } + + public final String getProperty(String key) { return map.get(key); } + public final Map<String, String> getProperties() { return map; } + + /** Returns the list of property keys in the order, as they were added. */ + public final List<String> getPropertyKeys() { return keyList; } + } + + public static class DataSet { + static final char SLASH = '/'; + static final char QMARK = '?'; + static final char AMPER = '&'; + static final char ASSIG = '='; + static final String COLSLASH2 = "://"; + static final String EMPTY = ""; + + String activityName = null; + ArrayList<String> packages = new ArrayList<String>(); + OrderedProperties properties = new OrderedProperties(); + + public final void setActivityName(String name) { activityName = name; } + public final String getActivityName() { return activityName; } + + public final void addPackage(String p) { + packages.add(p); + } + public final void addAllPackages(List<String> plist) { + packages.addAll(plist); + } + public final List<String> getPackages() { return packages; } + + public final void setProperty(String key, String value) { + properties.setProperty(key, value); + } + public final void addAllProperties(OrderedProperties props) { + properties.addAll(props); + } + public final void setSystemProperties() { + properties.setSystemProperties(); + } + public final String getProperty(String key) { return properties.getProperty(key); } + public final OrderedProperties getProperties() { return properties; } + public final List<String> getPropertyKeys() { return properties.getPropertyKeys(); } + + public final Uri getUri() { + StringBuilder sb = new StringBuilder(); + sb.append(SCHEME).append(COLSLASH2).append(HOST).append(SLASH).append(getActivityName()); + boolean needsSep = false; + if(packages.size()>0) { + sb.append(QMARK); + for(int i=0; i<packages.size(); i++) { + if(needsSep) { + sb.append(AMPER); + } + sb.append(PKG).append(ASSIG).append(packages.get(i)); + needsSep = true; + } + } + Iterator<String> argKeys = properties.keyList.iterator(); + while(argKeys.hasNext()) { + if(needsSep) { + sb.append(AMPER); + } + final String key = argKeys.next(); + sb.append(key).append(ASSIG).append(properties.map.get(key)); + needsSep = true; + } + return Uri.parse(sb.toString()); + } + + public static final DataSet create(Uri uri) { + if(!uri.getScheme().equals(SCHEME)) { + return null; + } + if(!uri.getHost().equals(HOST)) { + return null; + } + DataSet data = new DataSet(); + { + String an = uri.getPath(); + if(SLASH == an.charAt(0)) { + an = an.substring(1); + } + if(SLASH == an.charAt(an.length()-1)) { + an = an.substring(0, an.length()-1); + } + data.setActivityName(an); + } + + final String q = uri.getQuery(); + final int q_l = q.length(); + int q_e = -1; + while(q_e < q_l) { + int q_b = q_e + 1; // next term + q_e = q.indexOf(AMPER, q_b); + if(0 == q_e) { + // single seperator + continue; + } + if(0 > q_e) { + // end + q_e = q_l; + } + // n-part + final String part = q.substring(q_b, q_e); + final int assignment = part.indexOf(ASSIG); + if(0 < assignment) { + // assignment + final String k = part.substring(0, assignment); + final String v = part.substring(assignment+1); + if(k.equals(PKG)) { + if(v.length()==0) { + throw new IllegalArgumentException("Empty package name: part <"+part+">, query <"+q+"> of "+uri); + } + data.addPackage(v); + } else { + data.setProperty(k, v); + } + } else { + // property key only + if(part.equals(PKG)) { + throw new IllegalArgumentException("Empty package name: part <"+part+">, query <"+q+"> of "+uri); + } + data.setProperty(part, EMPTY); + } + } + data.validate(); + return data; + } + + public final void validate() { + if(null == activityName) { + throw new RuntimeException("Activity is not NULL"); + } + if(packages.size() == 0) { + throw new RuntimeException("Empty package list"); + } + } + } + + public final static Intent getIntent(String action, DataSet data) { + data.validate(); + return new Intent(action, data.getUri()); + } + + 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" + }; + } + for(int i=0; i<args.length; i++) { + String uri_s = args[i]; + Uri uri0 = Uri.parse(uri_s); + DataSet data = DataSet.create(uri0); + if(null == data) { + System.err.println("Error: NULL JogAmpLauncherUtil: <"+uri_s+"> -> "+uri0+" -> NULL"); + } + Uri uri1 = data.getUri(); + if(!uri0.equals(uri1)) { + System.err.println("Error: Not equal: <"+uri_s+"> -> "+uri0+" -> "+uri1); + } + } + } + +} |