calabash-android 0.5.1 → 0.5.2.pre1

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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/bin/calabash-android-console.rb +24 -9
  4. data/bin/calabash-android-run.rb +4 -1
  5. data/bin/calabash-android-setup.rb +1 -1
  6. data/lib/calabash-android/deprecated_actions.map +8 -0
  7. data/lib/calabash-android/env.rb +30 -2
  8. data/lib/calabash-android/environment_helpers.rb +12 -0
  9. data/lib/calabash-android/gestures.rb +308 -0
  10. data/lib/calabash-android/helpers.rb +55 -6
  11. data/lib/calabash-android/java_keystore.rb +2 -1
  12. data/lib/calabash-android/lib/TestServer.apk +0 -0
  13. data/lib/calabash-android/operations.rb +901 -707
  14. data/lib/calabash-android/removed_actions.txt +4 -0
  15. data/lib/calabash-android/steps/date_picker_steps.rb +4 -4
  16. data/lib/calabash-android/steps/time_picker_steps.rb +3 -3
  17. data/lib/calabash-android/touch_helpers.rb +114 -18
  18. data/lib/calabash-android/version.rb +1 -1
  19. data/test-server/calabash-js/src/calabash.js +42 -1
  20. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/HttpServer.java +67 -2
  21. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/MultiTouchGesture.java +749 -0
  22. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/softkey/PressKey.java +85 -0
  23. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/HideSoftKeyboard.java +24 -2
  24. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/PressUserActionButton.java +128 -0
  25. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/QueryHelper.java +8 -1
  26. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/query/InvocationOperation.java +56 -9
  27. metadata +10 -8
  28. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/time/SetDateByContentDescription.java +0 -33
  29. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/time/SetDateByIndex.java +0 -24
  30. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/time/SetTimeByContentDescription.java +0 -34
  31. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/time/SetTimeByIndex.java +0 -26
@@ -0,0 +1,85 @@
1
+ package sh.calaba.instrumentationbackend.actions.softkey;
2
+
3
+ import android.app.Instrumentation;
4
+ import android.view.KeyEvent;
5
+
6
+ import java.lang.reflect.Field;
7
+
8
+ import sh.calaba.instrumentationbackend.InstrumentationBackend;
9
+ import sh.calaba.instrumentationbackend.Result;
10
+ import sh.calaba.instrumentationbackend.actions.Action;
11
+
12
+ public class PressKey implements Action {
13
+ @Override
14
+ public Result execute(String ... args) {
15
+ if (args.length != 1) {
16
+ return Result.failedResult("This action takes one argument ([String/int] key).");
17
+ }
18
+
19
+ String keyString = args[0];
20
+ Integer keyCode = null;
21
+
22
+ if (isNumber(keyString)) {
23
+ keyCode = Integer.parseInt(keyString);
24
+ } else {
25
+ keyCode = getKey(keyString);
26
+ }
27
+
28
+ if (keyCode == null || keyCode < 0) {
29
+ return Result.failedResult("Could not find key code from argument '" + keyString + "'");
30
+ }
31
+
32
+ Instrumentation instrumentation = InstrumentationBackend.instrumentation;
33
+ Exception securityException = new SecurityException();
34
+
35
+ for (int i = 0; i < 10; i++) { // Retry sending the key 10 times
36
+ try {
37
+ instrumentation.sendKeyDownUpSync(keyCode);
38
+
39
+ return Result.successResult();
40
+ } catch (SecurityException e) {
41
+ securityException = e;
42
+
43
+ // Sleep and try again
44
+ try {
45
+ Thread.sleep(200);
46
+ } catch (InterruptedException interruptedException) {
47
+
48
+ }
49
+ }
50
+ }
51
+
52
+ // The input event injection failed. This is most likely due to the application not having focus
53
+ throw new SecurityException(securityException);
54
+ }
55
+
56
+ @Override
57
+ public String key() {
58
+ return "press_key";
59
+ }
60
+
61
+ public static Integer getKey(String keyName) {
62
+ keyName = keyName.toUpperCase();
63
+
64
+ Class<?> keyEventClass = KeyEvent.class;
65
+ try {
66
+ Field field = keyEventClass.getField(keyName);
67
+
68
+ return field.getInt(null);
69
+ } catch (NoSuchFieldException e) {
70
+ return null;
71
+ } catch (IllegalAccessException e) {
72
+ return null;
73
+ }
74
+ }
75
+
76
+ private static boolean isNumber(String string) {
77
+ try {
78
+ Integer.parseInt(string);
79
+
80
+ return true;
81
+ } catch (NumberFormatException e) {
82
+ return false;
83
+ }
84
+ }
85
+ }
@@ -5,6 +5,8 @@ import android.content.Context;
5
5
  import android.view.View;
6
6
  import android.view.inputmethod.InputMethodManager;
7
7
 
8
+ import java.lang.reflect.Field;
9
+
8
10
  import sh.calaba.instrumentationbackend.InstrumentationBackend;
9
11
  import sh.calaba.instrumentationbackend.Result;
10
12
  import sh.calaba.instrumentationbackend.actions.Action;
@@ -16,7 +18,13 @@ public class HideSoftKeyboard implements Action {
16
18
  InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
17
19
 
18
20
  Activity activity = InstrumentationBackend.solo.getCurrentActivity();
19
- View view = activity.getCurrentFocus();
21
+ View view;
22
+
23
+ view = tryGetServedView();
24
+
25
+ if (view == null) {
26
+ view = activity.getCurrentFocus();
27
+ }
20
28
 
21
29
  if (view == null) {
22
30
  view = new View(activity);
@@ -27,8 +35,22 @@ public class HideSoftKeyboard implements Action {
27
35
  return Result.successResult();
28
36
  }
29
37
 
38
+ View tryGetServedView() {
39
+ Context context = InstrumentationBackend.instrumentation.getTargetContext();
40
+
41
+ try {
42
+ InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
43
+ Field servedViewField = InputMethodManager.class.getDeclaredField("mServedView");
44
+ servedViewField.setAccessible(true);
45
+
46
+ return (View)servedViewField.get(inputMethodManager);
47
+ } catch (Exception e) {
48
+ return null;
49
+ }
50
+ }
51
+
30
52
  @Override
31
53
  public String key() {
32
54
  return "hide_soft_keyboard";
33
55
  }
34
- }
56
+ }
@@ -0,0 +1,128 @@
1
+ package sh.calaba.instrumentationbackend.actions.text;
2
+
3
+ import android.app.Activity;
4
+ import android.content.Context;
5
+ import android.view.View;
6
+ import android.view.inputmethod.EditorInfo;
7
+ import android.view.inputmethod.InputConnection;
8
+ import android.view.inputmethod.InputMethodManager;
9
+
10
+ import java.lang.Integer;
11
+ import java.lang.reflect.Field;
12
+ import java.lang.reflect.Method;
13
+ import java.util.Map;
14
+ import java.util.HashMap;
15
+
16
+ import sh.calaba.instrumentationbackend.InstrumentationBackend;
17
+ import sh.calaba.instrumentationbackend.Result;
18
+ import sh.calaba.instrumentationbackend.actions.Action;
19
+
20
+ public class PressUserActionButton implements Action {
21
+ private static Map<String,Integer> actionCodeMap;
22
+
23
+ static {
24
+ actionCodeMap = new HashMap<String, Integer>();
25
+ actionCodeMap.put("normal", 0);
26
+ actionCodeMap.put("unspecified", 0);
27
+ actionCodeMap.put("none", 1);
28
+ actionCodeMap.put("go", 2);
29
+ actionCodeMap.put("search", 3);
30
+ actionCodeMap.put("send", 4);
31
+ actionCodeMap.put("next", 5);
32
+ actionCodeMap.put("done", 6);
33
+ actionCodeMap.put("previous", 7);
34
+ }
35
+
36
+ @Override
37
+ public Result execute(String... args) {
38
+ if (args.length > 1) {
39
+ return Result.failedResult("This action takes zero arguments or one argument ([String] action name)");
40
+ }
41
+
42
+ final View view = getServedView();
43
+ final InputConnection inputConnection = getInputConnection();
44
+ final int imeActionCode;
45
+
46
+ if (inputConnection == null) {
47
+ return Result.failedResult("Could not press user action button. No element has focus.");
48
+ }
49
+
50
+ if (args.length >= 1) {
51
+ try {
52
+ imeActionCode = findActionCode(args[0]);
53
+ } catch (IllegalArgumentException e) {
54
+ throw new RuntimeException(e);
55
+ }
56
+ } else {
57
+ imeActionCode = findActionCode(view);
58
+ }
59
+
60
+ InstrumentationBackend.solo.runOnMainSync(new Runnable() {
61
+ @Override
62
+ public void run() {
63
+ inputConnection.performEditorAction(imeActionCode);
64
+ }
65
+ });
66
+
67
+ return Result.successResult();
68
+ }
69
+
70
+ @Override
71
+ public String key() {
72
+ return "press_user_action_button";
73
+ }
74
+
75
+ InputConnection getInputConnection() {
76
+ Context context = InstrumentationBackend.instrumentation.getTargetContext();
77
+
78
+ try {
79
+ InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
80
+ Field servedInputConnectionField = InputMethodManager.class.getDeclaredField("mServedInputConnection");
81
+ servedInputConnectionField.setAccessible(true);
82
+
83
+ return (InputConnection)servedInputConnectionField.get(inputMethodManager);
84
+ } catch (Exception e) {
85
+ throw new RuntimeException(e);
86
+ }
87
+ }
88
+
89
+ View getServedView() {
90
+ Context context = InstrumentationBackend.instrumentation.getTargetContext();
91
+
92
+ try {
93
+ InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
94
+ Field servedViewField = InputMethodManager.class.getDeclaredField("mServedView");
95
+ servedViewField.setAccessible(true);
96
+
97
+ return (View)servedViewField.get(inputMethodManager);
98
+ } catch (Exception e) {
99
+ throw new RuntimeException(e);
100
+ }
101
+ }
102
+
103
+ private int findActionCode(View view) {
104
+ EditorInfo editorInfo = new EditorInfo();
105
+ view.onCreateInputConnection(editorInfo);
106
+
107
+ int actionId = editorInfo.actionId;
108
+ int imeOptions = editorInfo.imeOptions & EditorInfo.IME_MASK_ACTION;
109
+
110
+ if (actionId > 0) {
111
+ return actionId;
112
+ } else if (imeOptions > 0) {
113
+ return imeOptions;
114
+ } else {
115
+ return findActionCode("done");
116
+ }
117
+ }
118
+
119
+ private int findActionCode(String actionName) throws IllegalArgumentException {
120
+ actionName = actionName.toLowerCase();
121
+
122
+ try {
123
+ return actionCodeMap.get(actionName);
124
+ } catch (NullPointerException e) {
125
+ throw new IllegalArgumentException("Action name '" + actionName + "' invalid");
126
+ }
127
+ }
128
+ }
@@ -46,13 +46,20 @@ public class QueryHelper {
46
46
  int center_y = (int)translateCoordToScreen(webviewLocation[1], scale, rectangle.get("center_y"));
47
47
 
48
48
  int x = (int)translateCoordToScreen(webviewLocation[0], scale, rectangle.get("left"));
49
- int y = (int)translateCoordToScreen(webviewLocation[0], scale, rectangle.get("top"));
49
+ int y = (int)translateCoordToScreen(webviewLocation[1], scale, rectangle.get("top"));
50
+
51
+ int width = (int)translateCoordToScreen(0, scale, rectangle.get("width"));
52
+ int height = (int)translateCoordToScreen(0, scale, rectangle.get("height"));
53
+
50
54
  Map<String,Integer> result = new HashMap<String, Integer>(rectangle);
51
55
 
52
56
  result.put("x", x);
53
57
  result.put("y", y);
54
58
  result.put("center_x", center_x);
55
59
  result.put("center_y", center_y);
60
+
61
+ result.put("width", width);
62
+ result.put("height", height);
56
63
 
57
64
  return result;
58
65
  } catch (Exception e) {
@@ -5,6 +5,7 @@ import java.util.List;
5
5
  import java.util.concurrent.atomic.AtomicReference;
6
6
 
7
7
  import sh.calaba.instrumentationbackend.InstrumentationBackend;
8
+ import sh.calaba.instrumentationbackend.Result;
8
9
 
9
10
  public class InvocationOperation implements Operation {
10
11
 
@@ -12,14 +13,16 @@ public class InvocationOperation implements Operation {
12
13
  @SuppressWarnings("rawtypes")
13
14
  private final List arguments;
14
15
  private final Class<?>[] classes;
16
+ private final Class<?>[] boxedClasses;
15
17
  private final Class<?>[] classesWithCharseq;
16
18
 
17
19
  @SuppressWarnings("rawtypes")
18
20
  public InvocationOperation(String methodName, List arguments) {
19
21
  this.methodName = methodName;
20
22
  this.arguments = arguments;
21
- this.classes = extractArgumentTypes(false);
22
- this.classesWithCharseq = extractArgumentTypes(true);
23
+ this.classes = extractArgumentTypes(false, false);
24
+ this.boxedClasses = extractArgumentTypes(false, true);
25
+ this.classesWithCharseq = extractArgumentTypes(true, false);
23
26
  }
24
27
 
25
28
  @SuppressWarnings("rawtypes")
@@ -71,7 +74,27 @@ public class InvocationOperation implements Operation {
71
74
  return;
72
75
  }
73
76
  } catch (NoSuchMethodException ee) {
74
- System.out.println("Method not found with correct argument types. Trying to type convert.");
77
+ try {
78
+ Method method = o.getClass().getMethod(InvocationOperation.this.methodName, InvocationOperation.this.boxedClasses);
79
+ method.setAccessible(true);
80
+ try {
81
+ Object result;
82
+ if( method.getReturnType().equals(Void.TYPE)){
83
+ invokeMethod(o, method);
84
+ result = "<VOID>";
85
+ }
86
+ else {
87
+ result = invokeMethod(o, method);
88
+ }
89
+ ref.set(result);
90
+ return;
91
+ } catch (Exception eee) {
92
+ refEx.set(eee);
93
+ return;
94
+ }
95
+ } catch (NoSuchMethodException eee) {
96
+ System.out.println("Method not found with correct argument types. Trying to type convert.");
97
+ }
75
98
  }
76
99
  }
77
100
  //Warning: Slow path
@@ -100,7 +123,27 @@ public class InvocationOperation implements Operation {
100
123
  }
101
124
  }
102
125
  }
103
-
126
+
127
+ StringBuilder stringBuilder = new StringBuilder("No such method found: ");
128
+ stringBuilder.append(InvocationOperation.this.methodName);
129
+ stringBuilder.append("(");
130
+ int length = InvocationOperation.this.arguments.size();
131
+
132
+ for (int i = 0; i < length; i++) {
133
+ Object argument = InvocationOperation.this.arguments.get(i);
134
+
135
+ if (i != 0) {
136
+ stringBuilder.append(", ");
137
+ }
138
+
139
+ stringBuilder.append("[").append(argument.getClass().getSimpleName()).append("]");
140
+ }
141
+
142
+ stringBuilder.append(")");
143
+
144
+
145
+ ref.set(UIQueryResultVoid.instance
146
+ .asMap(InvocationOperation.this.methodName, o, stringBuilder.toString()));
104
147
  }
105
148
 
106
149
  });
@@ -112,7 +155,7 @@ public class InvocationOperation implements Operation {
112
155
  }
113
156
 
114
157
  @SuppressWarnings("rawtypes")
115
- private Class[] extractArgumentTypes(boolean convertStringCharSeq) {
158
+ private Class[] extractArgumentTypes(boolean convertStringCharSeq, boolean userWrapperClass) {
116
159
  Class[] types = new Class[arguments.size()];
117
160
  for (int i=0;i<arguments.size(); i++) {
118
161
  Object o = arguments.get(i);
@@ -120,10 +163,14 @@ public class InvocationOperation implements Operation {
120
163
  Class<?> c = o.getClass();
121
164
  if (convertStringCharSeq && c.equals(String.class)) {
122
165
  c = CharSequence.class;//Android API specific optimization
123
- }
124
- types[i] = mapToPrimitiveClass(c);
125
- }
126
- else {
166
+ }
167
+
168
+ if (userWrapperClass) {
169
+ types[i] = c;
170
+ } else {
171
+ types[i] = mapToPrimitiveClass(c);
172
+ }
173
+ } else {
127
174
  types[i] = null;
128
175
  }
129
176
  }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: calabash-android
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.2.pre1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonas Maturana Larsen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-14 00:00:00.000000000 Z
11
+ date: 2014-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cucumber
@@ -159,7 +159,10 @@ files:
159
159
  - lib/calabash-android/canned_steps.md
160
160
  - lib/calabash-android/color_helper.rb
161
161
  - lib/calabash-android/cucumber.rb
162
+ - lib/calabash-android/deprecated_actions.map
162
163
  - lib/calabash-android/env.rb
164
+ - lib/calabash-android/environment_helpers.rb
165
+ - lib/calabash-android/gestures.rb
163
166
  - lib/calabash-android/helpers.rb
164
167
  - lib/calabash-android/java_keystore.rb
165
168
  - lib/calabash-android/lib/AXMLPrinter2.jar
@@ -312,6 +315,7 @@ files:
312
315
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/Action.java
313
316
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/Actions.java
314
317
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/HttpServer.java
318
+ - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/MultiTouchGesture.java
315
319
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/NanoHTTPD.java
316
320
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/NullAction.java
317
321
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/ViewDump.java
@@ -348,15 +352,13 @@ files:
348
352
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/softkey/EnterKey.java
349
353
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/softkey/GoBack.java
350
354
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/softkey/LeftKey.java
355
+ - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/softkey/PressKey.java
351
356
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/softkey/PressMenu.java
352
357
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/softkey/RightKey.java
353
358
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/softkey/UpKey.java
354
359
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/HideSoftKeyboard.java
355
360
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/KeyboardEnterText.java
356
- - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/time/SetDateByContentDescription.java
357
- - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/time/SetDateByIndex.java
358
- - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/time/SetTimeByContentDescription.java
359
- - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/time/SetTimeByIndex.java
361
+ - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/PressUserActionButton.java
360
362
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/version/Version.java
361
363
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/GetActivityName.java
362
364
  - test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/IsCurrentActivityFocused.java
@@ -826,9 +828,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
826
828
  version: '0'
827
829
  required_rubygems_version: !ruby/object:Gem::Requirement
828
830
  requirements:
829
- - - '>='
831
+ - - '>'
830
832
  - !ruby/object:Gem::Version
831
- version: '0'
833
+ version: 1.3.1
832
834
  requirements: []
833
835
  rubyforge_project:
834
836
  rubygems_version: 2.1.10