JOAL v2.6.0-rc-20250712
JOAL, OpenAL® API Binding for Java™ (public API).
LauncherUtil.java
Go to the documentation of this file.
1/**
2 * Copyright 2012 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28package com.jogamp.openal.test.android;
29
30import java.util.ArrayList;
31import java.util.HashMap;
32import java.util.Iterator;
33import java.util.List;
34import java.util.Map;
35
36import android.app.Activity;
37import android.content.Intent;
38import android.net.Uri;
39import android.os.Bundle;
40import android.util.Log;
41
42/**
43 * Helper class to parse Uri's and programmatically add package names and properties to create an Uri or Intend.
44 * <p>
45 * The order of the Uri segments (any arguments) is preserved.
46 * </p>
47 */
48public class LauncherUtil {
49
50 /** Default launch mode. */
51 public static final String LAUNCH_ACTIVITY_NORMAL = "org.jogamp.launcher.action.LAUNCH_ACTIVITY_NORMAL";
52
53 /** Transparent launch mode. Note: This seems to be required to achieve translucency, since setTheme(..) doesn't work. */
54 public static final String LAUNCH_ACTIVITY_TRANSPARENT = "org.jogamp.launcher.action.LAUNCH_ACTIVITY_TRANSPARENT";
55
56 /** FIXME: TODO */
57 public static final String LAUNCH_MAIN = "org.jogamp.launcher.action.LAUNCH_MAIN";
58
59 /** FIXME: TODO */
60 public static final String LAUNCH_JUNIT = "org.jogamp.launcher.action.LAUNCH_JUNIT";
61
62 /** The protocol <code>launch</code> */
63 public static final String SCHEME = "launch";
64
65 /** The host <code>jogamp.org</code> */
66 public static final String HOST = "jogamp.org";
67
68 static final String SYS_PKG = "sys";
69
70 static final String USR_PKG = "pkg";
71
72 static final String ARG = "arg";
73
74 public static abstract class BaseActivityLauncher extends Activity {
75 final OrderedProperties props = new OrderedProperties();
76 final ArrayList<String> args = new ArrayList<String>();
77 /**
78 * Returns the default {@link LauncherUtil#LAUNCH_ACTIVITY_NORMAL} action.
79 * <p>
80 * Should be overridden for other action, eg. {@link LauncherUtil#LAUNCH_ACTIVITY_TRANSPARENT}.
81 * </p>
82 */
83 public String getAction() { return LAUNCH_ACTIVITY_NORMAL; }
84
85 /**
86 * Returns the properties, which are being propagated to the target activity.
87 * <p>
88 * Maybe be used to set custom properties.
89 * </p>
90 */
91 public final OrderedProperties getProperties() { return props; }
92
93 /**
94 * Returns the commandline arguments, which are being propagated to the target activity.
95 * <p>
96 * Maybe be used to set custom commandline arguments.
97 * </p>
98 */
99 public final ArrayList<String> getArguments() { return args; }
100
101 /** Custom initialization hook which can be overriden to setup data, e.g. fill the properties retrieved by {@link #getProperties()}. */
102 public void init() { }
103
104 /** Returns true if this launcher activity shall end after starting the downstream activity. Defaults to <code>true</code>, override to change behavior. */
105 public boolean finishAfterDelegate() { return true; }
106
107 /** Must return the downstream Activity class name */
108 public abstract String getActivityName();
109
110 /** Must return a list of required user packages, at least one containing the activity. */
111 public abstract List<String> getUsrPackages();
112
113 /** Return a list of required system packages w/ native libraries, may return null or a zero sized list. */
114 public abstract List<String> getSysPackages();
115
116 @Override
117 public void onCreate(final Bundle savedInstanceState) {
118 super.onCreate(savedInstanceState);
119
120 init();
121
122 final DataSet data = new DataSet();
126 data.addAllProperties(props);
127 data.addAllArguments(args);
128
129 final Intent intent = LauncherUtil.getIntent(getAction(), data);
130 Log.d(getClass().getSimpleName(), "Launching Activity: "+intent);
131 startActivity (intent);
132
133 if(finishAfterDelegate()) {
134 finish(); // done
135 }
136 }
137 }
138
139 public static class OrderedProperties {
140 HashMap<String, String> map = new HashMap<String, String>();
141 ArrayList<String> keyList = new ArrayList<String>();
142
143 public final void setProperty(final String key, final String value) {
144 if(key.equals(SYS_PKG)) {
145 throw new IllegalArgumentException("Illegal property key, '"+SYS_PKG+"' is reserved");
146 }
147 if(key.equals(USR_PKG)) {
148 throw new IllegalArgumentException("Illegal property key, '"+USR_PKG+"' is reserved");
149 }
150 if(key.equals(ARG)) {
151 throw new IllegalArgumentException("Illegal property key, '"+ARG+"' is reserved");
152 }
153 final String oval = map.put(key, value);
154 if(null != oval) {
155 map.put(key, oval); // restore
156 throw new IllegalArgumentException("Property overwriting not allowed: "+key+": "+oval+" -> "+value);
157 }
158 keyList.add(key); // new key
159 }
160
161 public final void addAll(final OrderedProperties props) {
162 final Iterator<String> argKeys = props.keyList.iterator();
163 while(argKeys.hasNext()) {
164 final String key = argKeys.next();
165 setProperty(key, props.map.get(key));
166 }
167 }
168
169 public final void setSystemProperties() {
170 final Iterator<String> argKeys = keyList.iterator();
171 while(argKeys.hasNext()) {
172 final String key = argKeys.next();
173 System.setProperty(key, map.get(key));
174 }
175 }
176 public final void clearSystemProperties() {
177 final Iterator<String> argKeys = keyList.iterator();
178 while(argKeys.hasNext()) {
179 System.clearProperty(argKeys.next());
180 }
181 }
182
183 public final String getProperty(final String key) { return map.get(key); }
184 public final Map<String, String> getProperties() { return map; }
185
186 /** Returns the list of property keys in the order, as they were added. */
187 public final List<String> getPropertyKeys() { return keyList; }
188 }
189
190 /**
191 * Data set to transfer from and to launch URI consisting out of:
192 * <ul>
193 * <li>system packages w/ native libraries used on Android, which may use a cached ClassLoader, see {@link DataSet#getSysPackages()}.</li>
194 * <li>user packages w/o native libraries used on Android, which do not use a cached ClassLoader, see {@link DataSet#getUsrPackages()}.</li>
195 * <li>activity name, used to launch an Android activity, see {@link DataSet#getActivityName()}.</li>
196 * <li>properties, which will be added to the system properties, see {@link DataSet#getProperties()}.</li>
197 * <li>arguments, used to launch a class main-entry, see {@link DataSet#getArguments()}.</li>
198 * </ul>
199 * {@link DataSet#getUri()} returns a URI representation of all components.
200 */
201 public static class DataSet {
202 static final char SLASH = '/';
203 static final char QMARK = '?';
204 static final char AMPER = '&';
205 static final char ASSIG = '=';
206 static final String COLSLASH2 = "://";
207 static final String EMPTY = "";
208
209 String activityName = null;
210 ArrayList<String> sysPackages = new ArrayList<String>();
211 ArrayList<String> usrPackages = new ArrayList<String>();
212 OrderedProperties properties = new OrderedProperties();
213 ArrayList<String> arguments = new ArrayList<String>();
214
215 public final void setActivityName(final String name) { activityName = name; }
216 public final String getActivityName() { return activityName; }
217
218 public final void addSysPackage(final String p) {
219 sysPackages.add(p);
220 }
221 public final void addAllSysPackages(final List<String> plist) {
222 sysPackages.addAll(plist);
223 }
224 public final List<String> getSysPackages() { return sysPackages; }
225
226 public final void addUsrPackage(final String p) {
227 usrPackages.add(p);
228 }
229 public final void addAllUsrPackages(final List<String> plist) {
230 usrPackages.addAll(plist);
231 }
232 public final List<String> getUsrPackages() { return usrPackages; }
233
234 public final void setProperty(final String key, final String value) {
235 properties.setProperty(key, value);
236 }
237 public final void addAllProperties(final OrderedProperties props) {
238 properties.addAll(props);
239 }
240 public final void setSystemProperties() {
241 properties.setSystemProperties();
242 }
243 public final void clearSystemProperties() {
244 properties.clearSystemProperties();
245 }
246 public final String getProperty(final String key) { return properties.getProperty(key); }
247 public final OrderedProperties getProperties() { return properties; }
248 public final List<String> getPropertyKeys() { return properties.getPropertyKeys(); }
249
250 public final void addArgument(final String arg) { arguments.add(arg); }
251 public final void addAllArguments(final List<String> args) {
252 arguments.addAll(args);
253 }
254 public final ArrayList<String> getArguments() { return arguments; }
255
256 public final Uri getUri() {
257 final StringBuilder sb = new StringBuilder();
258 sb.append(SCHEME).append(COLSLASH2).append(HOST).append(SLASH).append(getActivityName());
259 boolean needsQMark = true;
260 boolean needsSep = false;
261 if(sysPackages.size()>0) {
262 if( needsQMark ) {
263 sb.append(QMARK);
264 needsQMark = false;
265 }
266 for(int i=0; i<sysPackages.size(); i++) {
267 if(needsSep) {
268 sb.append(AMPER);
269 }
270 sb.append(SYS_PKG).append(ASSIG).append(sysPackages.get(i));
271 needsSep = true;
272 }
273 }
274 if(usrPackages.size()>0) {
275 if( needsQMark ) {
276 sb.append(QMARK);
277 needsQMark = false;
278 }
279 for(int i=0; i<usrPackages.size(); i++) {
280 if(needsSep) {
281 sb.append(AMPER);
282 }
283 sb.append(USR_PKG).append(ASSIG).append(usrPackages.get(i));
284 needsSep = true;
285 }
286 }
287 final Iterator<String> propKeys = properties.keyList.iterator();
288 while(propKeys.hasNext()) {
289 if( needsQMark ) {
290 sb.append(QMARK);
291 needsQMark = false;
292 }
293 if(needsSep) {
294 sb.append(AMPER);
295 }
296 final String key = propKeys.next();
297 sb.append(key).append(ASSIG).append(properties.map.get(key));
298 needsSep = true;
299 }
300 final Iterator<String> args = arguments.iterator();
301 while(args.hasNext()) {
302 if( needsQMark ) {
303 sb.append(QMARK);
304 needsQMark = false;
305 }
306 if(needsSep) {
307 sb.append(AMPER);
308 }
309 sb.append(ARG).append(ASSIG).append(args.next());
310 needsSep = true;
311 }
312 return Uri.parse(sb.toString());
313 }
314
315 public static final DataSet create(final Uri uri) {
316 if(!uri.getScheme().equals(SCHEME)) {
317 return null;
318 }
319 if(!uri.getHost().equals(HOST)) {
320 return null;
321 }
322 final DataSet data = new DataSet();
323 {
324 String an = uri.getPath();
325 if(SLASH == an.charAt(0)) {
326 an = an.substring(1);
327 }
328 if(SLASH == an.charAt(an.length()-1)) {
329 an = an.substring(0, an.length()-1);
330 }
331 data.setActivityName(an);
332 }
333
334 final String q = uri.getQuery();
335 final int q_l = null != q ? q.length() : -1;
336 int q_e = -1;
337 while(q_e < q_l) {
338 final int q_b = q_e + 1; // next term
339 q_e = q.indexOf(AMPER, q_b);
340 if(0 == q_e) {
341 // single separator
342 continue;
343 }
344 if(0 > q_e) {
345 // end
346 q_e = q_l;
347 }
348 // n-part
349 final String part = q.substring(q_b, q_e);
350 final int assignment = part.indexOf(ASSIG);
351 if(0 < assignment) {
352 // assignment
353 final String k = part.substring(0, assignment);
354 final String v = part.substring(assignment+1);
355 if(k.equals(SYS_PKG)) {
356 if(v.length()==0) {
357 throw new IllegalArgumentException("Empty package name: part <"+part+">, query <"+q+"> of "+uri);
358 }
359 data.addSysPackage(v);
360 } else if(k.equals(USR_PKG)) {
361 if(v.length()==0) {
362 throw new IllegalArgumentException("Empty package name: part <"+part+">, query <"+q+"> of "+uri);
363 }
364 data.addUsrPackage(v);
365 } else if(k.equals(ARG)) {
366 if(v.length()==0) {
367 throw new IllegalArgumentException("Empty argument name: part <"+part+">, query <"+q+"> of "+uri);
368 }
369 data.addArgument(v);
370 } else {
371 data.setProperty(k, v);
372 }
373 } else {
374 // property key only
375 if( part.equals(USR_PKG) || part.equals(ARG) ) {
376 throw new IllegalArgumentException("Reserved key <"+part+"> in query <"+q+"> of "+uri);
377 }
378 data.setProperty(part, EMPTY);
379 }
380 }
381 data.validate();
382 return data;
383 }
384
385 public final void validate() {
386 if(null == activityName) {
387 throw new RuntimeException("Activity is not NULL");
388 }
389 }
390 }
391
392 public final static Intent getIntent(final String action, final DataSet data) {
393 data.validate();
394 return new Intent(action, data.getUri());
395 }
396
397 public static void main(String[] args) {
398 if(args.length==0) {
399 args = new String[] {
400 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",
401 SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+SYS_PKG+"=jogamp.pack1&jogamp.common.debug=true&com.jogamp.test=false",
402 SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+USR_PKG+"=jogamp.pack1&jogamp.common.debug=true&com.jogamp.test=false",
403 SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+USR_PKG+"=jogamp.pack1&"+USR_PKG+"=com.jogamp.pack2",
404 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",
405 SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+USR_PKG+"=jogamp.pack1&jogamp.common.debug=true&com.jogamp.test=false&"+ARG+"=arg1&"+ARG+"=arg2=arg2value&"+ARG+"=arg3",
406 SCHEME+"://"+HOST+"/com.jogamp.TestActivity?"+USR_PKG+"=jogamp.pack1&"+ARG+"=arg1&"+ARG+"=arg2=arg2value&"+ARG+"=arg3"
407 };
408 }
409 int errors = 0;
410 for(int i=0; i<args.length; i++) {
411 final String uri_s = args[i];
412 final Uri uri0 = Uri.parse(uri_s);
413 final DataSet data = DataSet.create(uri0);
414 if(null == data) {
415 errors++;
416 System.err.println("Error: NULL JogAmpLauncherUtil: <"+uri_s+"> -> "+uri0+" -> NULL");
417 } else {
418 final Uri uri1 = data.getUri();
419 if(!uri0.equals(uri1)) {
420 errors++;
421 System.err.println("Error: Not equal: <"+uri_s+"> -> "+uri0+" -> "+uri1);
422 } else {
423 System.err.println("OK: "+uri1);
424 }
425 }
426 }
427 System.err.println("LauncherUtil Self Test: Errors: "+errors);
428 }
429
430}
abstract List< String > getUsrPackages()
Must return a list of required user packages, at least one containing the activity.
boolean finishAfterDelegate()
Returns true if this launcher activity shall end after starting the downstream activity.
String getAction()
Returns the default LauncherUtil#LAUNCH_ACTIVITY_NORMAL action.
void init()
Custom initialization hook which can be overriden to setup data, e.g.
abstract List< String > getSysPackages()
Return a list of required system packages w/ native libraries, may return null or a zero sized list.
final ArrayList< String > getArguments()
Returns the commandline arguments, which are being propagated to the target activity.
abstract String getActivityName()
Must return the downstream Activity class name.
final OrderedProperties getProperties()
Returns the properties, which are being propagated to the target activity.
Data set to transfer from and to launch URI consisting out of:
final void addAllSysPackages(final List< String > plist)
final void addAllProperties(final OrderedProperties props)
final void setProperty(final String key, final String value)
final void addAllUsrPackages(final List< String > plist)
static final DataSet create(final Uri uri)
final void addAllArguments(final List< String > args)
final List< String > getPropertyKeys()
Returns the list of property keys in the order, as they were added.
final void addAll(final OrderedProperties props)
final void setProperty(final String key, final String value)
Helper class to parse Uri's and programmatically add package names and properties to create an Uri or...
static final String SCHEME
The protocol launch
static final String LAUNCH_JUNIT
FIXME: TODO.
static final String LAUNCH_MAIN
FIXME: TODO.
static final String HOST
The host jogamp.org
static final String LAUNCH_ACTIVITY_NORMAL
Default launch mode.
static final String LAUNCH_ACTIVITY_TRANSPARENT
Transparent launch mode.
static final Intent getIntent(final String action, final DataSet data)