calabash-android 0.2.11 → 0.2.12
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.
- data/CHANGES.txt +6 -0
- data/features-skeleton/support/app_installation_hooks.rb +11 -3
- data/features-skeleton/support/app_life_cycle_hooks.rb +9 -0
- data/features-skeleton/support/hooks.rb +18 -2
- data/lib/calabash-android/operations.rb +1 -1
- data/lib/calabash-android/steps/assert_steps.rb +12 -0
- data/lib/calabash-android/steps/list_steps.rb +40 -0
- data/lib/calabash-android/steps/map_steps.rb +61 -0
- data/lib/calabash-android/steps/navigation_steps.rb +10 -1
- data/lib/calabash-android/steps/progress_steps.rb +5 -0
- data/lib/calabash-android/version.rb +2 -2
- data/test-server/AndroidManifest.xml +5 -5
- data/test-server/build.xml +4 -0
- data/test-server/instrumentation-backend/.gitignore +1 -0
- data/test-server/instrumentation-backend/AndroidManifest.xml +4 -3
- data/test-server/instrumentation-backend/project.properties +1 -1
- data/test-server/instrumentation-backend/src/com/jayway/android/robotium/solo/MapViewUtils.java +328 -0
- data/test-server/instrumentation-backend/src/com/jayway/android/robotium/solo/SoloEnhanced.java +97 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/InstrumentationBackend.java +3 -3
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/TestHelpers.java +51 -1
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/GetListItemProperties.java +195 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/list/GetListItemText.java +136 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/GetMapBounds.java +27 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/GetMapCenter.java +27 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/GetMapMarker.java +31 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/GetMapMarkers.java +48 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/GetMapZoom.java +19 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/PanMapTo.java +23 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/SetMapCenter.java +23 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/SetMapZoom.java +34 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/TapAwayFromMarkers.java +28 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/map/TapMapMarker.java +29 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/spinner/GetSelectedSpinnerItemText.java +36 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/AssertGridViewContainsNoDuplicates.java +72 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/text/GetTextById.java +42 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/AssertViewProperty.java +141 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/ClickOnViewById.java +1 -8
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/GetActivityName.java +32 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/GetViewProperty.java +107 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/HasView.java +31 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/Press.java +1 -1
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/view/SelectTab.java +110 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForScreen.java +10 -6
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/wait/WaitForTab.java +108 -0
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/{view → wait}/WaitForView.java +1 -1
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/{view → wait}/WaitForViewById.java +21 -11
- data/test-server/instrumentation-backend/src/sh/calaba/instrumentationbackend/actions/webview/QueryHelper.java +3 -3
- metadata +102 -88
data/CHANGES.txt
CHANGED
@@ -5,7 +5,12 @@ AfterConfiguration do |config|
|
|
5
5
|
end
|
6
6
|
|
7
7
|
Before do |scenario|
|
8
|
-
|
8
|
+
@scenario_is_outline = (scenario.class == Cucumber::Ast::OutlineTable::ExampleRow)
|
9
|
+
if @scenario_is_outline
|
10
|
+
scenario = scenario.scenario_outline
|
11
|
+
end
|
12
|
+
|
13
|
+
feature_name = scenario.feature.title
|
9
14
|
if FeatureNameMemory.feature_name != feature_name \
|
10
15
|
or ENV["RESET_BETWEEN_SCENARIOS"] == "1"
|
11
16
|
if ENV["RESET_BETWEEN_SCENARIOS"] == "1"
|
@@ -18,11 +23,14 @@ Before do |scenario|
|
|
18
23
|
install_app(ENV["TEST_APP_PATH"])
|
19
24
|
install_app(ENV["APP_PATH"])
|
20
25
|
FeatureNameMemory.feature_name = feature_name
|
21
|
-
|
26
|
+
FeatureNameMemory.invocation = 1
|
27
|
+
else
|
28
|
+
FeatureNameMemory.invocation += 1
|
29
|
+
end
|
22
30
|
end
|
23
31
|
|
24
32
|
FeatureNameMemory = Class.new
|
25
33
|
class << FeatureNameMemory
|
26
34
|
@feature_name = nil
|
27
|
-
attr_accessor :feature_name
|
35
|
+
attr_accessor :feature_name, :invocation
|
28
36
|
end
|
@@ -1,6 +1,15 @@
|
|
1
1
|
require 'calabash-android/management/adb'
|
2
2
|
|
3
3
|
Before do |scenario|
|
4
|
+
# John Gallagher provided the "scenario_is_outline" fix: https://groups.google.com/forum/?fromgroups#!topic/calabash-ios/ICA4f24eSsY
|
5
|
+
# ...there may be a better way of doing this...
|
6
|
+
@scenario_is_outline = (scenario.class == Cucumber::Ast::OutlineTable::ExampleRow)
|
7
|
+
if @scenario_is_outline
|
8
|
+
scenario = scenario.scenario_outline
|
9
|
+
# Still need to call connect_to_test_server...
|
10
|
+
elsif scenario.failed?
|
11
|
+
return #No need to start the server is anything before this has failed.
|
12
|
+
end
|
4
13
|
|
5
14
|
return if scenario.failed? #No need to start the server is anything before this has failed.
|
6
15
|
start_test_server_in_background
|
@@ -1,13 +1,29 @@
|
|
1
1
|
|
2
2
|
Before do |scenario|
|
3
|
+
# https://groups.google.com/forum/?fromgroups#!topic/calabash-ios/ICA4f24eSsY
|
4
|
+
@scenario_is_outline = (scenario.class == Cucumber::Ast::OutlineTable::ExampleRow)
|
5
|
+
if @scenario_is_outline
|
6
|
+
scenario = scenario.scenario_outline
|
7
|
+
end
|
8
|
+
|
3
9
|
StepCounter.step_index = 0
|
4
|
-
|
10
|
+
# https://github.com/calabash/calabash-android/issues/58#issuecomment-6745642
|
11
|
+
if scenario.respond_to? :raw_steps
|
12
|
+
StepCounter.step_line = scenario.raw_steps[StepCounter.step_index].line
|
13
|
+
else
|
14
|
+
StepCounter.step_line = 0
|
15
|
+
end
|
5
16
|
end
|
6
17
|
|
7
18
|
AfterStep do |scenario|
|
8
19
|
#Handle multiline steps
|
9
20
|
StepCounter.step_index = StepCounter.step_index + 1
|
10
|
-
|
21
|
+
# https://github.com/calabash/calabash-android/issues/58#issuecomment-6745642
|
22
|
+
if scenario.respond_to? :raw_steps
|
23
|
+
StepCounter.step_line = scenario.raw_steps[StepCounter.step_index].line unless scenario.raw_steps[StepCounter.step_index].nil?
|
24
|
+
else
|
25
|
+
StepCounter.step_line = StepCounter.step_line + 1
|
26
|
+
end
|
11
27
|
end
|
12
28
|
|
13
29
|
StepCounter = Class.new
|
@@ -200,7 +200,7 @@ module Operations
|
|
200
200
|
filename_prefix = FeatureNameMemory.feature_name.gsub(/\s+/, '_').downcase
|
201
201
|
begin
|
202
202
|
Timeout.timeout(30) do
|
203
|
-
file_name = "#{path}/#{filename_prefix}_#{StepCounter.step_line}.png"
|
203
|
+
file_name = "#{path}/#{filename_prefix}_#{FeatureNameMemory.invocation}_#{StepCounter.step_line}.png"
|
204
204
|
image = http("/screenshot")
|
205
205
|
open(file_name ,"wb") { |file|
|
206
206
|
file.write(image)
|
@@ -29,4 +29,16 @@ Then /^I don't see "([^\"]*)"$/ do |text|
|
|
29
29
|
performAction('assert_text', text, false) #second param indicated that the text should _not_ be found
|
30
30
|
end
|
31
31
|
|
32
|
+
# This step is more of an example or macro to be used within your own custom steps
|
33
|
+
# Generally, assert_view_property takes 3 args, but for if 'property'='compoundDrawables', the next arg should be 'left'/'right'/'top'/'bottom', followed by the expected drawable ID.
|
34
|
+
# @param view_id - the name of the view, eg: R.my_view_id
|
35
|
+
# @param property - eg: 'visibility' (visible/invisible/gone), 'drawable' (expected drawable ID)
|
36
|
+
Then /^the view with id "([^\"]*)" should have property "([^\"]*)" = "([^\"]*)"$/ do | view_id, property, value |
|
37
|
+
# get_view_property is also available: performAction( 'get_view_property', 'my_view', 'visibility')
|
38
|
+
performAction( 'assert_view_property', view_id, property, value )
|
39
|
+
end
|
32
40
|
|
41
|
+
Then /^the "([^\"]*)" activity should be open$/ do | expected_activity |
|
42
|
+
actual_activity = performAction('get_activity_name')['message']
|
43
|
+
raise "The current activity is #{actual_activity}" unless( actual_activity == expected_activity || actual_activity == expected_activity + 'Activity' )
|
44
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# By default "get_list_item_text" returns an array of arrays of text for each entry in the first ListView
|
2
|
+
# The "get_list_item_text" action also supports:
|
3
|
+
# (all items of 2nd list) <code>performAction( 'get_list_item_text', '2' )</code>
|
4
|
+
# (1st item of 2nd list) <code>performAction( 'get_list_item_text', '2' , '1' )</code>
|
5
|
+
Then /^I should see following list:$/ do | expected_table |
|
6
|
+
result = performAction('get_list_item_text')
|
7
|
+
response_table = result['bonusInformation']
|
8
|
+
response_table.each_with_index do | row_data, index |
|
9
|
+
row_data = JSON.parse( row_data )
|
10
|
+
response_table[index] = row_data
|
11
|
+
end
|
12
|
+
|
13
|
+
expected_table.diff!(response_table)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Note: This step is currently intended as more of an example rather than a rock-solid, well-tested step.
|
17
|
+
# (The server implementation works well for me, but my test steps that use it are application-specific)
|
18
|
+
# Similarly to the "get_list_item_text" action, the "get_list_item_properties" action defaults to
|
19
|
+
# all rows of the first ListView, but can be instructed to target a specific row (or all rows) of a specific ListView.
|
20
|
+
# Example TextView row: {"id":"title", "text":"My Title", "color":0, "background":0, "compoundDrawables":["left"]}
|
21
|
+
# Example ViewGroup row: {"children":[{"id":"title", "text":"My Title"}, {"id":"subtitle", "text":"Second line"}]}
|
22
|
+
# Example TableLayout row: {"cells":[{"column":0, "id":"colA", "text": "This is a Test"}]}
|
23
|
+
Then /^The "([^\"]*)" for row (\d+) should be "([^\"]*)"$/ do | view_id, row, value |
|
24
|
+
response = performAction( 'get_list_item_properties', '1' , row )['bonusInformation']
|
25
|
+
response = JSON.parse( response[0] )
|
26
|
+
|
27
|
+
if( response['children'] )
|
28
|
+
found_id = false
|
29
|
+
response['children'] each do | view |
|
30
|
+
if( view['id'] == view_id )
|
31
|
+
raise "Text is #{view['text']}, expected #{value}" unless( view['text'] == value )
|
32
|
+
found_id = true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
raise "Could not find view with ID: #{view_id}" unless( found_id )
|
36
|
+
else
|
37
|
+
raise "ID is #{response['id']}, expected #{view_id}" unless( response['id'] == view_id )
|
38
|
+
raise "Text is #{response['text']}, expected #{view_id}" unless( response['text'] == value )
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
When /^I centre the map at (-?\d+\.\d+), (-?\d+\.\d+)$/ do | lat, lon |
|
2
|
+
performAction('set_map_center', lat, lon)
|
3
|
+
end
|
4
|
+
|
5
|
+
When /^I pan the map to (-?\d+\.\d+), (-?\d+\.\d+)$/ do | lat, lon |
|
6
|
+
performAction('pan_map_to', lat, lon)
|
7
|
+
performAction('wait', 1)
|
8
|
+
end
|
9
|
+
|
10
|
+
When /^(?:I )?set the map zoom level to (\d+)$/ do | zoom |
|
11
|
+
performAction('set_map_zoom', zoom)
|
12
|
+
sleep(0.2)
|
13
|
+
end
|
14
|
+
|
15
|
+
When /^(?:I )?zoom (in|out) on the map$/ do | zoom |
|
16
|
+
performAction('set_map_zoom', zoom)
|
17
|
+
sleep(0.2)
|
18
|
+
end
|
19
|
+
|
20
|
+
Then /^the map zoom level should be (\d+)$/ do | zoom |
|
21
|
+
result = performAction('get_map_zoom')
|
22
|
+
raise StandardError.new( "The map's zoom level should be #{zoom} but is #{result['message']}" ) unless zoom.eql?( result['message'] )
|
23
|
+
end
|
24
|
+
|
25
|
+
When /^I tap the map marker "([^\"]*)"$/ do | marker_title |
|
26
|
+
performAction('tap_map_marker_by_title', marker_title, 60000)
|
27
|
+
end
|
28
|
+
|
29
|
+
When /^I double tap the map marker "([^\"]*)"$/ do | marker_title |
|
30
|
+
performAction('tap_map_marker_by_title', marker_title, 60000)
|
31
|
+
sleep(0.4)
|
32
|
+
performAction('tap_map_marker_by_title', marker_title, 100)
|
33
|
+
end
|
34
|
+
|
35
|
+
When /^I tap away from the markers$/ do
|
36
|
+
performAction('tap_map_away_from_markers')
|
37
|
+
end
|
38
|
+
|
39
|
+
Then /^I should see the following markers:$/ do | marker_table |
|
40
|
+
verify_map_markers( marker_table )
|
41
|
+
end
|
42
|
+
|
43
|
+
Then /^the map should be centred at (-?\d+\.\d+), (-?\d+\.\d+)$/ do | lat, lon |
|
44
|
+
result = performAction('get_map_center')
|
45
|
+
bonus_info = result['bonusInformation']
|
46
|
+
actual_lat = bonus_info[0].to_f
|
47
|
+
actual_lon = bonus_info[1].to_f
|
48
|
+
lat = lat.to_f
|
49
|
+
lon = lon.to_f
|
50
|
+
tol = 0.00001
|
51
|
+
if( (lat - actual_lat).abs > tol || (lon - actual_lon).abs > tol )
|
52
|
+
raise StandardError.new( "The map should have been centred on: #{lat},#{lon} but was actually centred on #{bonus_info.inspect}" )
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
Then /^the map marker "([^\"]*)" should be highlighted$/ do | marker_title |
|
57
|
+
result = performAction('get_map_marker', marker_title)
|
58
|
+
result = result['message']
|
59
|
+
result = JSON.parse( result )
|
60
|
+
raise StandardError.new( "The marker '#{marker_title}' was found, but is not highlighted" ) unless result['focused']
|
61
|
+
end
|
@@ -23,10 +23,19 @@ Then /^I select "([^\"]*)" from the menu$/ do |item|
|
|
23
23
|
performAction('select_from_menu', item)
|
24
24
|
end
|
25
25
|
|
26
|
+
Then /^I select tab number (\d+)$/ do | tab |
|
27
|
+
performAction('select_tab', tab)
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param - the "tag" associated with the tab, or the text within the tab label
|
31
|
+
Then /^I select the "([^\"]*)" tab$/ do | tab |
|
32
|
+
performAction('select_tab', tab)
|
33
|
+
end
|
34
|
+
|
26
35
|
Then /^I scroll down$/ do
|
27
36
|
performAction('scroll_down')
|
28
37
|
end
|
29
38
|
|
30
39
|
Then /^I scroll up$/ do
|
31
40
|
performAction('scroll_up')
|
32
|
-
end
|
41
|
+
end
|
@@ -64,3 +64,8 @@ end
|
|
64
64
|
Then /^I wait up to (\d+) seconds for the "([^\"]*)" screen to appear$/ do |timeout, text|
|
65
65
|
performAction('wait_for_screen', text, timeout)
|
66
66
|
end
|
67
|
+
|
68
|
+
# @param - the "tag" associated with the tab, or the text within the tab label
|
69
|
+
Then /^I wait for the "([^\"]*)" tab to appear$/ do | tab |
|
70
|
+
performAction('wait_for_tab', tab)
|
71
|
+
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
<?xml version="1.0" encoding="utf-8"?>
|
2
2
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
3
3
|
package="#TESTED_APP_PACKAGE#.test"
|
4
|
-
android:versionCode="
|
5
|
-
android:versionName="
|
4
|
+
android:versionCode="3"
|
5
|
+
android:versionName="0.3.0">
|
6
6
|
<application android:label="instrumentation_backend">
|
7
|
-
|
8
|
-
|
7
|
+
<uses-library android:name="android.test.runner" />
|
8
|
+
<uses-library android:name="com.google.android.maps" android:required="false" />
|
9
9
|
</application>
|
10
10
|
<uses-sdk android:minSdkVersion="4" />
|
11
11
|
<instrumentation android:targetPackage="#TESTED_APP_PACKAGE#" android:name="sh.calaba.instrumentationbackend.CalabashInstrumentationTestRunner" />
|
12
12
|
<uses-permission android:name="android.permission.INTERNET" />
|
13
|
-
</manifest>
|
13
|
+
</manifest>
|
data/test-server/build.xml
CHANGED
@@ -89,6 +89,10 @@
|
|
89
89
|
<target name="-prepare.testserver" description="Makes sure the testserver matches the tested application by looking at its manifest file">
|
90
90
|
<copy todir="${staging.dir}">
|
91
91
|
<fileset dir="instrumentation-backend"/>
|
92
|
+
</copy>
|
93
|
+
<copy todir="${staging.dir}/libs">
|
94
|
+
<!-- There may be a better way of doing this, but it works -->
|
95
|
+
<fileset dir="${env.ANDROID_HOME}/add-ons/addon-google_apis-google-${android.api.level}/libs"/>
|
92
96
|
</copy>
|
93
97
|
<copy todir="${staging.dir}/assets">
|
94
98
|
<fileset dir="${calabashjs.dir}"/>
|
@@ -0,0 +1 @@
|
|
1
|
+
/bin
|
@@ -1,13 +1,14 @@
|
|
1
1
|
<?xml version="1.0" encoding="utf-8"?>
|
2
2
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
3
3
|
package="sh.calaba.test"
|
4
|
-
android:versionCode="
|
5
|
-
android:versionName="
|
4
|
+
android:versionCode="3"
|
5
|
+
android:versionName="0.3.0" >
|
6
6
|
|
7
7
|
<uses-sdk android:minSdkVersion="6" />
|
8
8
|
|
9
9
|
<application android:label="CalabashTestServer" >
|
10
10
|
<uses-library android:name="android.test.runner" />
|
11
|
+
<uses-library android:name="com.google.android.maps" android:required="false" />
|
11
12
|
</application>
|
12
13
|
|
13
14
|
<instrumentation
|
@@ -18,4 +19,4 @@
|
|
18
19
|
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
|
19
20
|
<uses-permission android:name="android.permission.INTERNET" />
|
20
21
|
|
21
|
-
</manifest>
|
22
|
+
</manifest>
|
data/test-server/instrumentation-backend/src/com/jayway/android/robotium/solo/MapViewUtils.java
ADDED
@@ -0,0 +1,328 @@
|
|
1
|
+
package com.jayway.android.robotium.solo;
|
2
|
+
|
3
|
+
import java.util.ArrayList;
|
4
|
+
import java.util.List;
|
5
|
+
|
6
|
+
import android.app.Instrumentation;
|
7
|
+
import android.graphics.PixelFormat;
|
8
|
+
import android.graphics.Point;
|
9
|
+
import android.graphics.Rect;
|
10
|
+
import android.graphics.Region;
|
11
|
+
import android.os.SystemClock;
|
12
|
+
import android.util.Log;
|
13
|
+
|
14
|
+
import com.google.android.maps.GeoPoint;
|
15
|
+
import com.google.android.maps.ItemizedOverlay;
|
16
|
+
import com.google.android.maps.MapView;
|
17
|
+
import com.google.android.maps.Overlay;
|
18
|
+
import com.google.android.maps.OverlayItem;
|
19
|
+
import com.google.android.maps.Projection;
|
20
|
+
|
21
|
+
/**
|
22
|
+
* @author Nicholas Albion
|
23
|
+
*/
|
24
|
+
public class MapViewUtils {
|
25
|
+
private final Instrumentation inst;
|
26
|
+
private final ViewFetcher viewFetcher;
|
27
|
+
private final Sleeper sleeper;
|
28
|
+
private final Waiter waiter;
|
29
|
+
|
30
|
+
/**
|
31
|
+
* Constructs this object.
|
32
|
+
*
|
33
|
+
* @param inst the {@code Instrumentation} instance.
|
34
|
+
* @param viewFetcher the {@code ViewFetcher} instance.
|
35
|
+
* @param sleeper the {@code Sleeper} instance
|
36
|
+
*/
|
37
|
+
public MapViewUtils( Instrumentation inst, ViewFetcher viewFetcher, Sleeper sleeper, Waiter waiter ) {
|
38
|
+
this.inst = inst;
|
39
|
+
this.viewFetcher = viewFetcher;
|
40
|
+
this.sleeper = sleeper;
|
41
|
+
this.waiter = waiter;
|
42
|
+
}
|
43
|
+
|
44
|
+
private MapView getMapView() {
|
45
|
+
return waiter.waitForAndGetView( 0, MapView.class );
|
46
|
+
// final ArrayList<View> viewList = RobotiumUtils.removeInvisibleViews(viewFetcher.getAllViews(true));
|
47
|
+
// ArrayList<MapView> maps = RobotiumUtils.filterViews( MapView.class, viewList );
|
48
|
+
// if( maps.size() == 0 ) {
|
49
|
+
// return null;
|
50
|
+
// }
|
51
|
+
// return maps.get(0);
|
52
|
+
}
|
53
|
+
|
54
|
+
/**
|
55
|
+
* @param lat
|
56
|
+
* @param lon
|
57
|
+
*/
|
58
|
+
public void setCenter( double lat, double lon ) {
|
59
|
+
MapView mapView = getMapView();
|
60
|
+
mapView.getController().setCenter( new GeoPoint((int)(lat * 1E6), (int)(lon * 1E6)) );
|
61
|
+
}
|
62
|
+
|
63
|
+
public double[] getMapCenter() {
|
64
|
+
MapView mapView = getMapView();
|
65
|
+
GeoPoint center = mapView.getMapCenter();
|
66
|
+
return new double[] { center.getLatitudeE6() / 1E6, center.getLongitudeE6() / 1E6 };
|
67
|
+
}
|
68
|
+
|
69
|
+
/**
|
70
|
+
* @param lat
|
71
|
+
* @param lon
|
72
|
+
*/
|
73
|
+
public void panTo( double lat, double lon ) {
|
74
|
+
MapView mapView = getMapView();
|
75
|
+
mapView.getController().animateTo( new GeoPoint((int)(lat * 1E6), (int)(lon * 1E6)) );
|
76
|
+
}
|
77
|
+
|
78
|
+
public int getZoom() {
|
79
|
+
MapView mapView = getMapView();
|
80
|
+
return mapView.getZoomLevel();
|
81
|
+
}
|
82
|
+
|
83
|
+
public int setZoom( int zoomLevel ) {
|
84
|
+
MapView mapView = getMapView();
|
85
|
+
mapView.getController().stopAnimation(true);
|
86
|
+
return mapView.getController().setZoom( zoomLevel );
|
87
|
+
}
|
88
|
+
|
89
|
+
public boolean zoomIn() {
|
90
|
+
MapView mapView = getMapView();
|
91
|
+
return mapView.getController().zoomIn();
|
92
|
+
}
|
93
|
+
|
94
|
+
public boolean zoomOut() {
|
95
|
+
MapView mapView = getMapView();
|
96
|
+
return mapView.getController().zoomOut();
|
97
|
+
}
|
98
|
+
|
99
|
+
/**
|
100
|
+
* @return [top, right, bottom, left] in decimal degrees
|
101
|
+
*/
|
102
|
+
public List<String> getBounds() {
|
103
|
+
MapView mapView = getMapView();
|
104
|
+
GeoPoint center = mapView.getMapCenter();
|
105
|
+
int latCtr = center.getLatitudeE6();
|
106
|
+
int lonCtr = center.getLongitudeE6();
|
107
|
+
int latSpan = mapView.getLatitudeSpan() >> 1;
|
108
|
+
int lonSpan = mapView.getLongitudeSpan() >> 1;
|
109
|
+
|
110
|
+
Log.i("MapView", "latSpan: " + latSpan);
|
111
|
+
|
112
|
+
ArrayList<String> bounds = new ArrayList<String>(4);
|
113
|
+
bounds.add( Double.toString( (latCtr + latSpan) / 1E6 ) );
|
114
|
+
bounds.add( Double.toString( (lonCtr + lonSpan) / 1E6 ) );
|
115
|
+
bounds.add( Double.toString( (latCtr - latSpan) / 1E6 ) );
|
116
|
+
bounds.add( Double.toString( (lonCtr - lonSpan) / 1E6 ) );
|
117
|
+
return bounds;
|
118
|
+
}
|
119
|
+
|
120
|
+
/**
|
121
|
+
* @return A list of JSON strings representing the markers.
|
122
|
+
* @see #getMarkerItem(String)
|
123
|
+
* @see MapViewUtils#toString(OverlayItem, boolean)
|
124
|
+
*/
|
125
|
+
public List<String> getMarkerItems() {
|
126
|
+
ArrayList<String> markers = new ArrayList<String>();
|
127
|
+
|
128
|
+
MapView mapView = getMapView();
|
129
|
+
for( Overlay overlay : mapView.getOverlays() ) {
|
130
|
+
if( overlay instanceof ItemizedOverlay ) {
|
131
|
+
@SuppressWarnings("rawtypes")
|
132
|
+
ItemizedOverlay markerOverlay = ((ItemizedOverlay)overlay);
|
133
|
+
int noOfMarkers = markerOverlay.size();
|
134
|
+
int lastFocused = markerOverlay.getLastFocusedIndex();
|
135
|
+
|
136
|
+
Log.i("MapView", "Overlay " + markerOverlay + " has " + noOfMarkers + " markers");
|
137
|
+
markers.ensureCapacity( markers.size() + noOfMarkers );
|
138
|
+
for( int i = 0; i < noOfMarkers; i++ ) {
|
139
|
+
OverlayItem item = markerOverlay.getItem(i);
|
140
|
+
String str = toString( item, lastFocused == i );
|
141
|
+
markers.add( str );
|
142
|
+
}
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
Log.i("MapView", "Sending response with " + markers.size() + " markers");
|
147
|
+
return markers;
|
148
|
+
}
|
149
|
+
|
150
|
+
/**
|
151
|
+
* @param title
|
152
|
+
* @return null or (for example) {"latitude":-33.123456, "longitude":151.123456, "title":"My Marker", "snippet":"More Info about my marker"}
|
153
|
+
*/
|
154
|
+
public String getMarkerItem( String title ) {
|
155
|
+
ArrayList<String> markers = new ArrayList<String>();
|
156
|
+
|
157
|
+
MapView mapView = getMapView();
|
158
|
+
for( Overlay overlay : mapView.getOverlays() ) {
|
159
|
+
if( overlay instanceof ItemizedOverlay ) {
|
160
|
+
@SuppressWarnings("rawtypes")
|
161
|
+
ItemizedOverlay markerOverlay = ((ItemizedOverlay)overlay);
|
162
|
+
int noOfMarkers = markerOverlay.size();
|
163
|
+
int lastFocused = markerOverlay.getLastFocusedIndex();
|
164
|
+
|
165
|
+
Log.i("MapView", "Overlay " + markerOverlay + " has " + noOfMarkers + " markers");
|
166
|
+
markers.ensureCapacity( markers.size() + noOfMarkers );
|
167
|
+
for( int i = 0; i < noOfMarkers; i++ ) {
|
168
|
+
OverlayItem item = markerOverlay.getItem(i);
|
169
|
+
|
170
|
+
if( title.equals(item.getTitle()) ) {
|
171
|
+
return toString( item, lastFocused == i );
|
172
|
+
}
|
173
|
+
}
|
174
|
+
}
|
175
|
+
}
|
176
|
+
return null;
|
177
|
+
}
|
178
|
+
|
179
|
+
/**
|
180
|
+
* @param title
|
181
|
+
* @param timeout in ms
|
182
|
+
* @return true if the marker was found and tapped upon
|
183
|
+
*/
|
184
|
+
public boolean tapMarkerItem( String title, long timeout ) {
|
185
|
+
final long endTime = SystemClock.uptimeMillis() + timeout;
|
186
|
+
Log.i("TapMarker", "Looking for marker '" + title + "'");
|
187
|
+
|
188
|
+
while( SystemClock.uptimeMillis() < endTime ) {
|
189
|
+
MapView mapView = getMapView();
|
190
|
+
for( Overlay overlay : mapView.getOverlays() ) {
|
191
|
+
if( overlay instanceof ItemizedOverlay ) {
|
192
|
+
@SuppressWarnings("rawtypes")
|
193
|
+
ItemizedOverlay markerOverlay = ((ItemizedOverlay)overlay);
|
194
|
+
int noOfMarkers = markerOverlay.size();
|
195
|
+
for( int i = 0; i < noOfMarkers; i++ ) {
|
196
|
+
OverlayItem item = markerOverlay.getItem(i);
|
197
|
+
String itemTitle = item.getTitle();
|
198
|
+
// Log.i("TapMarker", " item title: " + itemTitle);
|
199
|
+
if( title.equals( itemTitle ) ) {
|
200
|
+
markerOverlay.onTap( item.getPoint(), mapView );
|
201
|
+
return true;
|
202
|
+
}
|
203
|
+
}
|
204
|
+
}
|
205
|
+
}
|
206
|
+
|
207
|
+
Log.i("TapMarker", "Could not find marker '" + title + "', try again in a moment");
|
208
|
+
sleeper.sleep();
|
209
|
+
}
|
210
|
+
|
211
|
+
Log.i("TapMarker", "Nope, could not find marker '" + title + "'");
|
212
|
+
return false;
|
213
|
+
}
|
214
|
+
|
215
|
+
/**
|
216
|
+
* @param step - number of pixels to step when searching for an empty piece of screen
|
217
|
+
* @return true if it was possible to tap on the screen without tapping on a marker
|
218
|
+
*/
|
219
|
+
@SuppressWarnings("rawtypes")
|
220
|
+
public boolean tapAwayFromMarkerItems( int step ) {
|
221
|
+
MapView mapView = getMapView();
|
222
|
+
Projection proj = mapView.getProjection();
|
223
|
+
ItemizedOverlay overlayToTap = null;
|
224
|
+
Point markerPoint = new Point();
|
225
|
+
int w = mapView.getWidth();
|
226
|
+
int h = mapView.getHeight();
|
227
|
+
|
228
|
+
for( int x = 0; x < w; x += step ) {
|
229
|
+
NEXT_Y:
|
230
|
+
for( int y = 0; y < h; y += step ) {
|
231
|
+
boolean tappedMarkerAtPoint = false;
|
232
|
+
for( Overlay overlay : mapView.getOverlays() ) {
|
233
|
+
if( overlay instanceof ItemizedOverlay ) {
|
234
|
+
ItemizedOverlay markerOverlay = ((ItemizedOverlay)overlay);
|
235
|
+
// if( markerOverlay.onTap( geoPoint, mapView ) ) {
|
236
|
+
// tappedMarkerAtPoint = true;
|
237
|
+
// break;
|
238
|
+
// }
|
239
|
+
int noOfMarkers = markerOverlay.size();
|
240
|
+
for( int i = 0; i < noOfMarkers; i++ ) {
|
241
|
+
OverlayItem item = markerOverlay.getItem(i);
|
242
|
+
proj.toPixels( item.getPoint(), markerPoint );
|
243
|
+
Rect markerBounds = item.getMarker(0).getBounds();
|
244
|
+
markerBounds.offset( markerPoint.x, markerPoint.y );
|
245
|
+
|
246
|
+
Log.d("TapAwayFromMarkers", "markerBounds: " + markerBounds);
|
247
|
+
if( markerBounds.contains(x, y) ) {
|
248
|
+
Log.d("TapAwayFromMarkers", "Tapping at " + x + ", " + y + " would tap on " + item.getTitle());
|
249
|
+
continue NEXT_Y;
|
250
|
+
}
|
251
|
+
}
|
252
|
+
overlayToTap = markerOverlay;
|
253
|
+
}
|
254
|
+
}
|
255
|
+
|
256
|
+
if( tappedMarkerAtPoint == false && overlayToTap != null ) {
|
257
|
+
Log.i("TapAwayFromMarkers", "Tapping away from markers at " + x + ", " + y);
|
258
|
+
GeoPoint geoPoint = proj.fromPixels(x, y);
|
259
|
+
overlayToTap.onTap(geoPoint, mapView);
|
260
|
+
return true;
|
261
|
+
}
|
262
|
+
}
|
263
|
+
}
|
264
|
+
|
265
|
+
Log.i("TapMarker", "Nope, could not avoid tapping on any markers");
|
266
|
+
return false;
|
267
|
+
}
|
268
|
+
|
269
|
+
/**
|
270
|
+
* @param item
|
271
|
+
* @param isLastFocused
|
272
|
+
* @return eg: {"latitude":-33.123456, "longitude":151.123456, "title":"My Marker", "snippet":"More Info about my marker"}
|
273
|
+
*/
|
274
|
+
private String toString( OverlayItem item, boolean isLastFocused ) {
|
275
|
+
GeoPoint point = item.getPoint();
|
276
|
+
StringBuilder str = new StringBuilder("{\"latitude\":\"").append(Double.toString( point.getLatitudeE6() / 1E6 ))
|
277
|
+
.append("\", \"longitude\":\"").append( Double.toString( point.getLongitudeE6() / 1E6 ))
|
278
|
+
.append("\", \"title\":\"").append( item.getTitle().replaceAll("\"", "\\\"") );
|
279
|
+
String snippet = item.getSnippet();
|
280
|
+
if( snippet != null && snippet.length() != 0 ) {
|
281
|
+
str.append("\", \"snippet\":\"").append( snippet.replaceAll("\"", "\\\"") );
|
282
|
+
}
|
283
|
+
if( isLastFocused ) {
|
284
|
+
str.append("\", \"focused\":true");
|
285
|
+
} else {
|
286
|
+
str.append("\"");
|
287
|
+
}
|
288
|
+
|
289
|
+
appendTransparency( str, item );
|
290
|
+
|
291
|
+
str.append("}");
|
292
|
+
return str.toString();
|
293
|
+
}
|
294
|
+
|
295
|
+
private void appendTransparency( StringBuilder str, OverlayItem item ) {
|
296
|
+
StringBuilder transparencyStr = new StringBuilder();
|
297
|
+
appendTransparency( transparencyStr, item, "default", 0 );
|
298
|
+
appendTransparency( transparencyStr, item, "focused", OverlayItem.ITEM_STATE_FOCUSED_MASK );
|
299
|
+
appendTransparency( transparencyStr, item, "pressed", OverlayItem.ITEM_STATE_PRESSED_MASK );
|
300
|
+
appendTransparency( transparencyStr, item, "selected", OverlayItem.ITEM_STATE_SELECTED_MASK );
|
301
|
+
|
302
|
+
if( transparencyStr.length() != 0 ) {
|
303
|
+
transparencyStr.deleteCharAt( transparencyStr.length() - 1 );
|
304
|
+
str.append(", \"transparency\":{").append(transparencyStr).append("}");
|
305
|
+
}
|
306
|
+
}
|
307
|
+
|
308
|
+
private void appendTransparency( StringBuilder str, OverlayItem item, String stateName, int state ) {
|
309
|
+
switch( item.getMarker( OverlayItem.ITEM_STATE_FOCUSED_MASK ).getOpacity() ) {
|
310
|
+
case PixelFormat.UNKNOWN: break;
|
311
|
+
case PixelFormat.TRANSPARENT:
|
312
|
+
str.append("\"").append(stateName).append("\":\"transparent\",");
|
313
|
+
return;
|
314
|
+
case PixelFormat.TRANSLUCENT:
|
315
|
+
str.append("\"").append(stateName).append("\":\"translucent\",");
|
316
|
+
return;
|
317
|
+
case PixelFormat.OPAQUE:
|
318
|
+
str.append("\"").append(stateName).append("\":\"opaque\",");
|
319
|
+
return;
|
320
|
+
}
|
321
|
+
|
322
|
+
|
323
|
+
Region region = item.getMarker(state).getTransparentRegion();
|
324
|
+
if( region != null ) {
|
325
|
+
str.append("\"").append(stateName).append("\":true,");
|
326
|
+
}
|
327
|
+
}
|
328
|
+
}
|