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.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/bin/calabash-android +66 -45
  3. data/lib/calabash-android/calabash_steps.rb +0 -8
  4. data/lib/calabash-android/canned_steps.md +2 -30
  5. data/lib/calabash-android/lib/TestServer.apk +0 -0
  6. data/lib/calabash-android/operations.rb +199 -23
  7. data/lib/calabash-android/removed_actions.txt +52 -0
  8. data/lib/calabash-android/steps/assert_steps.rb +9 -24
  9. data/lib/calabash-android/steps/check_box_steps.rb +2 -2
  10. data/lib/calabash-android/steps/context_menu_steps.rb +11 -4
  11. data/lib/calabash-android/steps/date_picker_steps.rb +2 -2
  12. data/lib/calabash-android/steps/enter_text_steps.rb +13 -13
  13. data/lib/calabash-android/steps/l10n_steps.rb +5 -5
  14. data/lib/calabash-android/steps/map_steps.rb +12 -12
  15. data/lib/calabash-android/steps/navigation_steps.rb +12 -12
  16. data/lib/calabash-android/steps/press_button_steps.rb +16 -12
  17. data/lib/calabash-android/steps/progress_steps.rb +19 -22
  18. data/lib/calabash-android/steps/search_steps.rb +2 -2
  19. data/lib/calabash-android/steps/spinner_steps.rb +10 -2
  20. data/lib/calabash-android/steps/time_picker_steps.rb +2 -2
  21. data/lib/calabash-android/version.rb +1 -1
  22. data/lib/calabash-android/wait_helpers.rb +29 -1
  23. data/test-server/instrumentation-backend/antlr/UIQuery.g +11 -11
  24. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/CalabashInstrumentationTestRunner.java +3 -2
  25. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/InstrumentationBackend.java +9 -4
  26. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/Result.java +16 -12
  27. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/application/Backdoor.java +55 -0
  28. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/gestures/LongPressCoordinate.java +19 -2
  29. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/JavaScriptExecuter.java +105 -0
  30. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/QueryHelper.java +27 -30
  31. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ViewMapper.java +27 -18
  32. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/ComparisonOperator.java +7 -1
  33. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTPredicate.java +16 -4
  34. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryASTWith.java +13 -6
  35. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/ast/UIQueryUtils.java +94 -48
  36. metadata +5 -59
  37. data/lib/calabash-android/steps/additions_manual_steps.rb +0 -11
  38. data/lib/calabash-android/steps/app_steps.rb +0 -10
  39. data/lib/calabash-android/steps/list_steps.rb +0 -41
  40. data/lib/calabash-android/steps/rotation_steps.rb +0 -7
  41. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/PressButtonNumber.java +0 -22
  42. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/PressButtonText.java +0 -27
  43. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/PressImageButtonDescription.java +0 -39
  44. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/PressImageButtonNumber.java +0 -22
  45. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/button/WaitForButton.java +0 -47
  46. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/checkbox/ToggleCheckboxNumber.java +0 -22
  47. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/contextmenu/LongPressText.java +0 -22
  48. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/contextmenu/LongPressTextAndSelectFromMenuById.java +0 -26
  49. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/contextmenu/LongPressTextAndSelectFromMenuByIndex.java +0 -22
  50. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/contextmenu/LongPressTextAndSelectFromMenuByText.java +0 -26
  51. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/helpers/InspectCurrentDialog.java +0 -76
  52. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/GetListData.java +0 -85
  53. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/GetListItemProperties.java +0 -194
  54. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/GetListItemText.java +0 -136
  55. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/LongPressListItems.java +0 -22
  56. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/PressListItems.java +0 -22
  57. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/scrolling/ScrollDown.java +0 -22
  58. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/scrolling/ScrollUp.java +0 -22
  59. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/search/EnterQueryByIndex.java +0 -29
  60. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/softkey/SelectFromMenuByText.java +0 -24
  61. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/spinner/GetSelectedSpinnerItemText.java +0 -36
  62. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/spinner/SelectSpinnerItemByContentDescription.java +0 -43
  63. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/AssertGridViewContainsNoDuplicates.java +0 -72
  64. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/AssertText.java +0 -31
  65. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/AssertTextOfSpecificTextViewByContentDescription.java +0 -32
  66. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/ClearTextById.java +0 -30
  67. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/ClearTextByIndex.java +0 -22
  68. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/ClearTextFieldByContentDescription.java +0 -33
  69. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/ClickOnText.java +0 -22
  70. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/EnterTextByContentDescription.java +0 -32
  71. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/EnterTextById.java +0 -33
  72. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/EnterTextByIndex.java +0 -22
  73. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/GetTextById.java +0 -42
  74. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/AssertViewProperty.java +0 -141
  75. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/ClickOnViewByDescription.java +0 -46
  76. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/ClickOnViewById.java +0 -56
  77. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/GetViewProperty.java +0 -101
  78. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/HasView.java +0 -31
  79. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/IsEnabled.java +0 -30
  80. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/LongPressOnViewById.java +0 -34
  81. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/Press.java +0 -89
  82. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/SelectTab.java +0 -110
  83. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/Wait.java +0 -24
  84. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForDialogClose.java +0 -21
  85. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForProgress.java +0 -47
  86. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForScreen.java +0 -54
  87. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForTab.java +0 -108
  88. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForText.java +0 -37
  89. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForView.java +0 -43
  90. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForViewById.java +0 -58
  91. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/JavaScriptOperation.java +0 -44
  92. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/PressByCssSelector.java +0 -70
  93. 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
- performAction('enter_query_into_numbered_field', text, 1)
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
- performAction('enter_query_into_numbered_field', text, number)
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, spinner_content_description|
2
- performAction('select_item_from_named_spinner', spinner_content_description, item_text)
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
- performAction('set_time_with_index', time, index)
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
- performAction('set_time_with_description', content_description, time)
7
+ perform_action('set_time_with_description', content_description, time)
8
8
  end
@@ -1,5 +1,5 @@
1
1
  module Calabash
2
2
  module Android
3
- VERSION = "0.4.22.pre4"
3
+ VERSION = "0.5.0.pre1"
4
4
  end
5
5
  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
- opts[:action].call
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
- expr : (className | filter | visibility | predicate | DIRECTION^)
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.mainActivity = arguments.getString("main_activity");
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 mainActivity;
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(null);
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(mainActivity).asSubclass(Activity.class));
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, mainActivity);
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
- InstrumentationBackend.solo.clickLongOnScreen(x, y);
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
+ }