/**
* 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.
*
* The order of the Uri segments (any arguments) is preserved.
*
*/
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 launch
*/
public static final String SCHEME = "launch";
/** The host jogamp.org
*/
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.
*
* Should be overridden for other action, eg. {@link LauncherUtil#LAUNCH_ACTIVITY_TRANSPARENT}.
*
*/
public String getAction() { return LAUNCH_ACTIVITY_NORMAL; }
/**
* Returns the properties, which are being propagated to the target activity.
*
* Maybe be used to set custom properties.
*
*/
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 true
, 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 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 map = new HashMap();
ArrayList keyList = new ArrayList();
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 argKeys = props.keyList.iterator();
while(argKeys.hasNext()) {
final String key = argKeys.next();
setProperty(key, props.map.get(key));
}
}
public final void setSystemProperties() {
Iterator 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 getProperties() { return map; }
/** Returns the list of property keys in the order, as they were added. */
public final List 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 packages = new ArrayList();
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 plist) {
packages.addAll(plist);
}
public final List 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 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 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 -> "+uri0+" -> NULL");
}
Uri uri1 = data.getUri();
if(!uri0.equals(uri1)) {
System.err.println("Error: Not equal: <"+uri_s+"> -> "+uri0+" -> "+uri1);
}
}
}
}