calabash-android 0.4.0.pre6 → 0.4.0.pre7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/calabash-android +7 -0
- data/bin/calabash-android-build.rb +1 -1
- data/bin/calabash-android-console.rb +1 -1
- data/bin/calabash-android-run.rb +1 -1
- data/calabash-android.gemspec +1 -0
- data/irbrc +2 -0
- data/lib/calabash-android/helpers.rb +4 -2
- data/lib/calabash-android/lib/TestServer.apk +0 -0
- data/lib/calabash-android/operations.rb +31 -22
- data/lib/calabash-android/version.rb +1 -1
- data/test-server/instrumentation-backend/.classpath +0 -1
- data/test-server/instrumentation-backend/antlr/UIQuery.g +11 -2
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/Command.java +4 -3
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/FranklyResult.java +95 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/Result.java +7 -1
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/HttpServer.java +15 -23
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/location/FakeGPSLocation.java +13 -10
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/CalabashChromeClient.java +136 -36
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/DumpBodyHtml.java +38 -18
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/DumpHtml.java +38 -16
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/EnterTextByCssSelector.java +94 -66
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/ExecuteAsyncJavascript.java +55 -33
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/ExecuteJavascript.java +54 -31
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/JavaScriptOperation.java +44 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/PressByCssSelector.java +52 -27
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/QueryHelper.java +39 -32
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/ScrollTo.java +56 -41
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/SetPropertyByCssSelector.java +50 -25
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/SetText.java +19 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/CompletedFuture.java +40 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/InvocationOperation.java +201 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/Operation.java +7 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/PropertyOperation.java +56 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/Query.java +144 -72
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/UIQuery.tokens +15 -12
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/UIQueryResultVoid.java +22 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ViewMapper.java +38 -11
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/antlr/UIQueryLexer.java +226 -109
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/antlr/UIQueryParser.java +237 -84
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/PartialFutureList.java +100 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryAST.java +1 -1
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTClassName.java +26 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTWith.java +170 -102
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryEvaluator.java +54 -155
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryUtils.java +97 -2
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryVisibility.java +32 -0
- metadata +27 -5
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/Query.java +0 -24
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/Touch.java +0 -44
- data/test-server/instrumentation-backend/tests/sh/calaba/instrumentationbackend/query/tests/UIQueryTest.java +0 -134
@@ -1,7 +1,6 @@
|
|
1
1
|
package sh.calaba.instrumentationbackend.actions.webview;
|
2
2
|
|
3
3
|
|
4
|
-
import java.util.HashMap;
|
5
4
|
import java.util.List;
|
6
5
|
import java.util.Map;
|
7
6
|
|
@@ -9,60 +8,76 @@ import sh.calaba.instrumentationbackend.InstrumentationBackend;
|
|
9
8
|
import sh.calaba.instrumentationbackend.Result;
|
10
9
|
import sh.calaba.instrumentationbackend.actions.Action;
|
11
10
|
import sh.calaba.instrumentationbackend.actions.Actions;
|
12
|
-
import sh.calaba.org.codehaus.jackson.map.ObjectMapper;
|
13
|
-
import sh.calaba.org.codehaus.jackson.type.TypeReference;
|
14
11
|
import android.test.TouchUtils;
|
15
12
|
import android.webkit.WebView;
|
16
13
|
|
17
14
|
|
18
15
|
public class ScrollTo implements Action {
|
19
|
-
|
20
|
-
|
16
|
+
|
17
|
+
@Override
|
21
18
|
public Result execute(String... args) {
|
22
19
|
//TODO: Should do horizontal scrolling if needed
|
23
|
-
String
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
}
|
36
|
-
}
|
37
|
-
|
38
|
-
return new Result(true, "");
|
20
|
+
final String uiQuery = "webView " + args[0] + ":'"+ args[1] + "'";
|
21
|
+
|
22
|
+
CalabashChromeClient calabashChromeClient = CalabashChromeClient.findAndPrepareWebViews().get(0);
|
23
|
+
WebView webView = calabashChromeClient.getWebView();
|
24
|
+
|
25
|
+
scrollToTop(webView);
|
26
|
+
|
27
|
+
while (keepScrolling(uiQuery, webView)) {
|
28
|
+
TouchUtils.dragQuarterScreenUp(Actions.parentTestCase, InstrumentationBackend.solo.getCurrentActivity());
|
29
|
+
}
|
30
|
+
|
31
|
+
return new Result(isVisible(uiQuery, webView), "");
|
39
32
|
}
|
40
33
|
|
34
|
+
private void scrollToTop(final WebView webView) {
|
35
|
+
InstrumentationBackend.instrumentation.runOnMainSync(new Runnable() {
|
36
|
+
@Override
|
37
|
+
public void run() {
|
38
|
+
webView.scrollTo(0, 0);
|
39
|
+
}
|
40
|
+
});
|
41
|
+
}
|
41
42
|
|
43
|
+
private boolean keepScrolling(String uiQuery, WebView webView) {
|
44
|
+
int centerY = getCenterY(uiQuery, webView);
|
45
|
+
System.out.println("Keep scrolling centerY: "+ centerY);
|
42
46
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
if (p.isEmpty()) {
|
48
|
-
throw new RuntimeException("No element found");
|
49
|
-
}
|
50
|
-
System.out.println(p);
|
51
|
-
final Map<String, Object> firstRect = QueryHelper.findFirstVisibleRectangle(p);
|
52
|
-
return firstRect;
|
53
|
-
} catch (Exception e) {
|
54
|
-
throw new RuntimeException(e);
|
55
|
-
}
|
47
|
+
int[] location = new int[2];
|
48
|
+
webView.getLocationOnScreen(location);
|
49
|
+
int top = location[1];
|
50
|
+
int bottom = top + webView.getHeight();
|
56
51
|
|
57
|
-
|
52
|
+
System.out.println("isVisible top: "+ top);
|
53
|
+
System.out.println("isVisible bottom: "+ bottom);
|
54
|
+
|
55
|
+
return centerY > bottom;
|
56
|
+
}
|
57
|
+
|
58
|
+
private boolean isVisible(String uiQuery, WebView webView) {
|
59
|
+
int centerY = getCenterY(uiQuery, webView);
|
60
|
+
System.out.println("isVisible centerY: "+ centerY);
|
61
|
+
|
62
|
+
int[] location = new int[2];
|
63
|
+
webView.getLocationOnScreen(location);
|
64
|
+
int top = location[1];
|
65
|
+
int bottom = top + webView.getHeight();
|
66
|
+
System.out.println("isVisible top: "+ top);
|
67
|
+
System.out.println("isVisible bottom: "+ bottom);
|
68
|
+
|
69
|
+
return top < centerY && centerY < bottom;
|
70
|
+
}
|
58
71
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
72
|
+
@SuppressWarnings({ "rawtypes", "unchecked" })
|
73
|
+
private int getCenterY(String uiQuery, WebView webView) {
|
74
|
+
List queryResult = new sh.calaba.instrumentationbackend.query.Query(uiQuery).executeQuery();
|
75
|
+
if (queryResult.isEmpty()) {
|
76
|
+
throw new RuntimeException("Query found no elements");
|
77
|
+
}
|
78
|
+
final Map<String, Object> firstVisibleRectangle = QueryHelper.findFirstVisibleRectangle(queryResult);
|
64
79
|
|
65
|
-
|
80
|
+
return Math.round((Float)firstVisibleRectangle.get("center_y"));
|
66
81
|
}
|
67
82
|
|
68
83
|
@Override
|
@@ -1,42 +1,67 @@
|
|
1
1
|
package sh.calaba.instrumentationbackend.actions.webview;
|
2
2
|
|
3
3
|
|
4
|
-
import
|
4
|
+
import java.util.ArrayList;
|
5
|
+
import java.util.List;
|
6
|
+
import java.util.concurrent.Callable;
|
7
|
+
|
5
8
|
import sh.calaba.instrumentationbackend.Result;
|
6
|
-
import sh.calaba.instrumentationbackend.TestHelpers;
|
7
9
|
import sh.calaba.instrumentationbackend.actions.Action;
|
10
|
+
import sh.calaba.instrumentationbackend.actions.webview.CalabashChromeClient.WebFuture;
|
11
|
+
import sh.calaba.instrumentationbackend.query.ast.UIQueryUtils;
|
8
12
|
import android.webkit.WebView;
|
9
13
|
|
10
14
|
|
11
15
|
public class SetPropertyByCssSelector implements Action {
|
12
16
|
|
13
|
-
@
|
17
|
+
@SuppressWarnings({ "unchecked", "rawtypes" })
|
18
|
+
@Override
|
14
19
|
public Result execute(String... args) {
|
15
|
-
String cssSelector = args[0];
|
16
|
-
String propertyName = args[1];
|
17
|
-
String value = args[2];
|
18
|
-
|
19
|
-
|
20
|
-
WebView webView = ccc.getWebView();
|
20
|
+
final String cssSelector = args[0];
|
21
|
+
final String propertyName = args[1];
|
22
|
+
final String value = args[2];
|
23
|
+
|
24
|
+
List<WebFuture> webResults = (List<WebFuture>) UIQueryUtils.evaluateSyncInMainThread(new Callable() {
|
21
25
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
26
|
+
public Object call() throws Exception {
|
27
|
+
|
28
|
+
List<WebFuture> webResults = new ArrayList();
|
29
|
+
for (CalabashChromeClient ccc : CalabashChromeClient.findAndPrepareWebViews()) {
|
30
|
+
WebView webView = ccc.getWebView();
|
31
|
+
|
32
|
+
final String assignment = "document.querySelector(\"" + cssSelector + "\")." + propertyName + " = " + value + ";";
|
33
|
+
System.out.println(assignment);
|
34
|
+
webView.loadUrl("javascript:(function() {" +
|
35
|
+
assignment +
|
36
|
+
"prompt('calabash:true');" +
|
37
|
+
"})()");
|
38
|
+
webResults.add(ccc.getResult());
|
39
|
+
}
|
35
40
|
|
36
|
-
|
37
|
-
|
41
|
+
return webResults;
|
42
|
+
|
43
|
+
}
|
44
|
+
});
|
45
|
+
|
46
|
+
List<String> allResults = new ArrayList<String>(webResults.size());
|
47
|
+
boolean success = false;
|
48
|
+
for (WebFuture f : webResults) {
|
49
|
+
String result = f.getAsString();
|
50
|
+
allResults.add(result);
|
51
|
+
if ("true".equals(result)) {
|
52
|
+
success = true;
|
53
|
+
}
|
54
|
+
}
|
55
|
+
|
56
|
+
if (allResults.size() == 0) {
|
57
|
+
return new Result(false, "No WebView found");
|
58
|
+
}
|
59
|
+
else {
|
60
|
+
return new Result(success, allResults);
|
61
|
+
}
|
62
|
+
}
|
38
63
|
|
39
|
-
|
64
|
+
@Override
|
40
65
|
public String key() {
|
41
66
|
return "set_property_by_css_selector";
|
42
67
|
}
|
@@ -1,14 +1,12 @@
|
|
1
1
|
package sh.calaba.instrumentationbackend.actions.webview;
|
2
2
|
|
3
3
|
|
4
|
-
import java.util.HashMap;
|
5
4
|
import java.util.List;
|
6
5
|
import java.util.Map;
|
7
6
|
|
8
7
|
import sh.calaba.instrumentationbackend.Result;
|
9
8
|
import sh.calaba.instrumentationbackend.actions.Action;
|
10
|
-
import sh.calaba.
|
11
|
-
import sh.calaba.org.codehaus.jackson.type.TypeReference;
|
9
|
+
import sh.calaba.instrumentationbackend.actions.webview.CalabashChromeClient.WebFuture;
|
12
10
|
|
13
11
|
|
14
12
|
public class SetText implements Action {
|
@@ -18,26 +16,25 @@ public class SetText implements Action {
|
|
18
16
|
* args[1]: xpath or css selector
|
19
17
|
* args[2]: text to enter into the first selected element
|
20
18
|
*/
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
throw new RuntimeException("No element found");
|
29
|
-
}
|
30
|
-
Map<String, Object> firstElement = QueryHelper.findFirstVisibleElement(p);
|
31
|
-
//TODO: Hack! Should be serialized instead of removed
|
32
|
-
firstElement.remove("class");
|
33
|
-
firstElement.remove("html");
|
34
|
-
String firstElementJson = QueryHelper.toJsonString(firstElement);
|
35
|
-
|
36
|
-
String result = QueryHelper.executeJavascriptInWebview("set_text.js", firstElementJson, args[2]);
|
37
|
-
return new Result(true, result);
|
38
|
-
} catch (Exception e) {
|
39
|
-
throw new RuntimeException(e);
|
19
|
+
@SuppressWarnings({ "rawtypes", "unchecked"})
|
20
|
+
@Override
|
21
|
+
public Result execute(final String... args) {
|
22
|
+
final String uiQuery = "webView " + args[0] + ":'"+ args[1] + "'";
|
23
|
+
List queryResult = new sh.calaba.instrumentationbackend.query.Query(uiQuery).executeQuery();
|
24
|
+
if (queryResult.isEmpty()) {
|
25
|
+
throw new RuntimeException("No element found");
|
40
26
|
}
|
27
|
+
Map<String, Object> firstElement = QueryHelper.findFirstVisibleElement(queryResult);
|
28
|
+
//TODO: Hack! Should be serialized instead of removed
|
29
|
+
CalabashChromeClient client = CalabashChromeClient.findAndPrepareWebViews().get(0);
|
30
|
+
firstElement.remove("class");
|
31
|
+
firstElement.remove("webView");
|
32
|
+
firstElement.remove("html");
|
33
|
+
String firstElementJson = QueryHelper.toJsonString(firstElement);
|
34
|
+
|
35
|
+
WebFuture result = QueryHelper.executeAsyncJavascriptInWebviews(client.getWebView(),"set_text.js", firstElementJson, args[2]);
|
36
|
+
|
37
|
+
return new Result(true,result.getAsString());
|
41
38
|
}
|
42
39
|
|
43
40
|
@Override
|
@@ -0,0 +1,40 @@
|
|
1
|
+
package sh.calaba.instrumentationbackend.query;
|
2
|
+
|
3
|
+
import java.util.concurrent.ExecutionException;
|
4
|
+
import java.util.concurrent.Future;
|
5
|
+
import java.util.concurrent.TimeUnit;
|
6
|
+
import java.util.concurrent.TimeoutException;
|
7
|
+
|
8
|
+
public class CompletedFuture<T> implements Future<T> {
|
9
|
+
private final T result;
|
10
|
+
|
11
|
+
public CompletedFuture(final T result) {
|
12
|
+
this.result = result;
|
13
|
+
}
|
14
|
+
|
15
|
+
@Override
|
16
|
+
public boolean cancel(final boolean b) {
|
17
|
+
return false;
|
18
|
+
}
|
19
|
+
|
20
|
+
@Override
|
21
|
+
public boolean isCancelled() {
|
22
|
+
return false;
|
23
|
+
}
|
24
|
+
|
25
|
+
@Override
|
26
|
+
public boolean isDone() {
|
27
|
+
return true;
|
28
|
+
}
|
29
|
+
|
30
|
+
@Override
|
31
|
+
public T get() throws InterruptedException, ExecutionException {
|
32
|
+
return this.result;
|
33
|
+
}
|
34
|
+
|
35
|
+
@Override
|
36
|
+
public T get(long timeout, TimeUnit unit) throws InterruptedException,
|
37
|
+
ExecutionException, TimeoutException {
|
38
|
+
return get();
|
39
|
+
}
|
40
|
+
}
|
@@ -0,0 +1,201 @@
|
|
1
|
+
package sh.calaba.instrumentationbackend.query;
|
2
|
+
|
3
|
+
import java.lang.reflect.Method;
|
4
|
+
import java.util.List;
|
5
|
+
import java.util.concurrent.atomic.AtomicReference;
|
6
|
+
|
7
|
+
import sh.calaba.instrumentationbackend.InstrumentationBackend;
|
8
|
+
|
9
|
+
public class InvocationOperation implements Operation {
|
10
|
+
|
11
|
+
private final String methodName;
|
12
|
+
@SuppressWarnings("rawtypes")
|
13
|
+
private final List arguments;
|
14
|
+
private final Class<?>[] classes;
|
15
|
+
private final Class<?>[] classesWithCharseq;
|
16
|
+
|
17
|
+
@SuppressWarnings("rawtypes")
|
18
|
+
public InvocationOperation(String methodName, List arguments) {
|
19
|
+
this.methodName = methodName;
|
20
|
+
this.arguments = arguments;
|
21
|
+
this.classes = extractArgumentTypes(false);
|
22
|
+
this.classesWithCharseq = extractArgumentTypes(true);
|
23
|
+
}
|
24
|
+
|
25
|
+
@SuppressWarnings("rawtypes")
|
26
|
+
@Override
|
27
|
+
public Object apply(final Object o) throws Exception {
|
28
|
+
final AtomicReference ref = new AtomicReference();
|
29
|
+
final AtomicReference<Exception> refEx = new AtomicReference<Exception>();
|
30
|
+
|
31
|
+
InstrumentationBackend.instrumentation.runOnMainSync(new Runnable() {
|
32
|
+
|
33
|
+
@SuppressWarnings("unchecked")
|
34
|
+
@Override
|
35
|
+
public void run() {
|
36
|
+
try {
|
37
|
+
Method method = o.getClass().getMethod(InvocationOperation.this.methodName, InvocationOperation.this.classes);
|
38
|
+
method.setAccessible(true);
|
39
|
+
try {
|
40
|
+
Object result;
|
41
|
+
if( method.getReturnType().equals(Void.TYPE)){
|
42
|
+
invokeMethod(o, method);
|
43
|
+
result = "<VOID>";
|
44
|
+
}
|
45
|
+
else {
|
46
|
+
result = invokeMethod(o, method);
|
47
|
+
}
|
48
|
+
ref.set(result);
|
49
|
+
return;
|
50
|
+
} catch (Exception e) {
|
51
|
+
refEx.set(e);
|
52
|
+
return;
|
53
|
+
}
|
54
|
+
} catch (NoSuchMethodException e) {
|
55
|
+
try {
|
56
|
+
Method method = o.getClass().getMethod(InvocationOperation.this.methodName, InvocationOperation.this.classesWithCharseq);
|
57
|
+
method.setAccessible(true);
|
58
|
+
try {
|
59
|
+
Object result;
|
60
|
+
if( method.getReturnType().equals(Void.TYPE)){
|
61
|
+
invokeMethod(o, method);
|
62
|
+
result = "<VOID>";
|
63
|
+
}
|
64
|
+
else {
|
65
|
+
result = invokeMethod(o, method);
|
66
|
+
}
|
67
|
+
ref.set(result);
|
68
|
+
return;
|
69
|
+
} catch (Exception ee) {
|
70
|
+
refEx.set(e);
|
71
|
+
return;
|
72
|
+
}
|
73
|
+
} catch (NoSuchMethodException ee) {
|
74
|
+
System.out.println("Method not found with correct argument types. Trying to type convert.");
|
75
|
+
}
|
76
|
+
}
|
77
|
+
//Warning: Slow path
|
78
|
+
Method[] methods = o.getClass().getMethods();
|
79
|
+
for (Method m : methods) {
|
80
|
+
if (m.getName().equals(InvocationOperation.this.methodName)) {
|
81
|
+
Class<?>[] parameterTypes = m.getParameterTypes();
|
82
|
+
if (parameterTypes.length == InvocationOperation.this.classes.length && areArgumentsConvertibleTo(parameterTypes)) {
|
83
|
+
try {
|
84
|
+
Object result;
|
85
|
+
if( m.getReturnType().equals(Void.TYPE)){
|
86
|
+
invokeMethod(o, m);
|
87
|
+
result = "<VOID>";
|
88
|
+
}
|
89
|
+
else {
|
90
|
+
result = invokeMethod(o, m);
|
91
|
+
}
|
92
|
+
ref.set(result);
|
93
|
+
return;
|
94
|
+
} catch (Exception e) {
|
95
|
+
refEx.set(e);
|
96
|
+
return;
|
97
|
+
}
|
98
|
+
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
}
|
104
|
+
|
105
|
+
});
|
106
|
+
|
107
|
+
if (refEx.get() != null) {
|
108
|
+
throw refEx.get();
|
109
|
+
}
|
110
|
+
return ref.get();
|
111
|
+
}
|
112
|
+
|
113
|
+
@SuppressWarnings("rawtypes")
|
114
|
+
private Class[] extractArgumentTypes(boolean convertStringCharSeq) {
|
115
|
+
Class[] types = new Class[arguments.size()];
|
116
|
+
for (int i=0;i<arguments.size(); i++) {
|
117
|
+
Object o = arguments.get(i);
|
118
|
+
if (o != null) {
|
119
|
+
Class<?> c = o.getClass();
|
120
|
+
if (convertStringCharSeq && c.equals(String.class)) {
|
121
|
+
c = CharSequence.class;//Android API specific optimization
|
122
|
+
}
|
123
|
+
types[i] = c;
|
124
|
+
}
|
125
|
+
else {
|
126
|
+
types[i] = null;
|
127
|
+
}
|
128
|
+
}
|
129
|
+
return types;
|
130
|
+
}
|
131
|
+
|
132
|
+
//parameterType.length == this.classes.length
|
133
|
+
//Note: right now we don't do any clever mapping, we
|
134
|
+
//only use Java's sub type relation: isAssigableFrom
|
135
|
+
private boolean areArgumentsConvertibleTo(Class<?>[] parameterTypes) {
|
136
|
+
for (int i=0; i < parameterTypes.length; i++) {
|
137
|
+
Class<?> typei = parameterTypes[i];
|
138
|
+
if (this.classes[i] == null) {
|
139
|
+
if (typei.isPrimitive()) {
|
140
|
+
//Can't pass null as primitive
|
141
|
+
return false;
|
142
|
+
}
|
143
|
+
continue; //can always pass null (unless primitive)
|
144
|
+
}
|
145
|
+
if (!typei.isAssignableFrom(this.classes[i])) {
|
146
|
+
return false;
|
147
|
+
}
|
148
|
+
}
|
149
|
+
return true;
|
150
|
+
}
|
151
|
+
|
152
|
+
private Object invokeMethod(Object o, Method m) throws Exception {
|
153
|
+
List<?> a = this.arguments;
|
154
|
+
int size = a.size();
|
155
|
+
switch(size) {
|
156
|
+
case 0:
|
157
|
+
return m.invoke(o);
|
158
|
+
case 1:
|
159
|
+
return m.invoke(o,a.get(0));
|
160
|
+
case 2:
|
161
|
+
return m.invoke(o,a.get(0),a.get(1));
|
162
|
+
case 3:
|
163
|
+
return m.invoke(o,a.get(0),a.get(1),a.get(2));
|
164
|
+
case 4:
|
165
|
+
return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3));
|
166
|
+
case 5:
|
167
|
+
return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4));
|
168
|
+
case 6:
|
169
|
+
return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5));
|
170
|
+
case 7:
|
171
|
+
return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6));
|
172
|
+
case 8:
|
173
|
+
return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7));
|
174
|
+
case 9:
|
175
|
+
return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7),a.get(8));
|
176
|
+
case 10:
|
177
|
+
return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7),a.get(8),a.get(9));
|
178
|
+
case 11:
|
179
|
+
return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7),a.get(8),a.get(9),a.get(10));
|
180
|
+
case 12:
|
181
|
+
return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7),a.get(8),a.get(9),a.get(10),a.get(11));
|
182
|
+
case 13:
|
183
|
+
return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7),a.get(8),a.get(9),a.get(10),a.get(11),a.get(12));
|
184
|
+
case 14:
|
185
|
+
return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7),a.get(8),a.get(9),a.get(10),a.get(11),a.get(12),a.get(13));
|
186
|
+
case 15:
|
187
|
+
return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7),a.get(8),a.get(9),a.get(10),a.get(11),a.get(12),a.get(13),a.get(14));
|
188
|
+
case 16:
|
189
|
+
return m.invoke(o,a.get(0),a.get(1),a.get(2),a.get(3),a.get(4),a.get(5),a.get(6),a.get(7),a.get(8),a.get(9),a.get(10),a.get(11),a.get(12),a.get(13),a.get(14),a.get(15));
|
190
|
+
}
|
191
|
+
throw new UnsupportedOperationException("Method with more than 16 arguments are not supported");
|
192
|
+
|
193
|
+
}
|
194
|
+
|
195
|
+
|
196
|
+
@Override
|
197
|
+
public String getName() {
|
198
|
+
return "InvocationOp["+this.methodName+", arguments = " + this.arguments + "]";
|
199
|
+
}
|
200
|
+
|
201
|
+
}
|