calabash-android 0.5.1 → 0.5.2.pre1

Sign up to get free protection for your applications and to get access to all the features.
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