calabash-android 0.2.11 → 0.2.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/CHANGES.txt +6 -0
  2. data/features-skeleton/support/app_installation_hooks.rb +11 -3
  3. data/features-skeleton/support/app_life_cycle_hooks.rb +9 -0
  4. data/features-skeleton/support/hooks.rb +18 -2
  5. data/lib/calabash-android/operations.rb +1 -1
  6. data/lib/calabash-android/steps/assert_steps.rb +12 -0
  7. data/lib/calabash-android/steps/list_steps.rb +40 -0
  8. data/lib/calabash-android/steps/map_steps.rb +61 -0
  9. data/lib/calabash-android/steps/navigation_steps.rb +10 -1
  10. data/lib/calabash-android/steps/progress_steps.rb +5 -0
  11. data/lib/calabash-android/version.rb +2 -2
  12. data/test-server/AndroidManifest.xml +5 -5
  13. data/test-server/build.xml +4 -0
  14. data/test-server/instrumentation-backend/.gitignore +1 -0
  15. data/test-server/instrumentation-backend/AndroidManifest.xml +4 -3
  16. data/test-server/instrumentation-backend/project.properties +1 -1
  17. data/test-server/instrumentation-backend/src/com/jayway/android/robotium/solo/MapViewUtils.java +328 -0
  18. data/test-server/instrumentation-backend/src/com/jayway/android/robotium/solo/SoloEnhanced.java +97 -0
  19. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/InstrumentationBackend.java +3 -3
  20. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/TestHelpers.java +51 -1
  21. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/GetListItemProperties.java +195 -0
  22. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/GetListItemText.java +136 -0
  23. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/GetMapBounds.java +27 -0
  24. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/GetMapCenter.java +27 -0
  25. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/GetMapMarker.java +31 -0
  26. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/GetMapMarkers.java +48 -0
  27. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/GetMapZoom.java +19 -0
  28. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/PanMapTo.java +23 -0
  29. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/SetMapCenter.java +23 -0
  30. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/SetMapZoom.java +34 -0
  31. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/TapAwayFromMarkers.java +28 -0
  32. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/TapMapMarker.java +29 -0
  33. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/spinner/GetSelectedSpinnerItemText.java +36 -0
  34. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/AssertGridViewContainsNoDuplicates.java +72 -0
  35. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/GetTextById.java +42 -0
  36. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/AssertViewProperty.java +141 -0
  37. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/ClickOnViewById.java +1 -8
  38. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/GetActivityName.java +32 -0
  39. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/GetViewProperty.java +107 -0
  40. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/HasView.java +31 -0
  41. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/Press.java +1 -1
  42. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/SelectTab.java +110 -0
  43. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForScreen.java +10 -6
  44. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForTab.java +108 -0
  45. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/{view → wait}/WaitForView.java +1 -1
  46. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/{view → wait}/WaitForViewById.java +21 -11
  47. data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/QueryHelper.java +3 -3
  48. metadata +102 -88
@@ -0,0 +1,97 @@
1
+ package com.jayway.android.robotium.solo;
2
+
3
+ import java.util.List;
4
+
5
+ import android.app.Activity;
6
+ import android.app.Instrumentation;
7
+
8
+ public class SoloEnhanced extends Solo {
9
+ // private Pincher pincher;
10
+ private MapViewUtils mapViewUtils;
11
+
12
+ public SoloEnhanced(Instrumentation instrumentation, Activity activity) {
13
+ super(instrumentation, activity);
14
+ this.mapViewUtils = new MapViewUtils(instrumentation, viewFetcher, sleeper, waiter);
15
+ // this.pincher = new Pincher(instrumentation, viewFetcher);
16
+ }
17
+
18
+ public void setMapCenter( double lat, double lon ) {
19
+ mapViewUtils.setCenter(lat, lon);
20
+ }
21
+
22
+ /** @return {lat,lon} */
23
+ public double[] getMapCenter() {
24
+ return mapViewUtils.getMapCenter();
25
+ }
26
+
27
+ public void panMapTo( double lat, double lon ) {
28
+ mapViewUtils.panTo(lat, lon);
29
+ }
30
+
31
+ public boolean zoomInOnMap() {
32
+ return mapViewUtils.zoomIn();
33
+ }
34
+
35
+ public boolean zoomOutOnMap() {
36
+ return mapViewUtils.zoomOut();
37
+ }
38
+
39
+ public int setMapZoom( int zoomLevel ) {
40
+ return mapViewUtils.setZoom(zoomLevel);
41
+ }
42
+
43
+ public int getMapZoom() {
44
+ return mapViewUtils.getZoom();
45
+ }
46
+
47
+ public List<String> getMapMarkerItems() {
48
+ return mapViewUtils.getMarkerItems();
49
+ }
50
+
51
+ public String getMapMarkerItem( String title ) {
52
+ return mapViewUtils.getMarkerItem( title );
53
+ }
54
+
55
+ /**
56
+ * @param title
57
+ * @param timeout in ms
58
+ * @return
59
+ */
60
+ public boolean tapMapMarkerItem( String title, long timeout ) {
61
+ return mapViewUtils.tapMarkerItem( title, timeout );
62
+ }
63
+
64
+ public boolean tapMapAwayFromMarkers( int step ) {
65
+ return mapViewUtils.tapAwayFromMarkerItems( step );
66
+ }
67
+
68
+ /**
69
+ * @return [top, right, bottom, left] in decimal degrees
70
+ */
71
+ public List<String> getMapBounds() {
72
+ return mapViewUtils.getBounds();
73
+ }
74
+
75
+ // /**
76
+ // * Sorry, doesn't work yet
77
+ // * @param togetherOrApart - {@link Pincher#TOGETHER} or {@link Pincher#APART}
78
+ // */
79
+ // public void pinch(int togetherOrApart) {
80
+ // switch( togetherOrApart ) {
81
+ // case Pincher.TOGETHER: pincher.pinch(Pincher.Direction.TOGETHER); break;
82
+ // case Pincher.APART: pincher.pinch(Pincher.Direction.APART); break;
83
+ // }
84
+ // }
85
+ //
86
+ // /**
87
+ // * Sorry, doesn't work yet
88
+ // * @param togetherOrApart - {@link Pincher#TOGETHER} or {@link Pincher#APART}
89
+ // * @param view
90
+ // */
91
+ // public void pinch(int togetherOrApart, View view) {
92
+ // switch( togetherOrApart ) {
93
+ // case Pincher.TOGETHER: pincher.pinch(Pincher.Direction.TOGETHER, view); break;
94
+ // case Pincher.APART: pincher.pinch(Pincher.Direction.APART, view); break;
95
+ // }
96
+ // }
97
+ }
@@ -6,7 +6,7 @@ import android.app.Instrumentation;
6
6
  import android.test.ActivityInstrumentationTestCase2;
7
7
  import android.util.Log;
8
8
 
9
- import com.jayway.android.robotium.solo.Solo;
9
+ import com.jayway.android.robotium.solo.SoloEnhanced;
10
10
 
11
11
  public class InstrumentationBackend extends ActivityInstrumentationTestCase2 {
12
12
  public static final String TARGET_PACKAGE = "#ACTIVITY_PACKAGE#"; //Set from Ant at compile time
@@ -15,7 +15,7 @@ public class InstrumentationBackend extends ActivityInstrumentationTestCase2 {
15
15
  private static final String TAG = "InstrumentationBackend";
16
16
 
17
17
  public static Instrumentation instrumentation;
18
- public static Solo solo;
18
+ public static SoloEnhanced solo;
19
19
  public static Actions actions;
20
20
 
21
21
  private static Class getActivityClass() {
@@ -34,7 +34,7 @@ public class InstrumentationBackend extends ActivityInstrumentationTestCase2 {
34
34
  protected void setUp() throws Exception {
35
35
  super.setUp();
36
36
 
37
- solo = new Solo(getInstrumentation(), this.getActivity());
37
+ solo = new SoloEnhanced(getInstrumentation(), this.getActivity());
38
38
  actions = new Actions(getInstrumentation(), this);
39
39
  instrumentation = getInstrumentation();
40
40
  TestHelpers.loadIds(instrumentation.getContext());
@@ -12,6 +12,8 @@ import java.util.HashMap;
12
12
  import java.util.Map;
13
13
 
14
14
  import android.content.Context;
15
+ import android.content.res.Resources.NotFoundException;
16
+ import android.graphics.drawable.Drawable;
15
17
  import android.view.View;
16
18
  import android.widget.TextView;
17
19
 
@@ -69,6 +71,21 @@ public class TestHelpers {
69
71
  return null;
70
72
  }
71
73
 
74
+ @SuppressWarnings("unchecked")
75
+ public static <ViewType extends View> ViewType getViewById(String resName, Class<? extends View> expectedViewType) {
76
+ final View theView = getViewById(resName);
77
+
78
+ if (null == theView) {
79
+ return null;
80
+ }
81
+
82
+ if (!expectedViewType.isInstance(theView)) {
83
+ throw new RuntimeException(String.format("getViewById: Expected to find a View of type %s but found one of type %s", expectedViewType.getClass().getName(), theView.getClass().getName()));
84
+ }
85
+
86
+ return (ViewType) theView;
87
+ }
88
+
72
89
  public static View getViewById(String resName) {
73
90
  Integer intID = resourceNamesToIds.get(resName);
74
91
  System.out.println("getViewById: Looking for view " + resName + " as id " + intID);
@@ -76,7 +93,7 @@ public class TestHelpers {
76
93
  throw new RuntimeException("getViewById: Looking for view " + resName + " which does not have an id");
77
94
  }
78
95
  int id = intID.intValue();
79
- View view = InstrumentationBackend.solo.getCurrentActivity().findViewById(id);
96
+ View view = InstrumentationBackend.solo.getView(id);
80
97
  if (view != null) {
81
98
  if (id == view.getId()) {
82
99
  System.out.println("Did find view " + resName + ".");
@@ -87,6 +104,39 @@ public class TestHelpers {
87
104
  System.out.println("Did not find view " + resName);
88
105
  return view;
89
106
  }
107
+
108
+ public static Drawable getDrawableById(String resName) {
109
+ int id;
110
+ // This would probably work too...
111
+ if( true ) {
112
+ try {
113
+ // if( resName.startsWith("drawable/") == false ) {
114
+ // resName = "drawable/" + resName;
115
+ // }
116
+ // TypedValue outValue = new TypedValue();
117
+ // InstrumentationBackend.solo.getCurrentActivity().getResources().getValue( resName, outValue, false );
118
+ // id = outValue.resourceId;
119
+ id = InstrumentationBackend.solo.getCurrentActivity().getResources().getIdentifier( resName, "drawable", InstrumentationBackend.solo.getCurrentActivity().getPackageName() );
120
+ } catch( NotFoundException e ) {
121
+ throw new RuntimeException("getDrawableById: Looking for drawable " + resName + " but was not found");
122
+ }
123
+ } else {
124
+ Integer intID = resourceNamesToIds.get(resName);
125
+ System.out.println("getDrawableById: Looking for drawable " + resName + " as id " + intID);
126
+ if (intID == null) {
127
+ throw new RuntimeException("getDrawableById: Looking for drawable " + resName + " which does not have an id");
128
+ }
129
+ id = intID.intValue();
130
+ }
131
+ Drawable drawable = InstrumentationBackend.solo.getCurrentActivity().getResources().getDrawable(id);
132
+ if (drawable != null) {
133
+ System.out.println("Did find drawable " + resName + ": " + drawable);
134
+ return drawable;
135
+ } else {
136
+ System.out.println("Did not find drawable " + resName);
137
+ return drawable;
138
+ }
139
+ }
90
140
 
91
141
  public static int[] parseTime(String timeString) {
92
142
  String[] splitTimeString = timeString.split(":");
@@ -0,0 +1,195 @@
1
+ package sh.calaba.instrumentationbackend.actions.list;
2
+
3
+ import java.lang.reflect.Method;
4
+ import java.util.ArrayList;
5
+
6
+ import sh.calaba.instrumentationbackend.InstrumentationBackend;
7
+ import sh.calaba.instrumentationbackend.Result;
8
+ import sh.calaba.instrumentationbackend.actions.Action;
9
+ import android.graphics.drawable.ColorDrawable;
10
+ import android.graphics.drawable.Drawable;
11
+ import android.view.View;
12
+ import android.view.ViewGroup;
13
+ import android.widget.ListView;
14
+ import android.widget.TableRow;
15
+ import android.widget.TextView;
16
+
17
+ /**
18
+ * args:
19
+ * <ul>
20
+ * <li>1-based list index (first list is used if not specified)</li>
21
+ * <li>1-based row index (returns all rows if &lt;=0 or not specified)</li>
22
+ * </ul>
23
+ *
24
+ * eg: (all items of 1st list) <code>performAction( 'get_list_item_properties' )</code>
25
+ * eg: (all items of 2nd list) <code>performAction( 'get_list_item_properties', '2' )</code>
26
+ * eg: (1st item of 2nd list) <code>performAction( 'get_list_item_properties', '2' , '1' )</code>
27
+ *
28
+ * @return <code>bonusInformation</code> contain an array of Strings, one for each row in the list (or only for the specified row):
29
+ * eg: {[{"id":"title", "text":"My Title", "compoundDrawables":["left"]}, {"id":"subtitle", "text":"Another text field for the same list item"}]}
30
+ *
31
+ *
32
+ * In ruby, we can then parse the response:
33
+ * <pre>
34
+ * response_table = result['bonusInformation']
35
+ * response_table.each_with_index do | row_data, index |
36
+ * row_data = JSON.parse( row_data )
37
+ * response_table[index] = row_data
38
+ * end
39
+ * </pre>
40
+ *
41
+ * @author Nicholas Albion
42
+ */
43
+ public class GetListItemProperties implements Action {
44
+
45
+ @Override
46
+ public Result execute(String... args) {
47
+ int listIndex;
48
+ int rowIndex = -1;
49
+
50
+ if( args.length == 0 ) {
51
+ listIndex = 0;
52
+ } else {
53
+ if( args.length > 1 ) {
54
+ rowIndex = (Integer.parseInt(args[1]) - 1);
55
+ }
56
+ listIndex = (Integer.parseInt(args[0]) - 1);
57
+ }
58
+
59
+
60
+ ArrayList<ListView> listViews = InstrumentationBackend.solo.getCurrentListViews();
61
+ if( listViews == null || listViews.size() <= listIndex ) {
62
+ return new Result(false, "Could not find list #" + (listIndex + 1));
63
+ }
64
+
65
+ ListView list = listViews.get(listIndex);
66
+ Result result = new Result(true);
67
+
68
+ if( rowIndex < 0 ) {
69
+ int count = list.getChildCount();
70
+ for( int i = 0; i < count; i++ ) {
71
+ result.addBonusInformation( getListItemString( list.getChildAt(i) ) );
72
+ }
73
+ } else {
74
+ result.addBonusInformation( getListItemString( list.getChildAt(rowIndex) ) );
75
+ }
76
+
77
+ return result;
78
+ }
79
+
80
+ /**
81
+ * @return <code>bonusInformation</code> contain an array of Strings, one for each row in the list (or only for the specified row):
82
+ * eg: {[{"id":"title", "text":"My Title", "compoundDrawables":{"left":"drawable_id"}}, {"id":"subtitle", "text":"Another text field for the same list item"}]}
83
+ */
84
+ private String getListItemString( View row ) {
85
+ StringBuilder json = new StringBuilder("{");
86
+
87
+ if( row instanceof TextView ) {
88
+ addViewInfo( json, (TextView)row );
89
+ } else if( row instanceof ViewGroup ) {
90
+ addViewInfo( json, (ViewGroup)row );
91
+ }
92
+
93
+ json.deleteCharAt( json.length() - 1 ); // remove the last comma
94
+ json.append('}');
95
+ return json.toString();
96
+ }
97
+
98
+ private void addViewInfo( StringBuilder json, TextView view ) {
99
+ int resId = view.getId();
100
+ String resIdName = view.getResources().getResourceEntryName(resId);
101
+
102
+ json.append("\"id\":\"").append(resIdName).append("\", \"text:\"").append( ((TextView)view).getText() ).append("\"");
103
+
104
+ json.append(", \"color\":").append( view.getCurrentTextColor() );
105
+ Drawable background = view.getBackground();
106
+ if( background instanceof ColorDrawable ) {
107
+ try {
108
+ // As pointed out by kbielenberg, ColorDrawable.getColor() was only added in level 11/Android 3/Honeycomb
109
+ Method getColor = ColorDrawable.class.getMethod("getColor");
110
+ Integer color = (Integer)getColor.invoke(background);
111
+ json.append(", \"background\":").append( color );
112
+ } catch (Exception e) {}
113
+ }
114
+
115
+ StringBuilder compoundStr = new StringBuilder();
116
+ Drawable[] compoundDrawables = view.getCompoundDrawables(); // left, top, right, and bottom
117
+ if( compoundDrawables[0] != null ) {
118
+ compoundStr.append("\"left\"");
119
+ }
120
+ if( compoundDrawables[1] != null ) {
121
+ if( compoundStr.length() != 0 ) {
122
+ compoundStr.append(',');
123
+ }
124
+ compoundStr.append("\"top\"");
125
+ }
126
+ if( compoundDrawables[2] != null ) {
127
+ if( compoundStr.length() != 0 ) {
128
+ compoundStr.append(',');
129
+ }
130
+ compoundStr.append("\"right\"");
131
+ }
132
+ if( compoundDrawables[3] != null ) {
133
+ if( compoundStr.length() != 0 ) {
134
+ compoundStr.append(',');
135
+ }
136
+ compoundStr.append("\"bottom\"");
137
+ }
138
+ if( compoundStr.length() != 0 ) {
139
+ json.append(", \"compoundDrawables\":[").append(compoundStr).append(']');
140
+ }
141
+ }
142
+
143
+ private void addViewInfo( StringBuilder json, TableRow tableRow ) {
144
+ json.append("\"cells\":[");
145
+
146
+ int count = tableRow.getVirtualChildCount();
147
+ for( int i = 0; i < count; i++ ) {
148
+ if( i != 0 ) {
149
+ json.append(", ");
150
+ }
151
+ json.append("{\"column\":").append(i).append(", ");
152
+
153
+ View view = tableRow.getVirtualChildAt(i);
154
+ if( view instanceof TextView ) {
155
+ addViewInfo( json, (TextView)view );
156
+ } else if( view instanceof ViewGroup ) {
157
+ addViewInfo( json, (ViewGroup)view );
158
+ }
159
+
160
+ json.append('}');
161
+ }
162
+
163
+ json.append(']');
164
+ }
165
+
166
+ private void addViewInfo( StringBuilder json, ViewGroup viewGroup ) {
167
+ json.append("\"children\":[");
168
+
169
+ int count = viewGroup.getChildCount();
170
+ for( int i = 0; i < count; i++ ) {
171
+ if( i != 0 ) {
172
+ json.append(", ");
173
+ }
174
+ json.append('{');
175
+
176
+ View view = viewGroup.getChildAt(i);
177
+ if( view instanceof TextView ) {
178
+ addViewInfo( json, (TextView)view );
179
+ } else if( view instanceof TableRow ) {
180
+ addViewInfo( json, (TableRow)view );
181
+ } else if( view instanceof ViewGroup ) {
182
+ addViewInfo( json, (ViewGroup)view );
183
+ }
184
+
185
+ json.append('}');
186
+ }
187
+
188
+ json.append(']');
189
+ }
190
+
191
+ @Override
192
+ public String key() {
193
+ return "get_list_item_properties";
194
+ }
195
+ }
@@ -0,0 +1,136 @@
1
+ package sh.calaba.instrumentationbackend.actions.list;
2
+
3
+ import java.util.ArrayList;
4
+
5
+ import sh.calaba.instrumentationbackend.InstrumentationBackend;
6
+ import sh.calaba.instrumentationbackend.Result;
7
+ import sh.calaba.instrumentationbackend.actions.Action;
8
+ import android.util.Log;
9
+ import android.view.View;
10
+ import android.view.ViewGroup;
11
+ import android.widget.ListView;
12
+ import android.widget.TableRow;
13
+ import android.widget.TextView;
14
+
15
+ /**
16
+ * args:
17
+ * <ul>
18
+ * <li>1-based list index (first list is used if not specified)</li>
19
+ * <li>1-based row index (returns all rows if &lt;=0 or not specified)</li>
20
+ * </ul>
21
+ *
22
+ * eg: (all items of 1st list) <code>performAction( 'get_list_item_text' )</code>
23
+ * eg: (all items of 2nd list) <code>performAction( 'get_list_item_text', '2' )</code>
24
+ * eg: (1st item of 2nd list) <code>performAction( 'get_list_item_text', '2' , '1' )</code>
25
+ *
26
+ * @return <code>bonusInformation</code> contain an array of Strings, one for each row in the list (or only for the specified row):
27
+ * eg: {"title":"My Title", "subtitle":"Another text field for the same list item"}
28
+ *
29
+ *
30
+ * In ruby, we can then parse the response:
31
+ * <pre>
32
+ * response_table = result['bonusInformation']
33
+ * response_table.each_with_index do | row_data, index |
34
+ * row_data = JSON.parse( row_data )
35
+ * response_table[index] = row_data
36
+ * end
37
+ * </pre>
38
+ *
39
+ * @author Nicholas Albion
40
+ */
41
+ public class GetListItemText implements Action {
42
+
43
+ @Override
44
+ public Result execute(String... args) {
45
+ int listIndex;
46
+ int rowIndex = -1;
47
+
48
+ if( args.length == 0 ) {
49
+ listIndex = 0;
50
+ } else {
51
+ if( args.length > 1 ) {
52
+ rowIndex = (Integer.parseInt(args[1]) - 1);
53
+ }
54
+ listIndex = (Integer.parseInt(args[0]) - 1);
55
+ }
56
+
57
+
58
+ ArrayList<ListView> listViews = InstrumentationBackend.solo.getCurrentListViews();
59
+ Log.d("GetListItemText", "Found " + listViews.size() + " list views");
60
+ if( listViews == null || listViews.size() <= listIndex ) {
61
+ return new Result(false, "Could not find list #" + (listIndex + 1));
62
+ }
63
+
64
+ ListView list = listViews.get(listIndex);
65
+ Result result = new Result(true);
66
+
67
+ if( rowIndex < 0 ) {
68
+ int count = list.getChildCount();
69
+ Log.d("GetListItemText", "Found " + count + " list items");
70
+ for( int i = 0; i < count; i++ ) {
71
+ result.addBonusInformation( getListItemString( list.getChildAt(i) ) );
72
+ }
73
+ } else {
74
+ result.addBonusInformation( getListItemString( list.getChildAt(rowIndex) ) );
75
+ }
76
+
77
+ return result;
78
+ }
79
+
80
+ /**
81
+ * @return <code>bonusInformation</code> contain an array of Strings, one for each row in the list (or only for the specified row):
82
+ * eg: {"title":"My Title", "subtitle":"Another text field for the same list item"}
83
+ */
84
+ private String getListItemString( View row ) {
85
+ StringBuilder json = new StringBuilder("{");
86
+
87
+ if( row instanceof TextView ) {
88
+ addViewInfo( json, (TextView)row );
89
+ } else if( row instanceof ViewGroup ) {
90
+ addViewInfo( json, (ViewGroup)row );
91
+ }
92
+
93
+ json.deleteCharAt( json.length() - 1 ); // remove the last comma
94
+ json.append('}');
95
+ return json.toString();
96
+ }
97
+
98
+ private void addViewInfo( StringBuilder json, TextView view ) {
99
+ int resId = view.getId();
100
+ String resIdName = view.getResources().getResourceEntryName(resId);
101
+
102
+ //json.append("\"id\":\"").append(resIdName).append("\", \"text:\"").append( ((TextView)row).getText() ).append("\"");
103
+ json.append('"').append(resIdName).append("\":\"").append( ((TextView)view).getText() ).append("\",");
104
+ }
105
+
106
+ private void addViewInfo( StringBuilder json, TableRow tableRow ) {
107
+ int count = tableRow.getVirtualChildCount();
108
+ for( int i = 0; i < count; i++ ) {
109
+ View view = tableRow.getVirtualChildAt(i);
110
+ if( view instanceof TextView ) {
111
+ addViewInfo( json, (TextView)view );
112
+ } else if( view instanceof ViewGroup ) {
113
+ addViewInfo( json, (ViewGroup)view );
114
+ }
115
+ }
116
+ }
117
+
118
+ private void addViewInfo( StringBuilder json, ViewGroup viewGroup ) {
119
+ int count = viewGroup.getChildCount();
120
+ for( int i = 0; i < count; i++ ) {
121
+ View view = viewGroup.getChildAt(i);
122
+ if( view instanceof TextView ) {
123
+ addViewInfo( json, (TextView)view );
124
+ } else if( view instanceof TableRow ) {
125
+ addViewInfo( json, (TableRow)view );
126
+ } else if( view instanceof ViewGroup ) {
127
+ addViewInfo( json, (ViewGroup)view );
128
+ }
129
+ }
130
+ }
131
+
132
+ @Override
133
+ public String key() {
134
+ return "get_list_item_text";
135
+ }
136
+ }