calabash-android 0.4.22.pre4 → 0.5.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/calabash-android +66 -45
- data/lib/calabash-android/calabash_steps.rb +0 -8
- data/lib/calabash-android/canned_steps.md +2 -30
- data/lib/calabash-android/lib/TestServer.apk +0 -0
- data/lib/calabash-android/operations.rb +199 -23
- data/lib/calabash-android/removed_actions.txt +52 -0
- data/lib/calabash-android/steps/assert_steps.rb +9 -24
- data/lib/calabash-android/steps/check_box_steps.rb +2 -2
- data/lib/calabash-android/steps/context_menu_steps.rb +11 -4
- data/lib/calabash-android/steps/date_picker_steps.rb +2 -2
- data/lib/calabash-android/steps/enter_text_steps.rb +13 -13
- data/lib/calabash-android/steps/l10n_steps.rb +5 -5
- data/lib/calabash-android/steps/map_steps.rb +12 -12
- data/lib/calabash-android/steps/navigation_steps.rb +12 -12
- data/lib/calabash-android/steps/press_button_steps.rb +16 -12
- data/lib/calabash-android/steps/progress_steps.rb +19 -22
- data/lib/calabash-android/steps/search_steps.rb +2 -2
- data/lib/calabash-android/steps/spinner_steps.rb +10 -2
- data/lib/calabash-android/steps/time_picker_steps.rb +2 -2
- data/lib/calabash-android/version.rb +1 -1
- data/lib/calabash-android/wait_helpers.rb +29 -1
- data/test-server/instrumentation-backend/antlr/UIQuery.g +11 -11
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/CalabashInstrumentationTestRunner.java +3 -2
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/InstrumentationBackend.java +9 -4
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/Result.java +16 -12
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/application/Backdoor.java +55 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/gestures/LongPressCoordinate.java +19 -2
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/JavaScriptExecuter.java +105 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/QueryHelper.java +27 -30
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ViewMapper.java +27 -18
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/ComparisonOperator.java +7 -1
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTPredicate.java +16 -4
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTWith.java +13 -6
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryUtils.java +94 -48
- metadata +5 -59
- data/lib/calabash-android/steps/additions_manual_steps.rb +0 -11
- data/lib/calabash-android/steps/app_steps.rb +0 -10
- data/lib/calabash-android/steps/list_steps.rb +0 -41
- data/lib/calabash-android/steps/rotation_steps.rb +0 -7
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/PressButtonNumber.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/PressButtonText.java +0 -27
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/PressImageButtonDescription.java +0 -39
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/PressImageButtonNumber.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/WaitForButton.java +0 -47
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/checkbox/ToggleCheckboxNumber.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/contextmenu/LongPressText.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/contextmenu/LongPressTextAndSelectFromMenuById.java +0 -26
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/contextmenu/LongPressTextAndSelectFromMenuByIndex.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/contextmenu/LongPressTextAndSelectFromMenuByText.java +0 -26
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/helpers/InspectCurrentDialog.java +0 -76
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/GetListData.java +0 -85
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/GetListItemProperties.java +0 -194
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/GetListItemText.java +0 -136
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/LongPressListItems.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/PressListItems.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/scrolling/ScrollDown.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/scrolling/ScrollUp.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/search/EnterQueryByIndex.java +0 -29
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/softkey/SelectFromMenuByText.java +0 -24
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/spinner/GetSelectedSpinnerItemText.java +0 -36
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/spinner/SelectSpinnerItemByContentDescription.java +0 -43
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/AssertGridViewContainsNoDuplicates.java +0 -72
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/AssertText.java +0 -31
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/AssertTextOfSpecificTextViewByContentDescription.java +0 -32
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/ClearTextById.java +0 -30
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/ClearTextByIndex.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/ClearTextFieldByContentDescription.java +0 -33
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/ClickOnText.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/EnterTextByContentDescription.java +0 -32
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/EnterTextById.java +0 -33
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/EnterTextByIndex.java +0 -22
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/GetTextById.java +0 -42
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/AssertViewProperty.java +0 -141
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/ClickOnViewByDescription.java +0 -46
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/ClickOnViewById.java +0 -56
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/GetViewProperty.java +0 -101
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/HasView.java +0 -31
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/IsEnabled.java +0 -30
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/LongPressOnViewById.java +0 -34
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/Press.java +0 -89
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/SelectTab.java +0 -110
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/Wait.java +0 -24
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForDialogClose.java +0 -21
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForProgress.java +0 -47
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForScreen.java +0 -54
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForTab.java +0 -108
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForText.java +0 -37
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForView.java +0 -43
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForViewById.java +0 -58
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/JavaScriptOperation.java +0 -44
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/PressByCssSelector.java +0 -70
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/SetText.java +0 -64
@@ -1,7 +1,7 @@
|
|
1
1
|
Then /^I enter "([^\"]*)" into search field$/ do |text|
|
2
|
-
|
2
|
+
enter_text("android.widget.SearchView index:0", text)
|
3
3
|
end
|
4
4
|
|
5
5
|
Then /^I enter "([^\"]*)" into search field number (\d+)$/ do |text, number|
|
6
|
-
|
6
|
+
enter_text("android.widget.SearchView index:#{number.to_i-1}", text)
|
7
7
|
end
|
@@ -1,3 +1,11 @@
|
|
1
|
-
Then /^I select "([^\"]*)" from "([^\"]*)"$/ do |item_text,
|
2
|
-
|
1
|
+
Then /^I select "([^\"]*)" from "([^\"]*)"$/ do |item_text, spinner_identifier|
|
2
|
+
spinner = query("android.widget.Spinner marked:'#{spinner_identifier}'")
|
3
|
+
|
4
|
+
if spinner.empty?
|
5
|
+
tap_when_element_exists("android.widget.Spinner * marked:'#{spinner_identifier}'")
|
6
|
+
else
|
7
|
+
touch(spinner)
|
8
|
+
end
|
9
|
+
|
10
|
+
tap_when_element_exists("android.widget.PopupWindow$PopupViewContainer * marked:'#{item_text}'")
|
3
11
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
|
2
2
|
Given /^I set the time to "(\d\d:\d\d)" on TimePicker with index "([^\"]*)"$/ do |time, index|
|
3
|
-
|
3
|
+
perform_action('set_time_with_index', time, index)
|
4
4
|
end
|
5
5
|
|
6
6
|
Given /^I set the "([^\"]*)" time to "(\d\d:\d\d)"$/ do |content_description, time|
|
7
|
-
|
7
|
+
perform_action('set_time_with_description', content_description, time)
|
8
8
|
end
|
@@ -83,6 +83,11 @@ module Calabash
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
+
#options for wait_for apply
|
87
|
+
def wait_for_element_exists(uiquery, options={})
|
88
|
+
wait_for_elements_exist([uiquery], options)
|
89
|
+
end
|
90
|
+
|
86
91
|
#options for wait_for apply
|
87
92
|
def wait_for_elements_exist(elements_arr, options={})
|
88
93
|
if elements_arr.is_a?(String) || elements_arr.is_a?(Symbol)
|
@@ -93,6 +98,12 @@ module Calabash
|
|
93
98
|
elements_arr.all? { |q| element_exists(q) }
|
94
99
|
end
|
95
100
|
end
|
101
|
+
|
102
|
+
#options for wait_for apply
|
103
|
+
def wait_for_element_do_not_exist(uiquery, options={})
|
104
|
+
wait_for_elements_do_not_exist([uiquery], options)
|
105
|
+
end
|
106
|
+
|
96
107
|
#options for wait_for apply
|
97
108
|
def wait_for_elements_do_not_exist(elements_arr, options={})
|
98
109
|
if elements_arr.is_a?(String)
|
@@ -167,10 +178,27 @@ module Calabash
|
|
167
178
|
action = { :action => lambda { touch uiquery } }
|
168
179
|
opts = DEFAULT_OPTS.merge(action).merge(opts)
|
169
180
|
wait_for_elements_exist([uiquery], opts)
|
170
|
-
|
181
|
+
|
182
|
+
if opts[:action].parameters.length == 0
|
183
|
+
opts[:action].call
|
184
|
+
else
|
185
|
+
opts[:action].call(uiquery)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def wait_for_text(text, options={})
|
190
|
+
wait_for_element_exists("* {text CONTAINS[c] '#{text}'}", options)
|
171
191
|
end
|
172
192
|
|
193
|
+
def wait_for_text_to_disappear(text, options={})
|
194
|
+
wait_for_element_do_not_exist("* {text CONTAINS[c] '#{text}'}", options)
|
195
|
+
end
|
173
196
|
|
197
|
+
def wait_for_activity(activity_name, options={})
|
198
|
+
wait_for(options) do
|
199
|
+
perform_action('get_activity_name')['message'] == activity_name
|
200
|
+
end
|
201
|
+
end
|
174
202
|
end
|
175
203
|
end
|
176
204
|
end
|
@@ -32,13 +32,13 @@ options {
|
|
32
32
|
}
|
33
33
|
}
|
34
34
|
|
35
|
-
query : expr (WHITE! expr)*
|
35
|
+
query : expr (WHITE! expr)*
|
36
36
|
;
|
37
|
-
|
38
37
|
|
39
|
-
|
38
|
+
|
39
|
+
expr : (className | filter | visibility | predicate | DIRECTION^)
|
40
40
|
;
|
41
|
-
|
41
|
+
|
42
42
|
DIRECTION : 'descendant' | 'child' | 'parent' | 'sibling'
|
43
43
|
;
|
44
44
|
|
@@ -66,12 +66,12 @@ BEGINPRED : '{'
|
|
66
66
|
;
|
67
67
|
ENDPRED : '}'
|
68
68
|
;
|
69
|
-
|
70
|
-
RELATION : | '=' | '>' | '>=' | '<' | '<=' |
|
71
|
-
(( 'BEGINSWITH' | 'ENDSWITH' | 'CONTAINS' | 'LIKE'
|
69
|
+
|
70
|
+
RELATION : | '=' | '>' | '>=' | '<' | '<=' | '!=' | '<>' |
|
71
|
+
(( 'BEGINSWITH' | 'ENDSWITH' | 'CONTAINS' | 'LIKE'
|
72
72
|
| 'beginswith' | 'endswith' | 'contains' | 'like') ('[' ('a'..'z' | 'A'..'Z')* ']')?)
|
73
|
-
|
74
|
-
;
|
73
|
+
|
74
|
+
;
|
75
75
|
|
76
76
|
INT : '0'..'9'+
|
77
77
|
;
|
@@ -86,8 +86,8 @@ NAME : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_'|'$')*
|
|
86
86
|
;
|
87
87
|
|
88
88
|
STRING
|
89
|
-
: '\'' ( ESC_SEQ | ~('\\'|'\'') )* '\''
|
90
|
-
| '"' ( DOUBLE_ESC_SEQ | ~('\\'|'"') )* '"'
|
89
|
+
: '\'' ( ESC_SEQ | ~('\\'|'\'') )* '\''
|
90
|
+
| '"' ( DOUBLE_ESC_SEQ | ~('\\'|'"') )* '"'
|
91
91
|
;
|
92
92
|
|
93
93
|
WHITE : ' '+ ;
|
@@ -2,8 +2,8 @@ package sh.calaba.instrumentationbackend;
|
|
2
2
|
|
3
3
|
import java.lang.reflect.Method;
|
4
4
|
|
5
|
-
import sh.calaba.instrumentationbackend.actions.HttpServer;
|
6
5
|
import android.app.Activity;
|
6
|
+
import sh.calaba.instrumentationbackend.actions.HttpServer;
|
7
7
|
import android.content.Context;
|
8
8
|
import android.os.Bundle;
|
9
9
|
import android.test.InstrumentationTestRunner;
|
@@ -17,6 +17,7 @@ public class CalabashInstrumentationTestRunner extends InstrumentationTestRunner
|
|
17
17
|
Method method = c.getDeclaredMethod ("LoadApplication", Context.class, String.class, String[].class);
|
18
18
|
method.invoke (null, context, null, new String[]{context.getApplicationInfo ().sourceDir});
|
19
19
|
System.out.println("Calabash loaded Mono");
|
20
|
+
InstrumentationBackend.mainActivity = Class.forName(arguments.getString("main_activity")).asSubclass(Activity.class);
|
20
21
|
} catch (Exception e) {
|
21
22
|
System.out.println("Calabash did not load Mono. This is only a problem if you are trying to test a Mono application");
|
22
23
|
}
|
@@ -28,7 +29,7 @@ public class CalabashInstrumentationTestRunner extends InstrumentationTestRunner
|
|
28
29
|
InstrumentationBackend.extras = arguments;
|
29
30
|
|
30
31
|
try {
|
31
|
-
InstrumentationBackend.
|
32
|
+
InstrumentationBackend.mainActivityName = arguments.getString("main_activity");
|
32
33
|
} catch (Exception e) {
|
33
34
|
throw new RuntimeException(e);
|
34
35
|
}
|
@@ -24,7 +24,8 @@ import java.util.concurrent.atomic.AtomicReference;
|
|
24
24
|
|
25
25
|
public class InstrumentationBackend extends ActivityInstrumentationTestCase2<Activity> {
|
26
26
|
public static String testPackage;
|
27
|
-
public static String
|
27
|
+
public static String mainActivityName;
|
28
|
+
public static Class<? extends Activity> mainActivity;
|
28
29
|
public static Bundle extras;
|
29
30
|
|
30
31
|
private static final String TAG = "InstrumentationBackend";
|
@@ -35,13 +36,17 @@ public class InstrumentationBackend extends ActivityInstrumentationTestCase2<Act
|
|
35
36
|
public static Actions actions;
|
36
37
|
|
37
38
|
public InstrumentationBackend() {
|
38
|
-
super(
|
39
|
+
super((Class<Activity>)mainActivity);
|
39
40
|
}
|
40
41
|
|
41
42
|
@Override
|
42
43
|
public Activity getActivity() {
|
44
|
+
if (mainActivity != null) {
|
45
|
+
return super.getActivity();
|
46
|
+
}
|
47
|
+
|
43
48
|
try {
|
44
|
-
setMainActivity(Class.forName(
|
49
|
+
setMainActivity(Class.forName(mainActivityName).asSubclass(Activity.class));
|
45
50
|
return super.getActivity();
|
46
51
|
} catch (ClassNotFoundException e) {
|
47
52
|
throw new RuntimeException(e);
|
@@ -62,7 +67,7 @@ public class InstrumentationBackend extends ActivityInstrumentationTestCase2<Act
|
|
62
67
|
protected void setUp() throws Exception {
|
63
68
|
super.setUp();
|
64
69
|
Intent i = new Intent(Intent.ACTION_MAIN);
|
65
|
-
i.setClassName(testPackage,
|
70
|
+
i.setClassName(testPackage, mainActivityName);
|
66
71
|
i.addCategory("android.intent.category.LAUNCHER");
|
67
72
|
i.putExtras(extras);
|
68
73
|
setActivityIntent(i);
|
@@ -6,18 +6,18 @@ import java.util.ArrayList;
|
|
6
6
|
import java.util.List;
|
7
7
|
|
8
8
|
public class Result {
|
9
|
-
|
9
|
+
|
10
10
|
boolean success;
|
11
11
|
String message;
|
12
12
|
List<String> bonusInformation = new ArrayList<String>();
|
13
|
-
|
13
|
+
|
14
14
|
public Result() {
|
15
15
|
}
|
16
|
-
|
16
|
+
|
17
17
|
public Result(boolean success) {
|
18
18
|
this(success, "");
|
19
19
|
}
|
20
|
-
|
20
|
+
|
21
21
|
public Result(boolean success, String message) {
|
22
22
|
this.success = success;
|
23
23
|
this.message = message;
|
@@ -32,19 +32,19 @@ public class Result {
|
|
32
32
|
public String getMessage() {
|
33
33
|
return message;
|
34
34
|
}
|
35
|
-
|
35
|
+
|
36
36
|
public void setMessage(String message) {
|
37
37
|
this.message = message;
|
38
38
|
}
|
39
|
-
|
39
|
+
|
40
40
|
public boolean isSuccess() {
|
41
41
|
return success;
|
42
42
|
}
|
43
|
-
|
43
|
+
|
44
44
|
public void setSuccess(boolean success) {
|
45
45
|
this.success = success;
|
46
46
|
}
|
47
|
-
|
47
|
+
|
48
48
|
public void addBonusInformation(String information) {
|
49
49
|
bonusInformation.add(information);
|
50
50
|
}
|
@@ -52,11 +52,11 @@ public class Result {
|
|
52
52
|
public List<String> getBonusInformation() {
|
53
53
|
return bonusInformation;
|
54
54
|
}
|
55
|
-
|
55
|
+
|
56
56
|
public void setExtras(List<String> bonusInformation) {
|
57
57
|
this.bonusInformation = bonusInformation;
|
58
58
|
}
|
59
|
-
|
59
|
+
|
60
60
|
public static Result fromThrowable(Throwable t) {
|
61
61
|
Result r = new Result(false, t.getMessage());
|
62
62
|
CharArrayWriter caw = new CharArrayWriter();
|
@@ -64,11 +64,15 @@ public class Result {
|
|
64
64
|
r.addBonusInformation("Exception stack trace:\n" + caw.toString());
|
65
65
|
return r;
|
66
66
|
}
|
67
|
-
|
67
|
+
|
68
68
|
public static Result successResult() {
|
69
69
|
return new Result(true);
|
70
70
|
}
|
71
71
|
|
72
|
+
public static Result successResult(final String message) {
|
73
|
+
return new Result(true, message);
|
74
|
+
}
|
75
|
+
|
72
76
|
public static Result failedResult() {
|
73
77
|
return new Result(false);
|
74
78
|
}
|
@@ -76,7 +80,7 @@ public class Result {
|
|
76
80
|
public static Result failedResult(final String message) {
|
77
81
|
return new Result(false, message);
|
78
82
|
}
|
79
|
-
|
83
|
+
|
80
84
|
public String toString() {
|
81
85
|
return "Success: " + success + ", message: " + message;
|
82
86
|
}
|
@@ -0,0 +1,55 @@
|
|
1
|
+
package sh.calaba.instrumentationbackend.actions.application;
|
2
|
+
|
3
|
+
import java.util.ArrayList;
|
4
|
+
import java.util.List;
|
5
|
+
|
6
|
+
import android.app.Activity;
|
7
|
+
import android.app.Application;
|
8
|
+
import android.content.Context;
|
9
|
+
|
10
|
+
import sh.calaba.instrumentationbackend.InstrumentationBackend;
|
11
|
+
import sh.calaba.instrumentationbackend.Result;
|
12
|
+
import sh.calaba.instrumentationbackend.actions.Action;
|
13
|
+
import sh.calaba.instrumentationbackend.query.Operation;
|
14
|
+
import sh.calaba.instrumentationbackend.query.InvocationOperation;
|
15
|
+
import sh.calaba.instrumentationbackend.query.QueryResult;
|
16
|
+
import sh.calaba.instrumentationbackend.query.UIQueryResultVoid;
|
17
|
+
|
18
|
+
|
19
|
+
public class Backdoor implements Action {
|
20
|
+
|
21
|
+
private static final String TAG = "Backdoor";
|
22
|
+
|
23
|
+
@Override
|
24
|
+
public Result execute(String... args) {
|
25
|
+
if (args.length != 2) {
|
26
|
+
return Result.failedResult("You must provide method name and an argument.");
|
27
|
+
}
|
28
|
+
|
29
|
+
String methodName = args[0];
|
30
|
+
List arguments = new ArrayList(1);
|
31
|
+
arguments.add(args[1]);
|
32
|
+
// create invocation operation to call method
|
33
|
+
Operation op = new InvocationOperation(methodName, arguments);
|
34
|
+
// get an application object to call operation on
|
35
|
+
Context app = InstrumentationBackend.solo.getCurrentActivity().getApplication();
|
36
|
+
String backdoorResult = null;
|
37
|
+
try {
|
38
|
+
backdoorResult = (String)op.apply(app);
|
39
|
+
} catch (Exception e) {
|
40
|
+
android.util.Log.e(TAG, android.util.Log.getStackTraceString(e));
|
41
|
+
return Result.failedResult("No such backdoor method found: public String " + op.getName() + "(String arg)");
|
42
|
+
}
|
43
|
+
|
44
|
+
// set backdoor result as bonus
|
45
|
+
Result result = Result.successResult();
|
46
|
+
result.addBonusInformation(backdoorResult);
|
47
|
+
return result;
|
48
|
+
}
|
49
|
+
|
50
|
+
@Override
|
51
|
+
public String key() {
|
52
|
+
return "backdoor";
|
53
|
+
}
|
54
|
+
|
55
|
+
}
|
@@ -5,6 +5,19 @@ import sh.calaba.instrumentationbackend.InstrumentationBackend;
|
|
5
5
|
import sh.calaba.instrumentationbackend.Result;
|
6
6
|
import sh.calaba.instrumentationbackend.actions.Action;
|
7
7
|
|
8
|
+
/**
|
9
|
+
* <p>
|
10
|
+
* Action that performs a long press on given coordinates.
|
11
|
+
* </p>
|
12
|
+
* <p>
|
13
|
+
* Parameters:
|
14
|
+
* <ul>
|
15
|
+
* <li>args[0]: x coordinate (float)</li>
|
16
|
+
* <li>args[1]: y coordinate (float)</li>
|
17
|
+
* <li>args[2]: length of the long press in millisecond (optional, integer)</li>
|
18
|
+
* </ul>
|
19
|
+
* </p>
|
20
|
+
*/
|
8
21
|
public class LongPressCoordinate implements Action {
|
9
22
|
@Override
|
10
23
|
public Result execute(String... args) {
|
@@ -12,8 +25,12 @@ public class LongPressCoordinate implements Action {
|
|
12
25
|
|
13
26
|
float x = Float.parseFloat(args[0]);
|
14
27
|
float y = Float.parseFloat(args[1]);
|
15
|
-
|
16
|
-
|
28
|
+
if (args.length > 2) {
|
29
|
+
int time = Integer.parseInt(args[2]);
|
30
|
+
InstrumentationBackend.solo.clickLongOnScreen(x, y, time);
|
31
|
+
} else {
|
32
|
+
InstrumentationBackend.solo.clickLongOnScreen(x, y);
|
33
|
+
}
|
17
34
|
|
18
35
|
return Result.successResult();
|
19
36
|
}
|
@@ -0,0 +1,105 @@
|
|
1
|
+
package sh.calaba.instrumentationbackend.actions.webview;
|
2
|
+
|
3
|
+
import java.lang.reflect.Constructor;
|
4
|
+
import java.lang.reflect.Field;
|
5
|
+
import java.lang.reflect.InvocationTargetException;
|
6
|
+
import java.lang.reflect.Method;
|
7
|
+
|
8
|
+
import android.os.Build;
|
9
|
+
import android.webkit.WebView;
|
10
|
+
|
11
|
+
public class JavaScriptExecuter {
|
12
|
+
private WebView webView;
|
13
|
+
private Object provider;
|
14
|
+
|
15
|
+
public JavaScriptExecuter(WebView webView) {
|
16
|
+
this.webView = webView;
|
17
|
+
}
|
18
|
+
|
19
|
+
public void executeJavaScript(String javaScript) {
|
20
|
+
try {
|
21
|
+
provider = getProvider();
|
22
|
+
loadUrlImpl("javascript:" + javaScript);
|
23
|
+
} catch (Exception e) {
|
24
|
+
throw new RuntimeException(e);
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
private void callSwitchOutDrawHistory() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
|
29
|
+
Method method = provider.getClass().getDeclaredMethod("switchOutDrawHistory");
|
30
|
+
method.setAccessible(true);
|
31
|
+
method.invoke(provider);
|
32
|
+
}
|
33
|
+
|
34
|
+
private void loadUrlImpl(String url) throws NoSuchMethodException, IllegalAccessException, NoSuchFieldException, InstantiationException, InvocationTargetException, ClassNotFoundException {
|
35
|
+
callSwitchOutDrawHistory();
|
36
|
+
sendMessage(url);
|
37
|
+
}
|
38
|
+
|
39
|
+
private void sendMessage(String url) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InstantiationException, InvocationTargetException, ClassNotFoundException {
|
40
|
+
Object arg = getUrlData(url);
|
41
|
+
Object webViewCore = getWebViewCore();
|
42
|
+
|
43
|
+
int messageIdentifier = loadUrlMessage();
|
44
|
+
|
45
|
+
Method sendMessageMethod = webViewCore.getClass().getDeclaredMethod("sendMessage", int.class, Object.class);
|
46
|
+
sendMessageMethod.setAccessible(true);
|
47
|
+
sendMessageMethod.invoke(webViewCore, messageIdentifier, arg);
|
48
|
+
}
|
49
|
+
|
50
|
+
private final String EVENT_HUB_CLASS_NAME = "android.webkit.WebViewCore$EventHub";
|
51
|
+
|
52
|
+
private int loadUrlMessage() throws NoSuchFieldException, ClassNotFoundException, IllegalAccessException {
|
53
|
+
Class<?> eventHubClass = Class.forName(EVENT_HUB_CLASS_NAME);
|
54
|
+
Field loadUrlField = eventHubClass.getDeclaredField("LOAD_URL");
|
55
|
+
loadUrlField.setAccessible(true);
|
56
|
+
|
57
|
+
return loadUrlField.getInt(String.class);
|
58
|
+
}
|
59
|
+
|
60
|
+
private final String GET_URL_DATA_CLASS_NAME = "android.webkit.WebViewCore$GetUrlData";
|
61
|
+
|
62
|
+
private Object getUrlData(String url) throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException, IllegalAccessException, InvocationTargetException, InstantiationException {
|
63
|
+
// For Android OS pre 2.2 the url was a string
|
64
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) {
|
65
|
+
return url;
|
66
|
+
} else {
|
67
|
+
Class<?> getUrlDataClass = Class.forName(GET_URL_DATA_CLASS_NAME);
|
68
|
+
Constructor<?> constructor = getUrlDataClass.getDeclaredConstructor();
|
69
|
+
constructor.setAccessible(true);
|
70
|
+
|
71
|
+
Field mUrlField = getUrlDataClass.getDeclaredField("mUrl");
|
72
|
+
mUrlField.setAccessible(true);
|
73
|
+
Field mExtraHeadersField = getUrlDataClass.getDeclaredField("mExtraHeaders");
|
74
|
+
mExtraHeadersField.setAccessible(true);
|
75
|
+
|
76
|
+
Object getUrlDataInstance = constructor.newInstance();
|
77
|
+
mUrlField.set(getUrlDataInstance, url);
|
78
|
+
mExtraHeadersField.set(getUrlDataInstance, null);
|
79
|
+
|
80
|
+
return getUrlDataInstance;
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
private Object getProvider() throws NoSuchFieldException, IllegalAccessException {
|
85
|
+
// For Android OS pre 4.1 the implementation of loadUrl was within the WebView widget class
|
86
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
|
87
|
+
return webView;
|
88
|
+
} else {
|
89
|
+
Field fieldProvider = WebView.class.getDeclaredField("mProvider");
|
90
|
+
fieldProvider.setAccessible(true);
|
91
|
+
|
92
|
+
return fieldProvider.get(webView);
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
private Object getWebViewCore() throws IllegalStateException, IllegalAccessException, NoSuchFieldException {
|
97
|
+
if (provider == null) throw new IllegalStateException("Provider is null");
|
98
|
+
|
99
|
+
Field fieldCore = provider.getClass().getDeclaredField("mWebViewCore");
|
100
|
+
fieldCore.setAccessible(true);
|
101
|
+
Object webViewCore = fieldCore.get(provider);
|
102
|
+
|
103
|
+
return webViewCore;
|
104
|
+
}
|
105
|
+
}
|