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
@@ -11,58 +11,55 @@ import java.util.Map;
11
11
  import sh.calaba.instrumentationbackend.InstrumentationBackend;
12
12
  import sh.calaba.instrumentationbackend.actions.webview.CalabashChromeClient.WebFuture;
13
13
  import sh.calaba.org.codehaus.jackson.map.ObjectMapper;
14
+
15
+ import android.os.Build;
14
16
  import android.util.Log;
15
17
  import android.webkit.ValueCallback;
16
18
  import android.webkit.WebView;
17
19
 
18
20
  public class QueryHelper {
19
21
 
20
-
22
+
21
23
  @SuppressWarnings("unchecked")
22
24
  public static Map<String, Object> findFirstVisibleRectangle(List<HashMap<String,Object>> elements) {
23
- return (Map<String, Object>)findFirstVisibleElement(elements).get("rect");
25
+ return (Map<String, Object>)findFirstVisibleElement(elements).get("rect");
24
26
  }
25
-
27
+
26
28
  public static Map<String, Object> findFirstVisibleElement(List<HashMap<String,Object>> elements) {
27
29
  //TODO: Should do something more intelligent
28
- return (Map<String, Object>)elements.get(0);
30
+ return (Map<String, Object>)elements.get(0);
29
31
  }
30
-
32
+
31
33
  public static float translateCoordToScreen(int offset, float scale, Object point) {
32
34
  return offset + ((Number)point).floatValue() *scale;
33
35
  }
34
-
35
- public static Map<String, Object> translateRectToScreenCoordinates(WebView webView, Map<String, Object> rectangle) {
36
+
37
+ public static Map<String, Integer> translateRectToScreenCoordinates(WebView webView, Map<String, Integer> rectangle) {
36
38
  try {
37
-
38
39
  float scale = webView.getScale();
39
40
 
40
41
  int[] webviewLocation = new int[2];
41
42
  webView.getLocationOnScreen(webviewLocation);
42
43
  //center_x, center_y
43
44
  //left, top, width, height
44
- float center_x = translateCoordToScreen(webviewLocation[0], scale,
45
- rectangle.get("center_x"));
46
- float center_y = translateCoordToScreen(webviewLocation[1], scale,
47
- rectangle.get("center_y"));
48
-
49
- float x = translateCoordToScreen(webviewLocation[0], scale, rectangle.get("left"));
50
- float y = translateCoordToScreen(webviewLocation[0], scale, rectangle.get("top"));
51
- Map<String,Object> result = new HashMap<String, Object>(rectangle);
52
-
53
- result.put("x",x);
54
- result.put("y",y);
55
- result.put("center_x",center_x);
56
- result.put("center_y",center_y);
57
-
45
+ int center_x = (int)translateCoordToScreen(webviewLocation[0], scale, rectangle.get("center_x"));
46
+ int center_y = (int)translateCoordToScreen(webviewLocation[1], scale, rectangle.get("center_y"));
47
+
48
+ int x = (int)translateCoordToScreen(webviewLocation[0], scale, rectangle.get("left"));
49
+ int y = (int)translateCoordToScreen(webviewLocation[0], scale, rectangle.get("top"));
50
+ Map<String,Integer> result = new HashMap<String, Integer>(rectangle);
51
+
52
+ result.put("x", x);
53
+ result.put("y", y);
54
+ result.put("center_x", center_x);
55
+ result.put("center_y", center_y);
56
+
58
57
  return result;
59
-
60
-
61
58
  } catch (Exception e) {
62
59
  throw new RuntimeException(e);
63
60
  }
64
61
  }
65
-
62
+
66
63
  public static String toJsonString(Object o) {
67
64
  //http://www.mkyong.com/java/how-to-convert-java-map-to-from-json-jackson/
68
65
  try {
@@ -71,7 +68,7 @@ public class QueryHelper {
71
68
  throw new RuntimeException(e);
72
69
  }
73
70
  }
74
-
71
+
75
72
 
76
73
  private static String readJavascriptFromAsset(String scriptPath) {
77
74
  StringBuffer script = new StringBuffer();
@@ -88,7 +85,7 @@ public class QueryHelper {
88
85
  }
89
86
  return script.toString();
90
87
  }
91
-
88
+
92
89
  public static WebFuture executeAsyncJavascriptInWebviews(WebView webView,
93
90
  String scriptPath, String selector, String type) {
94
91
 
@@ -99,12 +96,12 @@ public class QueryHelper {
99
96
 
100
97
  CalabashChromeClient chromeClient = CalabashChromeClient.prepareWebView(webView);
101
98
 
102
- if (android.os.Build.VERSION.SDK_INT < 19) { // Android 4.4
103
- webView.loadUrl("javascript:calabash_result = " + script + ";prompt('calabash:' + calabash_result);");
99
+ if (Build.VERSION.SDK_INT < 19) { // Android 4.4
100
+ JavaScriptExecuter javaScriptExecuter = new JavaScriptExecuter(webView);
101
+ javaScriptExecuter.executeJavaScript("calabash_result = " + script + ";prompt('calabash:' + calabash_result);");
104
102
  } else {
105
103
  chromeClient.evaluateCalabashScript(script);
106
104
  }
107
-
108
105
  return chromeClient.getResult();
109
106
  }
110
107
  }
@@ -15,17 +15,18 @@ import android.widget.TextView;
15
15
  public class ViewMapper {
16
16
 
17
17
  @SuppressWarnings({ "rawtypes", "unchecked" })
18
- public static Object extractDataFromView(View v) {
19
-
18
+ public static Object extractDataFromView(View v) {
19
+
20
20
  Map data = new HashMap();
21
- data.put("class", getClassNameForView(v));
21
+ data.put("class", getClassNameForView(v));
22
22
  data.put("description", v.toString());
23
23
  data.put("contentDescription", getContentDescriptionForView(v));
24
24
  data.put("enabled", v.isEnabled());
25
-
25
+
26
26
  data.put("id", getIdForView(v));
27
+ data.put("tag", getTagForView(v));
27
28
 
28
- Map rect = getRectForView(v);
29
+ Map<String,Integer> rect = getRectForView(v);
29
30
 
30
31
  data.put("rect", rect);
31
32
 
@@ -45,19 +46,20 @@ public class ViewMapper {
45
46
 
46
47
  }
47
48
 
48
- public static Map getRectForView(View v) {
49
- Map rect = new HashMap();
49
+ public static Map<String, Integer> getRectForView(View v) {
50
+ Map<String,Integer> rect = new HashMap<String,Integer>();
50
51
  int[] location = new int[2];
51
52
  v.getLocationOnScreen(location);
52
53
 
53
54
  rect.put("x", location[0]);
54
55
  rect.put("y", location[1]);
55
-
56
- rect.put("center_x", location[0] + v.getWidth()/2.0);
57
- rect.put("center_y", location[1] + v.getHeight()/2.0);
58
-
56
+
57
+ rect.put("center_x", (int)(location[0] + v.getWidth()/2.0));
58
+ rect.put("center_y", (int)(location[1] + v.getHeight()/2.0));
59
+
59
60
  rect.put("width", v.getWidth());
60
61
  rect.put("height", v.getHeight());
62
+
61
63
  return rect;
62
64
  }
63
65
 
@@ -82,26 +84,33 @@ public class ViewMapper {
82
84
  return id;
83
85
  }
84
86
 
87
+ public static String getTagForView(View v) {
88
+ if (v.getTag() instanceof String || v.getTag() instanceof Integer) {
89
+ return v.getTag().toString();
90
+ }
91
+ return null;
92
+ }
93
+
85
94
  @SuppressWarnings({ "unchecked", "rawtypes" })
86
95
  public static Object mapView(Object o) {
87
96
  if (o instanceof View) {
88
97
  return extractDataFromView((View) o);
89
- }
90
- else if (o instanceof Map) {
91
- Map copy = new HashMap();
98
+ }
99
+ else if (o instanceof Map) {
100
+ Map copy = new HashMap();
92
101
  for (Object e : ((Map) o).entrySet()) {
93
102
  Map.Entry entry = (Entry) e;
94
103
  Object value = entry.getValue();
95
104
  if (value instanceof View) {
96
105
  copy.put(entry.getKey(), UIQueryUtils.getId((View) value));
97
- }
106
+ }
98
107
  else {
99
108
  copy.put(entry.getKey(),entry.getValue());
100
- }
109
+ }
101
110
  }
102
-
111
+
103
112
  return copy;
104
- }
113
+ }
105
114
  else if (o instanceof CharSequence) {
106
115
  return o.toString();
107
116
  }
@@ -25,7 +25,13 @@ public enum ComparisonOperator implements UIQueryASTPredicateRelation {
25
25
  if (firstValue == secondValue) {
26
26
  return true;
27
27
  }
28
- return (firstValue != null) && firstValue.equals(secondValue);
28
+ return (firstValue != null) && firstValue.equals(secondValue);
29
+ }
30
+ },
31
+
32
+ NOTEQUAL {
33
+ public boolean areRelated(Object firstValue, Object secondValue) {
34
+ return !EQUAL.areRelated(firstValue, secondValue);
29
35
  }
30
36
  },
31
37
 
@@ -80,6 +80,16 @@ public class UIQueryASTPredicate implements UIQueryAST {
80
80
  }
81
81
  }
82
82
 
83
+ // there's no tag property for non Views, handle them all here
84
+ if (this.propertyName.equals("tag")) {
85
+ String tag = (o instanceof View ? UIQueryUtils.getTag((View) o) : null);
86
+ if (this.relation.areRelated(tag, this.valueToMatch)) {
87
+ return o;
88
+ } else {
89
+ return null;
90
+ }
91
+ }
92
+
83
93
  Method propertyAccessor = UIQueryUtils
84
94
  .hasProperty(o, this.propertyName);
85
95
  if (propertyAccessor == null) {
@@ -90,8 +100,8 @@ public class UIQueryASTPredicate implements UIQueryAST {
90
100
  if (this.relation.areRelated(value, this.valueToMatch)) {
91
101
  return o;
92
102
  } else if (this.valueToMatch instanceof String
93
- && this.relation
94
- .areRelated(value.toString(), this.valueToMatch)) {
103
+ && value != null
104
+ && this.relation.areRelated(value.toString(), this.valueToMatch)) {
95
105
  return o;
96
106
  } else {
97
107
  return null;
@@ -109,7 +119,7 @@ public class UIQueryASTPredicate implements UIQueryAST {
109
119
  return new UIQueryASTPredicate(prop.getText(),
110
120
  UIQueryASTPredicate.parseRelation(rel),
111
121
  UIQueryUtils.parseValue(val));
112
-
122
+
113
123
  }
114
124
 
115
125
  private static UIQueryASTPredicateRelation parseRelation(CommonTree rel) {
@@ -120,7 +130,7 @@ public class UIQueryASTPredicate implements UIQueryAST {
120
130
  caseSensitive = false;
121
131
  relText = relText.substring(0,relText.length() - CASE_INSENSITIVE_SPEC.length());
122
132
  }
123
-
133
+
124
134
  if ("BEGINSWITH".equals(relText)) {
125
135
  return new BeginsWithRelation(caseSensitive);
126
136
  } else if ("ENDSWITH".equals(relText)) {
@@ -139,6 +149,8 @@ public class UIQueryASTPredicate implements UIQueryAST {
139
149
  return ComparisonOperator.GREATERTHAN;
140
150
  } else if (">=".equals(relText)) {
141
151
  return ComparisonOperator.GREATERTHANOREQUAL;
152
+ } else if ("!=".equals(relText) || "<>".equals(relText)) {
153
+ return ComparisonOperator.NOTEQUAL;
142
154
  } else {
143
155
  throw new IllegalStateException("Unsupported Relation: " + relText);
144
156
  }
@@ -63,13 +63,13 @@ public class UIQueryASTWith implements UIQueryAST {
63
63
  }
64
64
 
65
65
  }
66
- List visibilityFilteredResults = visibility.evaluateWithViews(futureResult, direction,
67
- visibility);
68
- return new PartialFutureList(visibilityFilteredResults);
66
+
67
+ return new PartialFutureList(futureResult);
69
68
  }
70
69
  });
71
70
 
72
- List processedResult = new ArrayList(queryResult.size());
71
+ final List processedResult = new ArrayList(queryResult.size());
72
+
73
73
  for (Object o : queryResult) {
74
74
  if (o instanceof Map) {
75
75
  Map m = (Map) o;
@@ -85,9 +85,16 @@ public class UIQueryASTWith implements UIQueryAST {
85
85
  processedResult.add(o);
86
86
  }
87
87
  }
88
- return processedResult;
89
-
90
88
 
89
+ List visibilityFilteredResults = (List) UIQueryUtils.evaluateSyncInMainThread(new Callable() {
90
+
91
+ @Override
92
+ public Object call() throws Exception {
93
+ return visibility.evaluateWithViews(processedResult, direction, visibility);
94
+ }
95
+ });
96
+
97
+ return visibilityFilteredResults;
91
98
  }
92
99
 
93
100
  private boolean isDomQuery() {
@@ -30,6 +30,7 @@ import sh.calaba.org.codehaus.jackson.type.TypeReference;
30
30
  import android.text.InputType;
31
31
  import android.util.Log;
32
32
  import android.view.View;
33
+ import android.view.ViewParent;
33
34
  import android.webkit.WebView;
34
35
  import android.widget.Button;
35
36
  import android.widget.CheckBox;
@@ -47,7 +48,7 @@ public class UIQueryUtils {
47
48
 
48
49
  @SuppressWarnings({ "unchecked", "rawtypes" })
49
50
  public static List subviews(Object o) {
50
-
51
+
51
52
  try {
52
53
  Method getChild = o.getClass().getMethod("getChildAt", int.class);
53
54
  getChild.setAccessible(true);
@@ -74,15 +75,15 @@ public class UIQueryUtils {
74
75
 
75
76
  @SuppressWarnings({ "rawtypes" })
76
77
  public static Future webViewSubViews(WebView o) {
77
-
78
+
78
79
  Log.i("Calabash", "About to webViewSubViews");
79
-
80
+
80
81
 
81
82
  WebFuture controls = QueryHelper.executeAsyncJavascriptInWebviews(o,
82
83
  "calabash.js", "input,button","css");
83
-
84
+
84
85
  return controls;
85
-
86
+
86
87
  }
87
88
 
88
89
  @SuppressWarnings({ "unchecked", "rawtypes" })
@@ -168,18 +169,44 @@ public class UIQueryUtils {
168
169
  }
169
170
 
170
171
  public static boolean isVisible(Object v) {
171
- if (!(v instanceof View)) {
172
- return true;
173
- }
174
- View view = (View) v;
172
+ if (v instanceof Map) {
173
+ Map map = (Map)v;
174
+ Map<String,Integer> viewRect = (Map<String,Integer>)map.get("rect");
175
+ Map<String,Integer> parentViewRec = ViewMapper.getRectForView((WebView)map.get("webView"));
175
176
 
176
- if (view.getHeight() == 0 || view.getWidth() == 0) {
177
- return false;
178
- }
177
+ return isViewSufficientlyShown(viewRect, parentViewRec);
178
+ } else if (v instanceof View) {
179
+ View view = (View) v;
179
180
 
180
- return view.isShown() && viewFetcher.isViewSufficientlyShown(view);
181
+ if (view.getHeight() == 0 || view.getWidth() == 0) {
182
+ return false;
183
+ }
184
+
185
+ return view.isShown() && isViewSufficientlyShown(view);
186
+ } else {
187
+ return true;
188
+ }
181
189
  }
182
190
 
191
+ public static boolean isViewSufficientlyShown(Map<String,Integer> viewRect, Map<String,Integer> parentViewRect) {
192
+ int centerX = viewRect.get("center_x");
193
+ int centerY = viewRect.get("center_y");
194
+
195
+ int parentX = parentViewRect.get("x");
196
+ int parentY = parentViewRect.get("y");
197
+ int parentWidth = parentViewRect.get("width");
198
+ int parentHeight = parentViewRect.get("height");
199
+ int windowWidth = parentX + parentWidth;
200
+ int windowHeight = parentY + parentHeight;
201
+
202
+ return (windowWidth > centerX && parentX < centerX &&
203
+ windowHeight > centerY && parentY < centerY);
204
+ }
205
+
206
+ public static boolean isViewSufficientlyShown(View view) {
207
+ return isViewSufficientlyShown(view, view.getParent());
208
+ }
209
+
183
210
  public static boolean isClickable(Object v) {
184
211
  if (!(v instanceof View)) {
185
212
  return true;
@@ -193,6 +220,10 @@ public class UIQueryUtils {
193
220
  return ViewMapper.getIdForView(view);
194
221
  }
195
222
 
223
+ public static String getTag(View view) {
224
+ return ViewMapper.getTagForView(view);
225
+ }
226
+
196
227
  @SuppressWarnings({ "rawtypes", "unchecked" })
197
228
  public static Future evaluateAsyncInMainThread(final Callable callable) throws Exception {
198
229
 
@@ -246,8 +277,8 @@ public class UIQueryUtils {
246
277
  new TypeReference<List<HashMap<String, Object>>>() {
247
278
  });
248
279
  for (Map<String, Object> data : parsedResult) {
249
- Map<String, Object> rect = (Map<String, Object>) data.get("rect");
250
- Map<String, Object> updatedRect = QueryHelper.translateRectToScreenCoordinates(webView, rect);
280
+ Map<String, Integer> rect = (Map<String, Integer>) data.get("rect");
281
+ Map<String, Integer> updatedRect = QueryHelper.translateRectToScreenCoordinates(webView, rect);
251
282
  data.put("rect", updatedRect);
252
283
  data.put("webView", webView);
253
284
  }
@@ -301,7 +332,7 @@ public class UIQueryUtils {
301
332
  }
302
333
 
303
334
  /*
304
- *
335
+ *
305
336
  * {"rect"=>{"x"=>0, "y"=>0, "width"=>768, "height"=>1024},
306
337
  * "hit-point"=>{"x"=>384, "y"=>512}, "id"=>"", "action"=>false,
307
338
  * "enabled"=>1, "visible"=>1, "value"=>nil, "type"=>"[object UIAWindow]",
@@ -343,7 +374,7 @@ public class UIQueryUtils {
343
374
  childrenArray.add(dumpRecursively(serializedChild,
344
375
  childrenList));
345
376
  }
346
-
377
+
347
378
  }
348
379
 
349
380
  parentView.put("children", childrenArray);
@@ -373,7 +404,7 @@ public class UIQueryUtils {
373
404
  }
374
405
 
375
406
  /*
376
- *
407
+ *
377
408
  "enabled" => true,
378
409
  "visible" => true,
379
410
  "children" => [],
@@ -412,16 +443,16 @@ public class UIQueryUtils {
412
443
  if (viewOrMap == null) {
413
444
  return null;
414
445
  }
415
-
416
- if (viewOrMap instanceof Map)
446
+
447
+ if (viewOrMap instanceof Map)
417
448
  {
418
- Map map = (Map) viewOrMap;
449
+ Map map = (Map) viewOrMap;
419
450
  map.put("el", map);
420
451
 
421
452
  Map rect = (Map) map.get("rect");
422
453
  Map hitPoint = extractHitPointFromRect(rect);
423
-
424
- map.put("hit-point", hitPoint);
454
+
455
+ map.put("hit-point", hitPoint);
425
456
  map.put("enabled", true);
426
457
  map.put("visible", true);
427
458
  map.put("value", null);
@@ -430,36 +461,36 @@ public class UIQueryUtils {
430
461
  map.put("label", null);
431
462
  map.put("children", Collections.EMPTY_LIST);
432
463
  String html = (String)map.get("html");
433
- String nodeName = (String) map.get("nodeName");
434
- if (nodeName != null && nodeName.toLowerCase().equals("input")) {
464
+ String nodeName = (String) map.get("nodeName");
465
+ if (nodeName != null && nodeName.toLowerCase().equals("input")) {
435
466
  String domType = extractDomType(html);
436
467
  if (isDomPasswordType(domType)) {
437
468
  map.put("entry_types", Collections.singletonList("password"));
438
469
  }
439
470
  else if (isDomTextType(domType)) {
440
471
  map.put("entry_types", Collections.singletonList("text"));
441
- }
472
+ }
442
473
  else {
443
- map.put("entry_types", Collections.emptyList());
444
- }
474
+ map.put("entry_types", Collections.emptyList());
475
+ }
445
476
  map.put("value", extractAttribute(html, "value"));
446
477
  map.put("type", "dom");
447
478
  map.put("name", extractAttribute(html, "name"));
448
479
  map.put("label", extractAttribute(html, "title"));
449
- }
450
-
451
- return map;
452
-
480
+ }
481
+
482
+ return map;
483
+
453
484
  }
454
- else
485
+ else
455
486
  {
456
487
  Map m = new HashMap();
457
-
488
+
458
489
  View view = (View) viewOrMap;
459
490
  m.put("id", getId(view));
460
491
  m.put("el", view);
461
492
 
462
- Map rect = ViewMapper.getRectForView(view);
493
+ Map<String,Integer> rect = ViewMapper.getRectForView(view);
463
494
  Map hitPoint = extractHitPointFromRect(rect);
464
495
 
465
496
  m.put("rect", rect);
@@ -472,14 +503,29 @@ public class UIQueryUtils {
472
503
  m.put("type", ViewMapper.getClassNameForView(view));
473
504
  m.put("name", getNameForView(view));
474
505
  m.put("label", ViewMapper.getContentDescriptionForView(view));
475
- return m;
506
+ return m;
476
507
  }
477
508
 
478
-
479
509
 
480
-
510
+
511
+
481
512
  }
482
513
 
514
+ private static boolean isViewSufficientlyShown(View view, ViewParent viewParent) {
515
+ if (!(viewParent instanceof View)) return true;
516
+
517
+ View parent = (View)viewParent;
518
+
519
+ if (view.equals(parent) || parent == null) {
520
+ return true;
521
+ }
522
+
523
+ Map<String,Integer> viewRect = ViewMapper.getRectForView(view);
524
+ Map<String,Integer> parentRect = ViewMapper.getRectForView(parent);
525
+
526
+ return isViewSufficientlyShown(viewRect, parentRect) && isViewSufficientlyShown(view, parent.getParent());
527
+ }
528
+
483
529
  private static boolean isDomTextType(String domType) {
484
530
  if (domType == null) {
485
531
  return true;
@@ -487,25 +533,25 @@ public class UIQueryUtils {
487
533
  return DOM_TEXT_TYPES.contains(domType);
488
534
  }
489
535
 
490
- private static boolean isDomPasswordType(String domType) {
536
+ private static boolean isDomPasswordType(String domType) {
491
537
  return "password".equalsIgnoreCase(domType);
492
538
  }
493
539
 
494
540
  // naive implementation only works for (valid) input tags
495
541
  public static String extractDomType(String input) {
496
- return extractAttribute(input, "type");
542
+ return extractAttribute(input, "type");
497
543
  }
498
-
544
+
499
545
  public static String extractAttribute(String input, String attribute) {
500
546
  String[] split = input.split(attribute+"=");
501
547
  if (split.length == 1) {
502
- split = input.split(attribute+" =");
548
+ split = input.split(attribute+" =");
503
549
  }
504
550
  if (split.length > 1) {
505
551
  String lastPart = split[1];
506
552
  if (lastPart == null) {
507
- return null;
508
- }
553
+ return null;
554
+ }
509
555
  if (lastPart.charAt(0) == '"' || lastPart.charAt(0) == '\'') {
510
556
  int endIndex = -1;
511
557
  for (int i=1;i<lastPart.length();i++) {
@@ -514,15 +560,15 @@ public class UIQueryUtils {
514
560
  break;
515
561
  }
516
562
  }
517
-
563
+
518
564
  if (endIndex > 0) {
519
565
  return lastPart.substring(1,endIndex);
520
566
  }
521
-
522
- }
567
+
568
+ }
523
569
  }
524
570
  return null;
525
-
571
+
526
572
  }
527
573
 
528
574