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.
- 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
|
+
}
|