acouchi 0.0.1

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 (36) hide show
  1. data/.gitignore +28 -0
  2. data/.ruby-version +1 -0
  3. data/Gemfile +4 -0
  4. data/README.md +48 -0
  5. data/Rakefile +1 -0
  6. data/acouchi.gemspec +21 -0
  7. data/examples/AcouchiSample/AndroidManifest.xml +15 -0
  8. data/examples/AcouchiSample/Rakefile +13 -0
  9. data/examples/AcouchiSample/acouchi_configuration.json +6 -0
  10. data/examples/AcouchiSample/ant.properties +17 -0
  11. data/examples/AcouchiSample/build.xml +92 -0
  12. data/examples/AcouchiSample/features/step_definitions/steps.rb +15 -0
  13. data/examples/AcouchiSample/features/support/env.rb +9 -0
  14. data/examples/AcouchiSample/features/write_text.feature +7 -0
  15. data/examples/AcouchiSample/project.properties +14 -0
  16. data/examples/AcouchiSample/res/drawable-hdpi/ic_launcher.png +0 -0
  17. data/examples/AcouchiSample/res/drawable-ldpi/ic_launcher.png +0 -0
  18. data/examples/AcouchiSample/res/drawable-mdpi/ic_launcher.png +0 -0
  19. data/examples/AcouchiSample/res/drawable-xhdpi/ic_launcher.png +0 -0
  20. data/examples/AcouchiSample/res/layout/main.xml +12 -0
  21. data/examples/AcouchiSample/res/values/strings.xml +4 -0
  22. data/examples/AcouchiSample/src/com/acouchi/sample/StartupActivity.java +15 -0
  23. data/jars/robotium-solo-3.4.1.jar +0 -0
  24. data/lib/acouchi.rb +5 -0
  25. data/lib/acouchi/apk_modifier.rb +54 -0
  26. data/lib/acouchi/configuration.rb +16 -0
  27. data/lib/acouchi/cucumber.rb +16 -0
  28. data/lib/acouchi/project_builder.rb +91 -0
  29. data/lib/acouchi/solo.rb +49 -0
  30. data/lib/acouchi/test_runner.rb +33 -0
  31. data/lib/acouchi/version.rb +3 -0
  32. data/not-yet-implemented.md +223 -0
  33. data/src/com/acouchi/Acouchi.java +144 -0
  34. data/src/com/acouchi/NanoHTTPD.java +1119 -0
  35. data/src/com/acouchi/TestCase.java +32 -0
  36. metadata +113 -0
@@ -0,0 +1,91 @@
1
+ require "acouchi/apk_modifier"
2
+ require "fileutils"
3
+
4
+ module Acouchi
5
+ JARS_PATH = File.expand_path(File.join(File.dirname(__FILE__), "../../jars"))
6
+ ROBOTIUM_SOURCE_PATH = File.expand_path(File.join(File.dirname(__FILE__), "../../src/com/acouchi"))
7
+
8
+ class ProjectBuilder
9
+ def initialize configuration
10
+ @configuration = configuration
11
+ end
12
+
13
+ def configuration
14
+ @configuration
15
+ end
16
+
17
+ def build
18
+ temporarily_copy_over_source_files do
19
+ build_apk
20
+ end
21
+
22
+ apk_path = File.join(configuration.project_path, "bin", configuration.apk)
23
+ modify_manifest(apk_path)
24
+ install_apk(apk_path)
25
+ end
26
+
27
+ def temporarily_copy_over_source_files
28
+ destination_libs_path = "#{configuration.project_path}/libs"
29
+ destination_source_path = "#{configuration.project_path}/src/com/acouchi"
30
+
31
+ FileUtils.mkdir_p destination_libs_path
32
+ Dir.glob(File.join(JARS_PATH, "*.jar")).each do |jar|
33
+ FileUtils.cp jar, destination_libs_path
34
+ end
35
+
36
+ FileUtils.mkdir_p destination_source_path
37
+ Dir.glob(File.join(ROBOTIUM_SOURCE_PATH, "*.java")).each do |java_file|
38
+ FileUtils.cp java_file, destination_source_path
39
+ file_path = File.join(destination_source_path, File.basename(java_file))
40
+ file_content = File.read(file_path).gsub("ACTIVITY_UNDER_TEST", configuration.activity)
41
+ File.open(file_path, "w") { |file| file.write(file_content) }
42
+ end
43
+
44
+ yield
45
+
46
+ Dir.glob(File.join(JARS_PATH, "*.jar")).each do |jar|
47
+ FileUtils.rm File.join(destination_libs_path, File.basename(jar))
48
+ end
49
+
50
+ Dir.glob(File.join(ROBOTIUM_SOURCE_PATH, "*.java")).each do |java_file|
51
+ FileUtils.rm File.join(destination_source_path, File.basename(java_file))
52
+ end
53
+ end
54
+
55
+ def modify_manifest apk_path
56
+ ApkModifier.new(apk_path).modify_manifest do |original|
57
+ require "nokogiri"
58
+ document = Nokogiri::XML(original)
59
+ manifest = document.xpath("//manifest").first
60
+
61
+ instrumentation = Nokogiri::XML::Node.new("instrumentation", document)
62
+ instrumentation["android:name"] = "android.test.InstrumentationTestRunner"
63
+ instrumentation["android:targetPackage"] = configuration.target_package
64
+ manifest.add_child(instrumentation)
65
+
66
+ uses_permission = Nokogiri::XML::Node.new("uses-permission", document)
67
+ uses_permission["android:name"] = "android.permission.INTERNET"
68
+ manifest.add_child(uses_permission)
69
+
70
+ application = document.xpath("//application").first
71
+ uses_library = Nokogiri::XML::Node.new("uses-library", document)
72
+ uses_library["android:name"] = "android.test.runner"
73
+ application.add_child(uses_library)
74
+
75
+ document.to_xml
76
+ end
77
+ end
78
+
79
+ def build_apk
80
+ Dir.chdir configuration.project_path do
81
+ system "ant clean"
82
+ system "ant debug"
83
+ end
84
+ end
85
+
86
+ def install_apk apk_path
87
+ system "adb uninstall #{configuration.target_package}"
88
+ system "adb install #{apk_path}"
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,49 @@
1
+ require "httparty"
2
+ require "json"
3
+
4
+ module Acouchi
5
+ class Solo
6
+ MENU = 82
7
+
8
+ def send_key key
9
+ call_method("sendKey", [{:type => "int", :value => key}])
10
+ end
11
+
12
+ def enter_text index, text
13
+ call_method("enterText", [
14
+ {:type => "int", :value => index},
15
+ {:type => "java.lang.String", :value => text}
16
+ ])
17
+ end
18
+
19
+ def clear_edit_text index
20
+ call_method("clearEditText", [{:type => "int", :value => index}])
21
+ end
22
+
23
+ def has_text? text, options={}
24
+ options = {
25
+ :scroll => true,
26
+ :minimum_matches => 0,
27
+ :must_be_visible => true
28
+ }.merge(options)
29
+
30
+ call_method("searchText", [
31
+ {:type => "java.lang.String", :value => text},
32
+ {:type => "int", :value => options[:minimum_matches]},
33
+ {:type => "boolean", :value => options[:scroll]},
34
+ {:type => "boolean", :value => options[:must_be_visible]}
35
+ ])
36
+ end
37
+
38
+ private
39
+ def call_method name, arguments
40
+ options = { :body => {:parameters => arguments.to_json} }
41
+ json = JSON.parse(HTTParty.post("http://127.0.0.1:7103/execute_method/#{name}", options).body)
42
+ if json["emptyResult"]
43
+ nil
44
+ else
45
+ json["result"]
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,33 @@
1
+ require "childprocess"
2
+
3
+ module Acouchi
4
+ class TestRunner
5
+ def initialize configuration
6
+ @configuration = configuration
7
+ end
8
+
9
+ def start
10
+ system "adb forward tcp:7103 tcp:7103"
11
+ @test_runner_process = ChildProcess.build("adb", "shell", "am", "instrument", "-w", "#{@configuration.target_package}/android.test.InstrumentationTestRunner")
12
+ @test_runner_process.start
13
+
14
+ while ready? == false
15
+ sleep 0.1
16
+ end
17
+ end
18
+
19
+ def stop
20
+ HTTParty.get("http://127.0.0.1:7103/finish") rescue nil
21
+ begin
22
+ @test_runner_process.poll_for_exit 10
23
+ rescue ChildProcess::TimeoutError
24
+ @test_runner_process.stop
25
+ end
26
+ end
27
+
28
+ private
29
+ def ready?
30
+ HTTParty.get("http://127.0.0.1:7103/").body == "Acouchi" rescue false
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,3 @@
1
+ module Acouchi
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,223 @@
1
+ Constants
2
+ ---------
3
+
4
+ com.jayway.android.robotium.solo.Solo
5
+ public static final int CLOSED 0
6
+ public static final int DELETE 67
7
+ public static final int DOWN 20
8
+ public static final int ENTER 66
9
+ public static final int LANDSCAPE 0
10
+ public static final int LEFT 21
11
+ public static final int MENU 82
12
+ public static final int OPENED 1
13
+ public static final int PORTRAIT 1
14
+ public static final int RIGHT 22
15
+ public static final int UP 19
16
+
17
+ Methods
18
+ -------
19
+
20
+ void assertCurrentActivity(String message, Class expectedClass) Asserts that the expected Activity is the currently active one.
21
+ void assertCurrentActivity(String message, Class expectedClass, boolean isNewInstance) Asserts that the expected Activity is the currently active one, with the possibility to verify that the expected Activity is a new instance of the Activity.
22
+ void assertCurrentActivity(String message, String name) Asserts that the expected Activity is the currently active one.
23
+ void assertCurrentActivity(String message, String name, boolean isNewInstance) Asserts that the expected Activity is the currently active one, with the possibility to verify that the expected Activity is a new instance of the Activity.
24
+
25
+ void assertMemoryNotLow() Asserts that the available memory in the system is not low.
26
+
27
+ * void clearEditText(android.widget.EditText editText) Clears the value of an EditText.
28
+ * void clearEditText(int index) Clears the value of an EditText.
29
+
30
+ ArrayList<android.widget.TextView> clickInList(int line) Clicks on a given list line and returns an ArrayList of the TextView objects that the list line is showing.
31
+ ArrayList<android.widget.TextView> clickInList(int line, int index) Clicks on a given list line on a specified list and returns an ArrayList of the TextView objects that the list line is showing.
32
+
33
+ ArrayList<android.widget.TextView> clickLongInList(int line) Long clicks on a given list line and returns an ArrayList of the TextView objects that the list line is showing.
34
+ ArrayList<android.widget.TextView> clickLongInList(int line, int index) Long clicks on a given list line on a specified list and returns an ArrayList of the TextView objects that the list line is showing.
35
+ ArrayList<android.widget.TextView> clickLongInList(int line, int index, int time) Long clicks on a given list line on a specified list and returns an ArrayList of the TextView objects that the list line is showing.
36
+
37
+ void clickLongOnScreen(float x, float y) Long clicks a given coordinate on the screen.
38
+ void clickLongOnScreen(float x, float y, int time) Long clicks a given coordinate on the screen for a given amount of time.
39
+
40
+ void clickLongOnText(String text) Long clicks on a given View.
41
+ void clickLongOnText(String text, int match) Long clicks on a given View.
42
+ void clickLongOnText(String text, int match, boolean scroll) Long clicks on a given View.
43
+ void clickLongOnText(String text, int match, int time) Long clicks on a given View.
44
+
45
+ void clickLongOnTextAndPress(String text, int index) Long clicks on a given View and then selects an item from the context menu that appears.
46
+
47
+ void clickLongOnView(android.view.View view) Long clicks on a given View.
48
+ void clickLongOnView(android.view.View view, int time) Long clicks on a given View for a given amount of time.
49
+
50
+ void clickOnButton(int index) Clicks on a Button with a given index.
51
+ void clickOnButton(String name) Clicks on a Button with a given text.
52
+
53
+ void clickOnCheckBox(int index) Clicks on a CheckBox with a given index.
54
+
55
+ void clickOnEditText(int index) Clicks on an EditText with a given index.
56
+
57
+ void clickOnImage(int index) Clicks on an ImageView with a given index.
58
+
59
+ void clickOnImageButton(int index) Clicks on an ImageButton with a given index.
60
+
61
+ void clickOnMenuItem(String text) Clicks on a MenuItem with a given text.
62
+ void clickOnMenuItem(String text, boolean subMenu) Clicks on a MenuItem with a given text.
63
+
64
+ void clickOnRadioButton(int index) Clicks on a RadioButton with a given index.
65
+
66
+ void clickOnScreen(float x, float y) Clicks on a given coordinate on the screen.
67
+
68
+ void clickOnText(String text) Clicks on a View displaying a given text.
69
+ void clickOnText(String text, int match) Clicks on a View displaying a given text.
70
+ void clickOnText(String text, int match, boolean scroll) Clicks on a View displaying a given text.
71
+
72
+ void clickOnToggleButton(String name) Clicks on a ToggleButton with a given text.
73
+
74
+ void clickOnView(android.view.View view) Clicks on a given View.
75
+
76
+ void drag(float fromX, float toX, float fromY, float toY, int stepCount) Simulate touching a given location and dragging it to a new location.
77
+
78
+ * void enterText(android.widget.EditText editText, String text) Enters text into a given EditText.
79
+ * void enterText(int index, String text) Enters text into an EditText with a given index.
80
+
81
+ void finalize() Finalizes the solo object and removes the ActivityMonitor.
82
+
83
+ void finishOpenedActivities() All activities that have been active are finished.
84
+
85
+ android.app.Instrumentation.ActivityMonitor getActivityMonitor() Returns the ActivityMonitor used by Robotium.
86
+
87
+ ArrayList<android.app.Activity> getAllOpenedActivities() Returns an ArrayList of all the opened/active activities.
88
+
89
+ android.widget.Button getButton(int index) Returns a Button with a given index.
90
+ android.widget.Button getButton(String text) Returns a Button which shows a given text.
91
+ android.widget.Button getButton(String text, boolean onlyVisible) Returns a Button which shows a given text.
92
+
93
+ android.app.Activity getCurrentActivity() Returns the current Activity.
94
+
95
+ ArrayList<android.widget.Button> getCurrentButtons() Returns an ArrayList of the Button objects currently shown in the focused Activity or Dialog.
96
+
97
+ ArrayList<android.widget.CheckBox> getCurrentCheckBoxes() Returns an ArrayList of the CheckBox objects currently shown in the focused Activity or Dialog.
98
+
99
+ ArrayList<android.widget.DatePicker> getCurrentDatePickers() Returns an ArrayList of the DatePicker objects currently shown in the focused Activity or Dialog.
100
+
101
+ ArrayList<android.widget.EditText> getCurrentEditTexts() Returns an ArrayList of the EditText objects currently shown in the focused Activity or Dialog.
102
+
103
+ ArrayList<android.widget.GridView> getCurrentGridViews() Returns an ArrayList of the GridView objects currently shown in the focused Activity or Dialog.
104
+
105
+ ArrayList<android.widget.ImageButton> getCurrentImageButtons() Returns an ArrayList of the ImageButton objects currently shown in the focused Activity or Dialog.
106
+
107
+ ArrayList<android.widget.ImageView> getCurrentImageViews() Returns an ArrayList of the ImageView objects currently shown in the focused Activity or Dialog.
108
+
109
+ ArrayList<android.widget.ListView> getCurrentListViews() Returns an ArrayList of the ListView objects currently shown in the focused Activity or Dialog.
110
+
111
+ ArrayList<android.widget.ProgressBar> getCurrentProgressBars() Returns an ArrayList of the ProgressBar objects currently shown in the focused Activity or Dialog.
112
+
113
+ ArrayList<android.widget.RadioButton> getCurrentRadioButtons() Returns an ArrayList of the RadioButton objects currently shown in the focused Activity or Dialog.
114
+
115
+ ArrayList<android.widget.ScrollView> getCurrentScrollViews() Returns an ArrayList of the ScrollView objects currently shown in the focused Activity or Dialog.
116
+
117
+ ArrayList<android.widget.SlidingDrawer> getCurrentSlidingDrawers() Returns an ArrayList of the SlidingDrawer objects currently shown in the focused Activity or Dialog.
118
+
119
+ ArrayList<android.widget.Spinner> getCurrentSpinners() Returns an ArrayList of the Spinner objects (drop-down menus) currently shown in the focused Activity or Dialog.
120
+
121
+ ArrayList<android.widget.TextView> getCurrentTextViews(android.view.View parent) Returns an ArrayList of the TextView objects currently shown in the focused Activity or Dialog.
122
+
123
+ ArrayList<android.widget.TimePicker> getCurrentTimePickers() Returns an ArrayList of the TimePicker objects currently shown in the focused Activity or Dialog.
124
+
125
+ ArrayList<android.widget.ToggleButton> getCurrentToggleButtons() Returns an ArrayList of the ToggleButton objects currently shown in the focused Activity or Dialog.
126
+
127
+ ArrayList<android.view.View> getCurrentViews() Returns an ArrayList of the View objects currently shown in the focused Activity or Dialog.
128
+
129
+ android.widget.EditText getEditText(int index) Returns an EditText with a given index.
130
+ android.widget.EditText getEditText(String text) Returns an EditText which shows a given text.
131
+ android.widget.EditText getEditText(String text, boolean onlyVisible) Returns an EditText which shows a given text.
132
+
133
+ android.widget.ImageView getImage(int index) Returns an ImageView with a given index.
134
+
135
+ android.widget.ImageButton getImageButton(int index) Returns an ImageButton with a given index. String getString(int resId) Returns a localized string.
136
+
137
+ android.widget.TextView getText(int index) Returns a TextView with a given index.
138
+ android.widget.TextView getText(String text) Returns a TextView which shows a given text.
139
+ android.widget.TextView getText(String text, boolean onlyVisible) Returns a TextView which shows a given text.
140
+
141
+ android.view.View getTopParent(android.view.View view) Returns the absolute top parent View for a given View.
142
+
143
+ <T extends android.view.View> android.view.View getView(Class<T> viewClass, int index) Returns a View of a given class and index. android.view.View getView(int id) Returns a View with a given id.
144
+
145
+ ArrayList<android.view.View> getViews() Returns an ArrayList of all the View objects located in the focused Activity or Dialog.
146
+ ArrayList<android.view.View> getViews(android.view.View parent) Returns an ArrayList of the View objects contained in the parent View.
147
+
148
+ void goBack() Simulates pressing the hardware back key.
149
+ void goBackToActivity(String name) Returns to the given Activity.
150
+
151
+ boolean isCheckBoxChecked(int index) Checks if a CheckBox with a given index is checked.
152
+ boolean isCheckBoxChecked(String text) Checks if a CheckBox with a given text is checked.
153
+
154
+ boolean isRadioButtonChecked(int index) Checks if a RadioButton with a given index is checked.
155
+ boolean isRadioButtonChecked(String text) Checks if a RadioButton with a given text is checked.
156
+
157
+ boolean isSpinnerTextSelected(int index, String text) Checks if a given text is selected in a given Spinner.
158
+ boolean isSpinnerTextSelected(String text) Checks if a given text is selected in any Spinner located in the current screen.
159
+
160
+ boolean isTextChecked(String text) Checks if the given text is checked.
161
+
162
+ boolean isToggleButtonChecked(int index) Checks if a ToggleButton with a given index is checked.
163
+ boolean isToggleButtonChecked(String text) Checks if a ToggleButton with a given text is checked.
164
+
165
+ void pressMenuItem(int index) Presses a MenuItem with a given index.
166
+ void pressMenuItem(int index, int itemsPerRow) Presses a MenuItem with a given index.
167
+
168
+ void pressSpinnerItem(int spinnerIndex, int itemIndex) Presses on a Spinner (drop-down menu) item.
169
+ boolean scrollDown() Scrolls down the screen.
170
+ boolean scrollDownList(int index) Scrolls down a list with a given index.
171
+ void scrollToSide(int side) Scrolls horizontally.
172
+ boolean scrollUp() Scrolls up the screen.
173
+ boolean scrollUpList(int index) Scrolls up a list with a given index.
174
+
175
+ boolean searchButton(String text) Searches for a Button with the given text string and returns true if at least one Button is found.
176
+ boolean searchButton(String text, boolean onlyVisible) Searches for a Button with the given text string and returns true if at least one Button is found.
177
+ boolean searchButton(String text, int minimumNumberOfMatches) Searches for a Button with the given text string and returns true if the searched Button is found a given number of times.
178
+ boolean searchButton(String text, int minimumNumberOfMatches, boolean onlyVisible) Searches for a Button with the given text string and returns true if the searched Button is found a given number of times.
179
+
180
+ boolean searchEditText(String text) Searches for a text string in the EditText objects currently shown and returns true if found.
181
+
182
+ boolean searchText(String text) Searches for a text string and returns true if at least one item is found with the expected text.
183
+ boolean searchText(String text, boolean onlyVisible) Searches for a text string and returns true if at least one item is found with the expected text.
184
+ boolean searchText(String text, int minimumNumberOfMatches) Searches for a text string and returns true if the searched text is found a given number of times.
185
+ boolean searchText(String text, int minimumNumberOfMatches, boolean scroll) Searches for a text string and returns true if the searched text is found a given number of times.
186
+ boolean searchText(String text, int minimumNumberOfMatches, boolean scroll, boolean onlyVisible) Searches for a text string and returns true if the searched text is found a given number of times.
187
+
188
+ boolean searchToggleButton(String text) Searches for a ToggleButton with the given text string and returns true if at least one ToggleButton is found.
189
+ boolean searchToggleButton(String text, int minimumNumberOfMatches) Searches for a ToggleButton with the given text string and returns true if the searched ToggleButton is found a given number of times.
190
+
191
+ * void sendKey(int key) Sends a key: Right, Left, Up, Down, Enter, Menu or Delete.
192
+
193
+ void setActivityOrientation(int orientation) Sets the Orientation (Landscape/Portrait) for the current activity.
194
+
195
+ void setDatePicker(android.widget.DatePicker datePicker, int year, int monthOfYear, int dayOfMonth) Sets the date in a given DatePicker.
196
+ void setDatePicker(int index, int year, int monthOfYear, int dayOfMonth) Sets the date in a DatePicker with a given index.
197
+
198
+ void setProgressBar(int index, int progress) Sets the progress of a ProgressBar with a given index.
199
+ void setProgressBar(android.widget.ProgressBar progressBar, int progress) Sets the progress of a given ProgressBar.
200
+
201
+ void setSlidingDrawer(int index, int status) Sets the status of a SlidingDrawer with a given index.
202
+ void setSlidingDrawer(android.widget.SlidingDrawer slidingDrawer, int status) Sets the status of a given SlidingDrawer.
203
+
204
+ void setTimePicker(int index, int hour, int minute) Sets the time in a TimePicker with a given index.
205
+ void setTimePicker(android.widget.TimePicker timePicker, int hour, int minute) Sets the time in a given TimePicker.
206
+
207
+ void sleep(int time) Robotium will sleep for a specified time.
208
+
209
+ boolean waitForActivity(String name) Waits for the given Activity.
210
+ boolean waitForActivity(String name, int timeout) Waits for the given Activity.
211
+
212
+ boolean waitForDialogToClose(long timeout) Waits for a Dialog to close.
213
+
214
+ * boolean waitForText(String text) Waits for a text to be shown.
215
+ * boolean waitForText(String text, int minimumNumberOfMatches, long timeout) Waits for a text to be shown.
216
+ * boolean waitForText(String text, int minimumNumberOfMatches, long timeout, boolean scroll) Waits for a text to be shown.
217
+ * boolean waitForText(String text, int minimumNumberOfMatches, long timeout, boolean scroll, boolean onlyVisible) Waits for a text to be shown.
218
+
219
+ <T extends android.view.View> boolean waitForView(Class<T> viewClass) Waits for a View of a certain class to be shown.
220
+ <T extends android.view.View> boolean waitForView(Class<T> viewClass, int minimumNumberOfMatches, int timeout) Waits for a View of a certain class to be shown.
221
+ <T extends android.view.View> boolean waitForView(Class<T> viewClass, int minimumNumberOfMatches, int timeout, boolean scroll) Waits for a View of a certain class to be shown.
222
+ <T extends android.view.View> boolean waitForView(android.view.View view) Waits for a View to be shown.
223
+ <T extends android.view.View> boolean waitForView(android.view.View view, int timeout, boolean scroll) Waits for a View to be shown.
@@ -0,0 +1,144 @@
1
+ package com.acouchi;
2
+ import com.jayway.android.robotium.solo.Solo;
3
+
4
+ import java.util.Properties;
5
+ import java.io.File;
6
+ import java.io.IOException;
7
+
8
+ import java.util.concurrent.locks.Condition;
9
+ import java.util.concurrent.locks.Lock;
10
+ import java.util.concurrent.locks.ReentrantLock;
11
+
12
+ import android.app.Instrumentation;
13
+ import android.app.Activity;
14
+ import java.lang.reflect.Method;
15
+ import org.json.JSONArray;
16
+ import org.json.JSONObject;
17
+ import org.json.JSONException;
18
+ import java.util.ArrayList;
19
+ import java.io.PrintWriter;
20
+ import java.io.StringWriter;
21
+ import java.io.Writer;
22
+
23
+ public class Acouchi extends NanoHTTPD
24
+ {
25
+ private Solo solo;
26
+ private boolean serverRunning = true;
27
+ private Lock lock = new ReentrantLock();
28
+ private Condition endedCondition = lock.newCondition();
29
+
30
+ public Acouchi(Solo solo) throws IOException
31
+ {
32
+ super(7103, new File("."));
33
+ this.solo = solo;
34
+ }
35
+
36
+ public void WaitUntilServerKilled() throws InterruptedException
37
+ {
38
+ lock.lock();
39
+ try {
40
+ while(serverRunning)
41
+ {
42
+ endedCondition.await();
43
+ }
44
+ }
45
+ finally {
46
+ lock.unlock();
47
+ }
48
+ }
49
+
50
+ public Response serve(String uri, String method, Properties header, Properties params, Properties files )
51
+ {
52
+ if (uri.endsWith("/finish"))
53
+ {
54
+ try {
55
+ serverRunning = false;
56
+ stop();
57
+ endedCondition.signal();
58
+ }
59
+ finally {
60
+ lock.unlock();
61
+ }
62
+ return new NanoHTTPD.Response(HTTP_OK, MIME_HTML, "");
63
+ }
64
+ else if (uri.startsWith("/execute_method"))
65
+ {
66
+ String methodName = uri.replace("/execute_method/", "");
67
+ return ExecuteMethod(methodName, params.getProperty("parameters"));
68
+ }
69
+
70
+ return new NanoHTTPD.Response(HTTP_OK, MIME_HTML, "Acouchi");
71
+ }
72
+
73
+ private NanoHTTPD.Response ExecuteMethod(String methodName, String json)
74
+ {
75
+ try {
76
+ JSONArray jsonArray = new JSONArray(json);
77
+ Class[] parameterTypes = new Class[jsonArray.length()];
78
+ Object[] parameters = new Object[jsonArray.length()];
79
+
80
+ for (int i = 0; i < jsonArray.length(); i++) {
81
+ JSONObject jsonObject = jsonArray.getJSONObject(i);
82
+
83
+ parameterTypes[i] = getClassType(jsonObject.getString("type"));
84
+ parameters[i] = getConvertedValue(jsonObject.getString("type"), jsonObject.getString("value"));
85
+ }
86
+
87
+ Method method = solo.getClass().getMethod(methodName, parameterTypes);
88
+ return displayMethodResultAsJson(method.invoke(solo, parameters));
89
+ } catch (Exception exception) {
90
+ return showException(exception);
91
+ }
92
+ }
93
+
94
+ private NanoHTTPD.Response displayMethodResultAsJson(Object result)
95
+ {
96
+ try {
97
+ JSONObject object = new JSONObject();
98
+
99
+ if (result == null) {
100
+ object.put("emptyResult", true);
101
+ } else {
102
+ object.put("result", result);
103
+ }
104
+
105
+ return new NanoHTTPD.Response(HTTP_OK, MIME_HTML, object.toString());
106
+ } catch (JSONException e) {
107
+ return showException(e);
108
+ }
109
+ }
110
+
111
+ private Class getClassType(String name) throws java.lang.ClassNotFoundException
112
+ {
113
+ if (name.equals("int")) return int.class;
114
+ if (name.equals("long")) return long.class;
115
+ if (name.equals("double")) return double.class;
116
+ if (name.equals("boolean")) return boolean.class;
117
+ return Class.forName(name);
118
+ }
119
+
120
+ private Object getConvertedValue(String name, String value)
121
+ {
122
+ if (name.equals("int")) return Integer.parseInt(value);
123
+ if (name.equals("long")) return Long.parseLong(value);
124
+ if (name.equals("double")) return Double.parseDouble(value);
125
+ if (name.equals("boolean")) return Boolean.parseBoolean(value);
126
+ if (name.equals("java.lang.Integer")) return Integer.parseInt(value);
127
+ if (name.equals("java.lang.Long")) return Long.parseLong(value);
128
+ if (name.equals("java.lang.Double")) return Double.parseDouble(value);
129
+ if (name.equals("java.lang.Boolean")) return Boolean.parseBoolean(value);
130
+ return value;
131
+ }
132
+
133
+ private NanoHTTPD.Response showException(Exception exception)
134
+ {
135
+ return new NanoHTTPD.Response(HTTP_OK, MIME_HTML, "exception: " + exception.toString() + "\n" + getStackTrace(exception));
136
+ }
137
+
138
+ private static String getStackTrace(Throwable aThrowable) {
139
+ final Writer result = new StringWriter();
140
+ final PrintWriter printWriter = new PrintWriter(result);
141
+ aThrowable.printStackTrace(printWriter);
142
+ return result.toString();
143
+ }
144
+ }