Added OsmAndCore-sample
13
OsmAndCore-sample/.gitignore
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# Android Studio
|
||||||
|
/.idea
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
|
||||||
|
# MacOSX
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Output
|
||||||
|
/build
|
24
OsmAndCore-sample/AndroidManifest.xml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="net.osmand.core.samples.android.sample1" >
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:icon="@mipmap/sample_app"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/AppTheme">
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity"
|
||||||
|
android:label="@string/title_activity_main">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
92
OsmAndCore-sample/build.gradle
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 23
|
||||||
|
buildToolsVersion "23.0.3"
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion 14
|
||||||
|
targetSdkVersion 23
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
}
|
||||||
|
|
||||||
|
lintOptions {
|
||||||
|
abortOnError false
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is from OsmAndCore_android.aar - for some reason it's not inherited
|
||||||
|
aaptOptions {
|
||||||
|
// Don't compress any embedded resources
|
||||||
|
noCompress "qz"
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
main {
|
||||||
|
manifest.srcFile "AndroidManifest.xml"
|
||||||
|
jni.srcDirs = []
|
||||||
|
jniLibs.srcDirs = ["libs"]
|
||||||
|
java.srcDirs = ["src"]
|
||||||
|
resources.srcDirs = ["src"]
|
||||||
|
renderscript.srcDirs = ["src"]
|
||||||
|
res.srcDirs = ["res"]
|
||||||
|
assets.srcDirs = ["assets"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
productFlavors {
|
||||||
|
x86 {
|
||||||
|
ndk {
|
||||||
|
abiFilter "x86"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mips {
|
||||||
|
ndk {
|
||||||
|
abiFilter "mips"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
armv7 {
|
||||||
|
ndk {
|
||||||
|
abiFilter "armeabi-v7a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
armv5 {
|
||||||
|
ndk {
|
||||||
|
abiFilter "armeabi"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fat
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
debug {
|
||||||
|
signingConfig android.signingConfigs.debug
|
||||||
|
}
|
||||||
|
nativeDebug {
|
||||||
|
signingConfig android.signingConfigs.debug
|
||||||
|
}
|
||||||
|
release {
|
||||||
|
signingConfig android.signingConfigs.debug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
ivy {
|
||||||
|
name = "OsmAndBinariesIvy"
|
||||||
|
url = "http://builder.osmand.net"
|
||||||
|
layout "pattern" , {
|
||||||
|
artifact "ivy/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile project(path: ':OsmAnd-java', configuration: 'android')
|
||||||
|
compile 'com.android.support:appcompat-v7:23.3.0'
|
||||||
|
compile fileTree(dir: "libs", include: ["*.jar"])
|
||||||
|
compile "net.osmand:OsmAndCore_android:0.1-SNAPSHOT@aar"
|
||||||
|
debugCompile "net.osmand:OsmAndCore_androidNativeRelease:0.1-SNAPSHOT@aar"
|
||||||
|
nativeDebugCompile "net.osmand:OsmAndCore_androidNativeDebug:0.1-SNAPSHOT@aar"
|
||||||
|
releaseCompile "net.osmand:OsmAndCore_androidNativeRelease:0.1-SNAPSHOT@aar"
|
||||||
|
}
|
BIN
OsmAndCore-sample/res/drawable-hdpi/bg_contextmenu_shadow.9.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
OsmAndCore-sample/res/drawable-hdpi/ic_action_remove_dark.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
OsmAndCore-sample/res/drawable-hdpi/map_bt_round_1_shadow.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
OsmAndCore-sample/res/drawable-hdpi/map_compass_niu.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
OsmAndCore-sample/res/drawable-hdpi/map_zoom_in.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
OsmAndCore-sample/res/drawable-hdpi/map_zoom_out.png
Normal file
After Width: | Height: | Size: 1 KiB |
BIN
OsmAndCore-sample/res/drawable-mdpi/bg_contextmenu_shadow.9.png
Normal file
After Width: | Height: | Size: 1 KiB |
BIN
OsmAndCore-sample/res/drawable-mdpi/ic_action_remove_dark.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
OsmAndCore-sample/res/drawable-mdpi/map_bt_round_1_shadow.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
OsmAndCore-sample/res/drawable-mdpi/map_compass_niu.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
OsmAndCore-sample/res/drawable-mdpi/map_zoom_in.png
Normal file
After Width: | Height: | Size: 1 KiB |
BIN
OsmAndCore-sample/res/drawable-mdpi/map_zoom_out.png
Normal file
After Width: | Height: | Size: 1 KiB |
BIN
OsmAndCore-sample/res/drawable-xhdpi/bg_contextmenu_shadow.9.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
OsmAndCore-sample/res/drawable-xhdpi/ic_action_remove_dark.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
OsmAndCore-sample/res/drawable-xhdpi/map_bt_round_1_shadow.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
OsmAndCore-sample/res/drawable-xhdpi/map_compass_niu.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
OsmAndCore-sample/res/drawable-xhdpi/map_zoom_in.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
OsmAndCore-sample/res/drawable-xhdpi/map_zoom_out.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.1 KiB |
BIN
OsmAndCore-sample/res/drawable-xxhdpi/ic_action_remove_dark.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
OsmAndCore-sample/res/drawable-xxhdpi/map_bt_round_1_shadow.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
OsmAndCore-sample/res/drawable-xxhdpi/map_compass_niu.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
OsmAndCore-sample/res/drawable-xxhdpi/map_zoom_in.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
OsmAndCore-sample/res/drawable-xxhdpi/map_zoom_out.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
5
OsmAndCore-sample/res/drawable/btn_circle.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@drawable/btn_circle_p" android:state_pressed="true"/>
|
||||||
|
<item android:drawable="@drawable/btn_circle_n"></item>
|
||||||
|
</selector>
|
22
OsmAndCore-sample/res/drawable/btn_circle_n.xml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<bitmap
|
||||||
|
android:gravity="fill"
|
||||||
|
android:src="@drawable/map_bt_round_1_shadow" />
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
|
||||||
|
<inset
|
||||||
|
android:insetBottom="2dp"
|
||||||
|
android:insetLeft="2dp"
|
||||||
|
android:insetRight="2dp"
|
||||||
|
android:insetTop="2dp" >
|
||||||
|
<shape android:shape="oval" >
|
||||||
|
<solid android:color="#fff" />
|
||||||
|
</shape>
|
||||||
|
</inset>
|
||||||
|
</item>
|
||||||
|
|
||||||
|
</layer-list>
|
21
OsmAndCore-sample/res/drawable/btn_circle_p.xml
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||||
|
|
||||||
|
<item>
|
||||||
|
<bitmap
|
||||||
|
android:gravity="fill"
|
||||||
|
android:src="@drawable/map_bt_round_1_shadow" />
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
|
||||||
|
<inset
|
||||||
|
android:insetBottom="2dp"
|
||||||
|
android:insetLeft="2dp"
|
||||||
|
android:insetRight="2dp"
|
||||||
|
android:insetTop="2dp" >
|
||||||
|
<shape android:shape="oval" >
|
||||||
|
<solid android:color="#fff" />
|
||||||
|
</shape>
|
||||||
|
</inset>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
120
OsmAndCore-sample/res/layout/activity_main.xml
Executable file
|
@ -0,0 +1,120 @@
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:context="net.osmand.core.samples.android.sample1.MainActivity">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/clearButton"
|
||||||
|
style="@style/Widget.AppCompat.ActionButton"
|
||||||
|
android:layout_width="48dp"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:contentDescription="@string/shared_string_close"
|
||||||
|
android:src="@drawable/ic_action_remove_dark"/>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/searchEditText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginLeft="16dp"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="@string/search_hint"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:lines="1"
|
||||||
|
android:textColor="@color/titleTextColor"
|
||||||
|
tools:text="Search request"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:foreground="@drawable/bg_contextmenu_shadow"
|
||||||
|
android:foregroundGravity="top|fill_horizontal">
|
||||||
|
|
||||||
|
<net.osmand.core.android.AtlasMapRendererView
|
||||||
|
android:id="@+id/mapRendererView"
|
||||||
|
android:focusable="true"
|
||||||
|
android:focusableInTouchMode="true"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"/>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="top|right"
|
||||||
|
android:layout_marginRight="10dp"
|
||||||
|
android:layout_marginTop="10dp">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/map_azimuth_north_button"
|
||||||
|
android:layout_width="52dp"
|
||||||
|
android:layout_height="52dp"
|
||||||
|
android:background="@drawable/btn_circle"
|
||||||
|
android:contentDescription="@string/azimuthNorth"
|
||||||
|
android:src="@drawable/map_compass_niu"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|right"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:layout_marginRight="10dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_zoom"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:text="10"
|
||||||
|
android:textColor="#000"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textStyle="bold"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/map_zoom_in_button"
|
||||||
|
android:layout_width="52dp"
|
||||||
|
android:layout_height="52dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:background="@drawable/btn_circle"
|
||||||
|
android:contentDescription="@string/zoomIn"
|
||||||
|
android:src="@drawable/map_zoom_in"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/map_zoom_out_button"
|
||||||
|
android:layout_width="52dp"
|
||||||
|
android:layout_height="52dp"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:background="@drawable/btn_circle"
|
||||||
|
android:contentDescription="@string/zoomOut"
|
||||||
|
android:src="@drawable/map_zoom_out"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<ListView
|
||||||
|
android:id="@android:id/list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:drawSelectorOnTop="true"
|
||||||
|
android:background="@color/listBackgroundColor"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
58
OsmAndCore-sample/res/layout/search_list_item.xml
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="?attr/listPreferredItemHeight"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingBottom="12dp"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:paddingTop="8dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imageView"
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
|
||||||
|
tools:text="Amsterdam"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/distance"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="right"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
tools:text="100 km"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/subtitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||||
|
tools:text="City"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
BIN
OsmAndCore-sample/res/mipmap-hdpi/sample_app.png
Executable file
After Width: | Height: | Size: 8 KiB |
BIN
OsmAndCore-sample/res/mipmap-mdpi/sample_app.png
Executable file
After Width: | Height: | Size: 4.8 KiB |
BIN
OsmAndCore-sample/res/mipmap-xhdpi/sample_app.png
Executable file
After Width: | Height: | Size: 11 KiB |
BIN
OsmAndCore-sample/res/mipmap-xxhdpi/sample_app.png
Executable file
After Width: | Height: | Size: 21 KiB |
BIN
OsmAndCore-sample/res/mipmap-xxxhdpi/sample_app.png
Executable file
After Width: | Height: | Size: 41 KiB |
6
OsmAndCore-sample/res/values-w820dp/dimens.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<resources>
|
||||||
|
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
|
||||||
|
(such as screen margins) for screens with more than 820dp of available width. This
|
||||||
|
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
|
||||||
|
<dimen name="activity_horizontal_margin">64dp</dimen>
|
||||||
|
</resources>
|
17
OsmAndCore-sample/res/values/colors.xml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="colorPrimary">#ff8f00</color>
|
||||||
|
<color name="colorPrimaryDark">#e68200</color>
|
||||||
|
<color name="colorAccent">#FF4081</color>
|
||||||
|
|
||||||
|
<color name="dividerColor">#F0F0F0</color>
|
||||||
|
<color name="windowBackgroundColor">#EAEAEA</color>
|
||||||
|
<color name="itemBackgroundColor">#FFF</color>
|
||||||
|
<color name="iconColor">#727272</color>
|
||||||
|
<color name="dialogTitleBackgroundColor">#2f7af5</color>
|
||||||
|
|
||||||
|
<color name="listBackgroundColor">#EAEAEA</color>
|
||||||
|
<color name="titleTextColor">#FFF</color>
|
||||||
|
<color name="listTextColor">#000</color>
|
||||||
|
|
||||||
|
</resources>
|
6
OsmAndCore-sample/res/values/dimens.xml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<resources>
|
||||||
|
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||||
|
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||||
|
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||||
|
<dimen name="list_content_padding">16dp</dimen>
|
||||||
|
</resources>
|
10
OsmAndCore-sample/res/values/strings.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">OsmAnd Core API sample 1 for Android OS</string>
|
||||||
|
<string name="title_activity_main">OsmAnd Core Sample 1</string>
|
||||||
|
<string name="zoomIn">Zoom in</string>
|
||||||
|
<string name="zoomOut">Zoom out</string>
|
||||||
|
<string name="azimuthNorth">Azimuth to North</string>
|
||||||
|
<string name="search_hint">Type and Search</string>
|
||||||
|
<string name="shared_string_close">Close</string>
|
||||||
|
</resources>
|
11
OsmAndCore-sample/res/values/styles.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<resources>
|
||||||
|
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||||
|
<item name="colorPrimary">@color/colorPrimary</item>
|
||||||
|
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||||
|
<item name="colorAccent">@color/colorAccent</item>
|
||||||
|
|
||||||
|
<item name="android:windowBackground">@color/windowBackgroundColor</item>
|
||||||
|
<item name="android:colorBackground">@color/windowBackgroundColor</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</resources>
|
|
@ -0,0 +1,546 @@
|
||||||
|
package net.osmand.core.samples.android.sample1;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.content.SharedPreferences.Editor;
|
||||||
|
import android.graphics.PointF;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.support.v4.view.ViewCompat;
|
||||||
|
import android.support.v4.view.ViewPropertyAnimatorListener;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.text.TextWatcher;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.GestureDetector;
|
||||||
|
import android.view.GestureDetector.SimpleOnGestureListener;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ListView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import net.osmand.core.android.AtlasMapRendererView;
|
||||||
|
import net.osmand.core.android.CoreResourcesFromAndroidAssets;
|
||||||
|
import net.osmand.core.android.NativeCore;
|
||||||
|
import net.osmand.core.jni.AreaI;
|
||||||
|
import net.osmand.core.jni.IMapLayerProvider;
|
||||||
|
import net.osmand.core.jni.IMapStylesCollection;
|
||||||
|
import net.osmand.core.jni.LatLon;
|
||||||
|
import net.osmand.core.jni.LogSeverityLevel;
|
||||||
|
import net.osmand.core.jni.Logger;
|
||||||
|
import net.osmand.core.jni.MapObjectsSymbolsProvider;
|
||||||
|
import net.osmand.core.jni.MapPresentationEnvironment;
|
||||||
|
import net.osmand.core.jni.MapPrimitivesProvider;
|
||||||
|
import net.osmand.core.jni.MapPrimitiviser;
|
||||||
|
import net.osmand.core.jni.MapRasterLayerProvider_Software;
|
||||||
|
import net.osmand.core.jni.MapStylesCollection;
|
||||||
|
import net.osmand.core.jni.ObfMapObjectsProvider;
|
||||||
|
import net.osmand.core.jni.ObfsCollection;
|
||||||
|
import net.osmand.core.jni.PointI;
|
||||||
|
import net.osmand.core.jni.QIODeviceLogSink;
|
||||||
|
import net.osmand.core.jni.ResolvedMapStyle;
|
||||||
|
import net.osmand.core.jni.Utilities;
|
||||||
|
import net.osmand.core.samples.android.sample1.MultiTouchSupport.MultiTouchZoomListener;
|
||||||
|
import net.osmand.core.samples.android.sample1.SearchAPI.SearchAPICallback;
|
||||||
|
import net.osmand.core.samples.android.sample1.SearchAPI.SearchItem;
|
||||||
|
import net.osmand.core.samples.android.sample1.SearchUIHelper.SearchListAdapter;
|
||||||
|
import net.osmand.core.samples.android.sample1.SearchUIHelper.SearchRow;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class MainActivity extends Activity {
|
||||||
|
private static final String TAG = "OsmAndCoreSample";
|
||||||
|
|
||||||
|
private float displayDensityFactor;
|
||||||
|
private int referenceTileSize;
|
||||||
|
private int rasterTileSize;
|
||||||
|
private IMapStylesCollection mapStylesCollection;
|
||||||
|
private ResolvedMapStyle mapStyle;
|
||||||
|
private ObfsCollection obfsCollection;
|
||||||
|
private MapPresentationEnvironment mapPresentationEnvironment;
|
||||||
|
private MapPrimitiviser mapPrimitiviser;
|
||||||
|
private ObfMapObjectsProvider obfMapObjectsProvider;
|
||||||
|
private MapPrimitivesProvider mapPrimitivesProvider;
|
||||||
|
private MapObjectsSymbolsProvider mapObjectsSymbolsProvider;
|
||||||
|
private IMapLayerProvider mapLayerProvider0;
|
||||||
|
private IMapLayerProvider mapLayerProvider1;
|
||||||
|
private QIODeviceLogSink fileLogSink;
|
||||||
|
|
||||||
|
private AtlasMapRendererView mapView;
|
||||||
|
private TextView textZoom;
|
||||||
|
private ImageButton azimuthNorthButton;
|
||||||
|
|
||||||
|
private GestureDetector gestureDetector;
|
||||||
|
private PointI target31;
|
||||||
|
private float zoom;
|
||||||
|
private float azimuth;
|
||||||
|
private float elevationAngle;
|
||||||
|
private MultiTouchSupport multiTouchSupport;
|
||||||
|
|
||||||
|
private SearchAPI searchAPI;
|
||||||
|
private ListView searchListView;
|
||||||
|
private SearchListAdapter adapter;
|
||||||
|
private final static int MAX_SEARCH_RESULTS = 50;
|
||||||
|
|
||||||
|
// Germany
|
||||||
|
private final static float INIT_LAT = 49.353953f;
|
||||||
|
private final static float INIT_LON = 11.214384f;
|
||||||
|
// Kyiv
|
||||||
|
//private final static float INIT_LAT = 50.450117f;
|
||||||
|
//private final static float INIT_LON = 30.524142f;
|
||||||
|
private final static float INIT_ZOOM = 6.0f;
|
||||||
|
private final static float INIT_AZIMUTH = 0.0f;
|
||||||
|
private final static float INIT_ELEVATION_ANGLE = 90.0f;
|
||||||
|
private final static int MIN_ZOOM_LEVEL = 2;
|
||||||
|
private final static int MAX_ZOOM_LEVEL = 22;
|
||||||
|
|
||||||
|
private static final String PREF_MAP_CENTER_LAT = "MAP_CENTER_LAT";
|
||||||
|
private static final String PREF_MAP_CENTER_LON = "MAP_CENTER_LON";
|
||||||
|
private static final String PREF_MAP_AZIMUTH = "MAP_AZIMUTH";
|
||||||
|
private static final String PREF_MAP_ZOOM = "MAP_ZOOM";
|
||||||
|
private static final String PREF_MAP_ELEVATION_ANGLE = "MAP_ELEVATION_ANGLE";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
gestureDetector = new GestureDetector(this, new MapViewOnGestureListener());
|
||||||
|
multiTouchSupport = new MultiTouchSupport(this, new MapViewMultiTouchZoomListener());
|
||||||
|
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// Initialize native core prior (if needed)
|
||||||
|
if (NativeCore.isAvailable() && !NativeCore.isLoaded())
|
||||||
|
NativeCore.load(CoreResourcesFromAndroidAssets.loadFromCurrentApplication(this));
|
||||||
|
|
||||||
|
Logger.get().setSeverityLevelThreshold(LogSeverityLevel.Debug);
|
||||||
|
|
||||||
|
// Inflate views
|
||||||
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
|
// Get map view
|
||||||
|
mapView = (AtlasMapRendererView) findViewById(R.id.mapRendererView);
|
||||||
|
|
||||||
|
textZoom = (TextView) findViewById(R.id.text_zoom);
|
||||||
|
azimuthNorthButton = (ImageButton) findViewById(R.id.map_azimuth_north_button);
|
||||||
|
|
||||||
|
azimuthNorthButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
setAzimuth(0f);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
findViewById(R.id.map_zoom_in_button).setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
setZoom(zoom + 1f);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
findViewById(R.id.map_zoom_out_button).setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
setZoom(zoom - 1f);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Additional log sink
|
||||||
|
fileLogSink = QIODeviceLogSink.createFileLogSink(
|
||||||
|
Environment.getExternalStorageDirectory() + "/osmand/osmandcore.log");
|
||||||
|
Logger.get().addLogSink(fileLogSink);
|
||||||
|
|
||||||
|
// Get device display density factor
|
||||||
|
DisplayMetrics displayMetrics = new DisplayMetrics();
|
||||||
|
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
|
||||||
|
displayDensityFactor = displayMetrics.densityDpi / 160.0f;
|
||||||
|
referenceTileSize = (int)(256 * displayDensityFactor);
|
||||||
|
rasterTileSize = Integer.highestOneBit(referenceTileSize - 1) * 2;
|
||||||
|
Log.i(TAG, "displayDensityFactor = " + displayDensityFactor);
|
||||||
|
Log.i(TAG, "referenceTileSize = " + referenceTileSize);
|
||||||
|
Log.i(TAG, "rasterTileSize = " + rasterTileSize);
|
||||||
|
|
||||||
|
Log.i(TAG, "Going to resolve default embedded style...");
|
||||||
|
mapStylesCollection = new MapStylesCollection();
|
||||||
|
mapStyle = mapStylesCollection.getResolvedStyleByName("default");
|
||||||
|
if (mapStyle == null)
|
||||||
|
{
|
||||||
|
Log.e(TAG, "Failed to resolve style 'default'");
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(TAG, "Going to prepare OBFs collection");
|
||||||
|
obfsCollection = new ObfsCollection();
|
||||||
|
Log.i(TAG, "Will load OBFs from " + Environment.getExternalStorageDirectory() + "/osmand");
|
||||||
|
obfsCollection.addDirectory(Environment.getExternalStorageDirectory() + "/osmand", false);
|
||||||
|
|
||||||
|
Log.i(TAG, "Going to prepare all resources for renderer");
|
||||||
|
mapPresentationEnvironment = new MapPresentationEnvironment(
|
||||||
|
mapStyle,
|
||||||
|
displayDensityFactor,
|
||||||
|
1.0f,
|
||||||
|
1.0f,
|
||||||
|
MapUtils.LANGUAGE);
|
||||||
|
//mapPresentationEnvironment->setSettings(configuration.styleSettings);
|
||||||
|
mapPrimitiviser = new MapPrimitiviser(
|
||||||
|
mapPresentationEnvironment);
|
||||||
|
obfMapObjectsProvider = new ObfMapObjectsProvider(
|
||||||
|
obfsCollection);
|
||||||
|
mapPrimitivesProvider = new MapPrimitivesProvider(
|
||||||
|
obfMapObjectsProvider,
|
||||||
|
mapPrimitiviser,
|
||||||
|
rasterTileSize);
|
||||||
|
mapObjectsSymbolsProvider = new MapObjectsSymbolsProvider(
|
||||||
|
mapPrimitivesProvider,
|
||||||
|
rasterTileSize);
|
||||||
|
|
||||||
|
mapView.setReferenceTileSizeOnScreenInPixels(referenceTileSize);
|
||||||
|
mapView.addSymbolsProvider(mapObjectsSymbolsProvider);
|
||||||
|
|
||||||
|
restoreMapState();
|
||||||
|
|
||||||
|
mapLayerProvider0 = new MapRasterLayerProvider_Software(mapPrimitivesProvider);
|
||||||
|
mapView.setMapLayerProvider(0, mapLayerProvider0);
|
||||||
|
|
||||||
|
System.out.println("NATIVE_INITIALIZED = " + (System.currentTimeMillis() - startTime) / 1000f);
|
||||||
|
|
||||||
|
//Setup search
|
||||||
|
|
||||||
|
searchAPI = new SearchAPI(obfsCollection);
|
||||||
|
|
||||||
|
final EditText searchEditText = (EditText) findViewById(R.id.searchEditText);
|
||||||
|
searchEditText.addTextChangedListener(new TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable s) {
|
||||||
|
if (s.length() > 2) {
|
||||||
|
runSearch(getScreenBounds31(), s.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
searchEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
|
||||||
|
@Override
|
||||||
|
public void onFocusChange(View v, boolean hasFocus) {
|
||||||
|
if (hasFocus && adapter.getCount() > 0 && isSearchListHidden()) {
|
||||||
|
showSearchList();
|
||||||
|
LatLon latLon = Utilities.convert31ToLatLon(target31);
|
||||||
|
adapter.updateDistance(latLon.getLatitude(), latLon.getLongitude());
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ImageButton clearButton = (ImageButton) findViewById(R.id.clearButton);
|
||||||
|
clearButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
searchEditText.setText("");
|
||||||
|
adapter.clear();
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
hideSearchList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
searchListView = (ListView) findViewById(android.R.id.list);
|
||||||
|
adapter = new SearchListAdapter(this);
|
||||||
|
searchListView.setAdapter(adapter);
|
||||||
|
searchListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
|
hideSearchList();
|
||||||
|
mapView.requestFocus();
|
||||||
|
SearchRow item = adapter.getItem(position);
|
||||||
|
PointI target = Utilities.convertLatLonTo31(new LatLon(item.getLatitude(), item.getLongitude()));
|
||||||
|
setTarget(target);
|
||||||
|
setZoom(17f);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
mapView.handleOnResume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
saveMapState();
|
||||||
|
mapView.handleOnPause();
|
||||||
|
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
mapView.handleOnDestroy();
|
||||||
|
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AreaI getScreenBounds31() {
|
||||||
|
PointI topLeftPoint = new PointI();
|
||||||
|
PointI bottomRightPoint = new PointI();
|
||||||
|
mapView.getLocationFromScreenPoint(new PointI(0, 0), topLeftPoint);
|
||||||
|
mapView.getLocationFromScreenPoint(new PointI(mapView.getWidth(), mapView.getHeight()), bottomRightPoint);
|
||||||
|
return new AreaI(topLeftPoint, bottomRightPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSearchListHidden() {
|
||||||
|
return searchListView.getVisibility() != View.VISIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showSearchList() {
|
||||||
|
if (isSearchListHidden()) {
|
||||||
|
ViewCompat.setAlpha(searchListView, 0f);
|
||||||
|
searchListView.setVisibility(View.VISIBLE);
|
||||||
|
ViewCompat.animate(searchListView).alpha(1f).setListener(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hideSearchList() {
|
||||||
|
ViewCompat.animate(searchListView).alpha(0f).setListener(new ViewPropertyAnimatorListener() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationStart(View view) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(View view) {
|
||||||
|
searchListView.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationCancel(View view) {
|
||||||
|
searchListView.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void saveMapState() {
|
||||||
|
SharedPreferences prefs = getPreferences(MODE_PRIVATE);
|
||||||
|
Editor edit = prefs.edit();
|
||||||
|
LatLon latLon = Utilities.convert31ToLatLon(target31);
|
||||||
|
edit.putFloat(PREF_MAP_CENTER_LAT, (float)latLon.getLatitude());
|
||||||
|
edit.putFloat(PREF_MAP_CENTER_LON, (float)latLon.getLongitude());
|
||||||
|
edit.putFloat(PREF_MAP_AZIMUTH, azimuth);
|
||||||
|
edit.putFloat(PREF_MAP_ZOOM, zoom);
|
||||||
|
edit.putFloat(PREF_MAP_ELEVATION_ANGLE, elevationAngle);
|
||||||
|
edit.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restoreMapState() {
|
||||||
|
SharedPreferences prefs = getPreferences(MODE_PRIVATE);
|
||||||
|
float prefLat = prefs.getFloat(PREF_MAP_CENTER_LAT, INIT_LAT);
|
||||||
|
float prefLon = prefs.getFloat(PREF_MAP_CENTER_LON, INIT_LON);
|
||||||
|
float prefAzimuth = prefs.getFloat(PREF_MAP_AZIMUTH, INIT_AZIMUTH);
|
||||||
|
float prefZoom = prefs.getFloat(PREF_MAP_ZOOM, INIT_ZOOM);
|
||||||
|
float prefElevationAngle = prefs.getFloat(PREF_MAP_ELEVATION_ANGLE, INIT_ELEVATION_ANGLE);
|
||||||
|
|
||||||
|
setAzimuth(prefAzimuth);
|
||||||
|
setElevationAngle(prefElevationAngle);
|
||||||
|
setTarget(Utilities.convertLatLonTo31(new LatLon(prefLat, prefLon)));
|
||||||
|
setZoom(prefZoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean setTarget(PointI pointI) {
|
||||||
|
target31 = pointI;
|
||||||
|
return mapView.setTarget(pointI);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("DefaultLocale")
|
||||||
|
public boolean setZoom(float zoom) {
|
||||||
|
if (zoom < MIN_ZOOM_LEVEL) {
|
||||||
|
zoom = MIN_ZOOM_LEVEL;
|
||||||
|
} else if (zoom > MAX_ZOOM_LEVEL) {
|
||||||
|
zoom = MAX_ZOOM_LEVEL;
|
||||||
|
}
|
||||||
|
this.zoom = zoom;
|
||||||
|
textZoom.setText(String.format("%.0f", zoom));
|
||||||
|
return mapView.setZoom(zoom);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAzimuth(float angle) {
|
||||||
|
angle = MapUtils.unifyRotationTo360(angle);
|
||||||
|
this.azimuth = angle;
|
||||||
|
mapView.setAzimuth(angle);
|
||||||
|
|
||||||
|
if (angle == 0f && azimuthNorthButton.getVisibility() == View.VISIBLE) {
|
||||||
|
azimuthNorthButton.setVisibility(View.INVISIBLE);
|
||||||
|
} else if (angle != 0f && azimuthNorthButton.getVisibility() == View.INVISIBLE) {
|
||||||
|
azimuthNorthButton.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setElevationAngle(float angle) {
|
||||||
|
if (angle < 35f) {
|
||||||
|
angle = 35f;
|
||||||
|
} else if (angle > 90f) {
|
||||||
|
angle = 90f;
|
||||||
|
}
|
||||||
|
this.elevationAngle = angle;
|
||||||
|
mapView.setElevationAngle(angle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onTouchEvent(MotionEvent event) {
|
||||||
|
return multiTouchSupport.onTouchEvent(event)
|
||||||
|
|| gestureDetector.onTouchEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runSearch(AreaI bounds31, String keyword) {
|
||||||
|
|
||||||
|
searchAPI.setObfAreaFilter(bounds31);
|
||||||
|
searchAPI.startSearch(keyword, MAX_SEARCH_RESULTS, new SearchAPICallback() {
|
||||||
|
@Override
|
||||||
|
public void onSearchFinished(List<SearchItem> searchItems, boolean cancelled) {
|
||||||
|
if (searchItems != null && !cancelled) {
|
||||||
|
LatLon latLon = Utilities.convert31ToLatLon(target31);
|
||||||
|
List<SearchRow> rows = new ArrayList<>();
|
||||||
|
for (SearchItem item : searchItems) {
|
||||||
|
SearchRow row = new SearchRow(item);
|
||||||
|
rows.add(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
adapter.clear();
|
||||||
|
adapter.addAll(rows);
|
||||||
|
adapter.updateDistance(latLon.getLatitude(), latLon.getLongitude());
|
||||||
|
adapter.sort(new Comparator<SearchRow>() {
|
||||||
|
@Override
|
||||||
|
public int compare(SearchRow lhs, SearchRow rhs) {
|
||||||
|
int res = Double.compare(lhs.getDistance(), rhs.getDistance());
|
||||||
|
if (res == 0) {
|
||||||
|
return lhs.getSearchItem().getLocalizedName().compareToIgnoreCase(rhs.getSearchItem().getLocalizedName());
|
||||||
|
} else {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
if (adapter.getCount() > 0) {
|
||||||
|
searchListView.setSelection(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
showSearchList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MapViewOnGestureListener extends SimpleOnGestureListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onSingleTapUp(MotionEvent e) {
|
||||||
|
mapView.requestFocus();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||||
|
float fromX = e2.getX() + distanceX;
|
||||||
|
float fromY = e2.getY() + distanceY;
|
||||||
|
float toX = e2.getX();
|
||||||
|
float toY = e2.getY();
|
||||||
|
|
||||||
|
float dx = (fromX - toX);
|
||||||
|
float dy = (fromY - toY);
|
||||||
|
|
||||||
|
PointI newTarget = new PointI();
|
||||||
|
mapView.getLocationFromScreenPoint(new PointI(mapView.getWidth() / 2 + (int)dx, mapView.getHeight() / 2 + (int)dy), newTarget);
|
||||||
|
|
||||||
|
setTarget(newTarget);
|
||||||
|
|
||||||
|
mapView.requestFocus();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MapViewMultiTouchZoomListener implements MultiTouchZoomListener {
|
||||||
|
|
||||||
|
private float initialZoom;
|
||||||
|
private float initialAzimuth;
|
||||||
|
private float initialElevation;
|
||||||
|
private PointF centerPoint;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onGestureFinished(float scale, float rotation) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onGestureInit(float x1, float y1, float x2, float y2) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onZoomStarted(PointF centerPoint) {
|
||||||
|
initialZoom = zoom;
|
||||||
|
initialAzimuth = azimuth;
|
||||||
|
this.centerPoint = centerPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onZoomingOrRotating(float scale, float rotation) {
|
||||||
|
|
||||||
|
PointI centerLocationBefore = new PointI();
|
||||||
|
mapView.getLocationFromScreenPoint(
|
||||||
|
new PointI((int)centerPoint.x, (int)centerPoint.y), centerLocationBefore);
|
||||||
|
|
||||||
|
// Change zoom
|
||||||
|
setZoom(initialZoom + (float)(Math.log(scale) / Math.log(2)));
|
||||||
|
|
||||||
|
// Adjust current target position to keep touch center the same
|
||||||
|
PointI centerLocationAfter = new PointI();
|
||||||
|
mapView.getLocationFromScreenPoint(
|
||||||
|
new PointI((int)centerPoint.x, (int)centerPoint.y), centerLocationAfter);
|
||||||
|
PointI centerLocationDelta = new PointI(
|
||||||
|
centerLocationAfter.getX() - centerLocationBefore.getX(),
|
||||||
|
centerLocationAfter.getY() - centerLocationBefore.getY());
|
||||||
|
|
||||||
|
setTarget(new PointI(target31.getX() - centerLocationDelta.getX(), target31.getY() - centerLocationDelta.getY()));
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Convert point from screen to location
|
||||||
|
PointI centerLocation = new PointI();
|
||||||
|
mapView.getLocationFromScreenPoint(
|
||||||
|
new PointI((int)centerPoint.x, (int)centerPoint.y), centerLocation);
|
||||||
|
|
||||||
|
// Rotate current target around center location
|
||||||
|
PointI target = new PointI(xI - centerLocation.getX(), yI - centerLocation.getY());
|
||||||
|
double cosAngle = Math.cos(-Math.toRadians(rotation));
|
||||||
|
double sinAngle = Math.sin(-Math.toRadians(rotation));
|
||||||
|
|
||||||
|
PointI newTarget = new PointI(
|
||||||
|
(int)(target.getX() * cosAngle - target.getY() * sinAngle + centerLocation.getX()),
|
||||||
|
(int)(target.getX() * sinAngle + target.getY() * cosAngle + centerLocation.getY()));
|
||||||
|
|
||||||
|
setTarget(newTarget);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Set rotation
|
||||||
|
setAzimuth(initialAzimuth - rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChangeViewAngleStarted() {
|
||||||
|
initialElevation = elevationAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChangingViewAngle(float angle) {
|
||||||
|
setElevationAngle(initialElevation - angle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package net.osmand.core.samples.android.sample1;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class MapUtils {
|
||||||
|
|
||||||
|
public static final String LANGUAGE;
|
||||||
|
|
||||||
|
static {
|
||||||
|
LANGUAGE = getLanguage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float unifyRotationTo360(float rotate) {
|
||||||
|
while (rotate < -180) {
|
||||||
|
rotate += 360;
|
||||||
|
}
|
||||||
|
while (rotate > +180) {
|
||||||
|
rotate -= 360;
|
||||||
|
}
|
||||||
|
return rotate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getLanguage() {
|
||||||
|
String langCode = Locale.getDefault().getLanguage();
|
||||||
|
if (langCode.isEmpty()) {
|
||||||
|
langCode = "en";
|
||||||
|
}
|
||||||
|
return langCode;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,202 @@
|
||||||
|
package net.osmand.core.samples.android.sample1;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.PointF;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
public class MultiTouchSupport {
|
||||||
|
|
||||||
|
private static final String TAG = "MultiTouchSupport";
|
||||||
|
|
||||||
|
public static final int ACTION_MASK = 255;
|
||||||
|
protected final Context ctx;
|
||||||
|
private final MultiTouchZoomListener listener;
|
||||||
|
protected Method getPointerCount;
|
||||||
|
protected Method getX;
|
||||||
|
protected Method getY;
|
||||||
|
protected Method getPointerId;
|
||||||
|
|
||||||
|
private float initialAngle;
|
||||||
|
private float rotation;
|
||||||
|
private static final float ROTATION_THRESHOLD_DEG = 15.0f;
|
||||||
|
private boolean isRotating;
|
||||||
|
|
||||||
|
private boolean multiTouchAPISupported = false;
|
||||||
|
|
||||||
|
private boolean inTiltMode = false;
|
||||||
|
private PointF firstFingerStart = new PointF();
|
||||||
|
private PointF secondFingerStart = new PointF();
|
||||||
|
private static final int TILT_X_THRESHOLD_PX = 40;
|
||||||
|
private static final int TILT_Y_THRESHOLD_PX = 40;
|
||||||
|
private static final int TILT_DY_THRESHOLD_PX = 40;
|
||||||
|
|
||||||
|
private boolean inZoomMode = false;
|
||||||
|
private float initialDistance = 100;
|
||||||
|
private float scale = 1;
|
||||||
|
private PointF centerPoint = new PointF();
|
||||||
|
|
||||||
|
private boolean multiTouch;
|
||||||
|
|
||||||
|
public MultiTouchSupport(Context ctx, MultiTouchZoomListener listener) {
|
||||||
|
this.ctx = ctx;
|
||||||
|
this.listener = listener;
|
||||||
|
initMethods();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMultiTouchSupported(){
|
||||||
|
return multiTouchAPISupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInZoomMode(){
|
||||||
|
return inZoomMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInTiltMode() {
|
||||||
|
return inTiltMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initMethods() {
|
||||||
|
try {
|
||||||
|
getPointerCount = MotionEvent.class.getMethod("getPointerCount"); //$NON-NLS-1$
|
||||||
|
getPointerId = MotionEvent.class.getMethod("getPointerId", Integer.TYPE); //$NON-NLS-1$
|
||||||
|
getX = MotionEvent.class.getMethod("getX", Integer.TYPE); //$NON-NLS-1$
|
||||||
|
getY = MotionEvent.class.getMethod("getY", Integer.TYPE); //$NON-NLS-1$
|
||||||
|
multiTouchAPISupported = true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
multiTouchAPISupported = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onTouchEvent(MotionEvent event){
|
||||||
|
if(!isMultiTouchSupported()){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int actionCode = event.getAction() & ACTION_MASK;
|
||||||
|
try {
|
||||||
|
if (actionCode == MotionEvent.ACTION_UP || actionCode == MotionEvent.ACTION_CANCEL) {
|
||||||
|
multiTouch = false;
|
||||||
|
}
|
||||||
|
Integer pointCount = (Integer) getPointerCount.invoke(event);
|
||||||
|
if (pointCount < 2) {
|
||||||
|
if (inZoomMode || inTiltMode) {
|
||||||
|
listener.onGestureFinished(scale, rotation);
|
||||||
|
inZoomMode = false;
|
||||||
|
inTiltMode = false;
|
||||||
|
}
|
||||||
|
return multiTouch;
|
||||||
|
} else {
|
||||||
|
multiTouch = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Float x1 = (Float) getX.invoke(event, 0);
|
||||||
|
Float x2 = (Float) getX.invoke(event, 1);
|
||||||
|
Float y1 = (Float) getY.invoke(event, 0);
|
||||||
|
Float y2 = (Float) getY.invoke(event, 1);
|
||||||
|
float distance = (float) Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
|
||||||
|
float angle = 0;
|
||||||
|
boolean angleDefined = false;
|
||||||
|
if (x1.floatValue() != x2.floatValue() || y1.floatValue() != y2.floatValue()) {
|
||||||
|
angleDefined = true;
|
||||||
|
angle = (float) (Math.atan2(y2 - y1, x2 -x1) * 180 / Math.PI);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (actionCode) {
|
||||||
|
|
||||||
|
case MotionEvent.ACTION_POINTER_DOWN: {
|
||||||
|
|
||||||
|
centerPoint = new PointF((x1 + x2) / 2, (y1 + y2) / 2);
|
||||||
|
firstFingerStart = new PointF(x1, y1);
|
||||||
|
secondFingerStart = new PointF(x2, y2);
|
||||||
|
listener.onGestureInit(x1, y1, x2, y2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case MotionEvent.ACTION_POINTER_UP: {
|
||||||
|
|
||||||
|
if (inZoomMode || inTiltMode) {
|
||||||
|
listener.onGestureFinished(scale, rotation);
|
||||||
|
inZoomMode = false;
|
||||||
|
inTiltMode = false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case MotionEvent.ACTION_MOVE: {
|
||||||
|
|
||||||
|
if (inZoomMode) {
|
||||||
|
if (angleDefined) {
|
||||||
|
float a = MapUtils.unifyRotationTo360(angle - initialAngle);
|
||||||
|
if (!isRotating && Math.abs(a) > ROTATION_THRESHOLD_DEG) {
|
||||||
|
isRotating = true;
|
||||||
|
initialAngle = angle;
|
||||||
|
} else if (isRotating) {
|
||||||
|
rotation = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scale = distance / initialDistance;
|
||||||
|
|
||||||
|
listener.onZoomingOrRotating(scale, rotation);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (inTiltMode) {
|
||||||
|
float dy2 = secondFingerStart.y - y2;
|
||||||
|
float viewAngle = dy2 / 8f;
|
||||||
|
listener.onChangingViewAngle(viewAngle);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
float dx1 = Math.abs(firstFingerStart.x - x1);
|
||||||
|
float dx2 = Math.abs(secondFingerStart.x - x2);
|
||||||
|
float dy1 = Math.abs(firstFingerStart.y - y1);
|
||||||
|
float dy2 = Math.abs(secondFingerStart.y - y2);
|
||||||
|
float startDy = Math.abs(secondFingerStart.y - firstFingerStart.y);
|
||||||
|
if (dx1 < TILT_X_THRESHOLD_PX && dx2 < TILT_X_THRESHOLD_PX
|
||||||
|
&& dy1 > TILT_Y_THRESHOLD_PX && dy2 > TILT_Y_THRESHOLD_PX
|
||||||
|
&& startDy < TILT_Y_THRESHOLD_PX * 6
|
||||||
|
&& Math.abs(dy2 - dy1) < TILT_DY_THRESHOLD_PX) {
|
||||||
|
listener.onChangeViewAngleStarted();
|
||||||
|
inTiltMode = true;
|
||||||
|
|
||||||
|
} else if (dx1 > TILT_X_THRESHOLD_PX || dx2 > TILT_X_THRESHOLD_PX
|
||||||
|
|| Math.abs(dy2 - dy1) > TILT_DY_THRESHOLD_PX
|
||||||
|
|| Math.abs(dy1 - dy2) > TILT_DY_THRESHOLD_PX) {
|
||||||
|
listener.onZoomStarted(centerPoint);
|
||||||
|
initialDistance = distance;
|
||||||
|
initialAngle = angle;
|
||||||
|
rotation = 0;
|
||||||
|
scale = 0;
|
||||||
|
isRotating = false;
|
||||||
|
inZoomMode = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Multi touch exception" , e); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PointF getCenterPoint() {
|
||||||
|
return centerPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface MultiTouchZoomListener {
|
||||||
|
|
||||||
|
void onZoomStarted(PointF centerPoint);
|
||||||
|
|
||||||
|
void onZoomingOrRotating(float scale, float rotation);
|
||||||
|
|
||||||
|
void onChangeViewAngleStarted();
|
||||||
|
|
||||||
|
void onChangingViewAngle(float angle);
|
||||||
|
|
||||||
|
void onGestureFinished(float scale, float rotation);
|
||||||
|
|
||||||
|
void onGestureInit(float x1, float y1, float x2, float y2);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,306 @@
|
||||||
|
package net.osmand.core.samples.android.sample1;
|
||||||
|
|
||||||
|
import android.os.AsyncTask;
|
||||||
|
|
||||||
|
import net.osmand.core.jni.AmenitiesByNameSearch;
|
||||||
|
import net.osmand.core.jni.Amenity;
|
||||||
|
import net.osmand.core.jni.Amenity.DecodedCategory;
|
||||||
|
import net.osmand.core.jni.AreaI;
|
||||||
|
import net.osmand.core.jni.DecodedCategoryList;
|
||||||
|
import net.osmand.core.jni.IObfsCollection;
|
||||||
|
import net.osmand.core.jni.IQueryController;
|
||||||
|
import net.osmand.core.jni.ISearch;
|
||||||
|
import net.osmand.core.jni.LatLon;
|
||||||
|
import net.osmand.core.jni.NullableAreaI;
|
||||||
|
import net.osmand.core.jni.ObfInfo;
|
||||||
|
import net.osmand.core.jni.ObfsCollection;
|
||||||
|
import net.osmand.core.jni.PointI;
|
||||||
|
import net.osmand.core.jni.QStringStringHash;
|
||||||
|
import net.osmand.core.jni.Utilities;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SearchAPI {
|
||||||
|
|
||||||
|
private ObfsCollection obfsCollection;
|
||||||
|
private AreaI searchableArea;
|
||||||
|
private AreaI obfAreaFilter;
|
||||||
|
private SearchRequestExecutor executor;
|
||||||
|
|
||||||
|
interface SearchAPICallback {
|
||||||
|
void onSearchFinished(List<SearchItem> searchItems, boolean cancelled);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SearchAPI(ObfsCollection obfsCollection) {
|
||||||
|
this.obfsCollection = obfsCollection;
|
||||||
|
executor = new SearchRequestExecutor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AreaI getSearchableArea() {
|
||||||
|
return searchableArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSearchableArea(AreaI searchableArea) {
|
||||||
|
this.searchableArea = searchableArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AreaI getObfAreaFilter() {
|
||||||
|
return obfAreaFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setObfAreaFilter(AreaI obfAreaFilter) {
|
||||||
|
this.obfAreaFilter = obfAreaFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startSearch(String keyword, int maxSearchResults, SearchAPICallback apiCallback) {
|
||||||
|
executor.run(new SearchRequest(keyword, maxSearchResults, apiCallback), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancelSearch() {
|
||||||
|
executor.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class SearchRequestExecutor {
|
||||||
|
|
||||||
|
private SearchRequest ongoingSearchRequest;
|
||||||
|
private SearchRequest nextSearchRequest;
|
||||||
|
|
||||||
|
public void run(SearchRequest searchRequest, boolean cancelCurrentRequest) {
|
||||||
|
if (ongoingSearchRequest != null) {
|
||||||
|
nextSearchRequest = searchRequest;
|
||||||
|
if (cancelCurrentRequest) {
|
||||||
|
ongoingSearchRequest.cancel();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ongoingSearchRequest = searchRequest;
|
||||||
|
nextSearchRequest = null;
|
||||||
|
searchRequest.setOnFinishedCallback(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
operationFinished();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
searchRequest.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancel() {
|
||||||
|
if (nextSearchRequest != null) {
|
||||||
|
nextSearchRequest = null;
|
||||||
|
}
|
||||||
|
if (ongoingSearchRequest != null) {
|
||||||
|
ongoingSearchRequest.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void operationFinished() {
|
||||||
|
ongoingSearchRequest = null;
|
||||||
|
if (nextSearchRequest != null) {
|
||||||
|
run(nextSearchRequest, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SearchRequest {
|
||||||
|
private String keyword;
|
||||||
|
private int maxSearchResults;
|
||||||
|
private Runnable onFinished;
|
||||||
|
private SearchAPICallback apiCallback;
|
||||||
|
|
||||||
|
private boolean cancelled;
|
||||||
|
private int resCount;
|
||||||
|
|
||||||
|
public SearchRequest(String keyword, int maxSearchResults, SearchAPICallback apiCallback) {
|
||||||
|
this.keyword = keyword;
|
||||||
|
this.maxSearchResults = maxSearchResults;
|
||||||
|
this.apiCallback = apiCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
new AsyncTask<String, Void, List<SearchItem>>() {
|
||||||
|
@Override
|
||||||
|
protected List<SearchItem> doInBackground(String... params) {
|
||||||
|
return doSearch(params[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPostExecute(List<SearchItem> searchItems) {
|
||||||
|
|
||||||
|
if (onFinished != null) {
|
||||||
|
onFinished.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apiCallback != null) {
|
||||||
|
apiCallback.onSearchFinished(searchItems, cancelled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute(keyword);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<SearchItem> doSearch(String keyword) {
|
||||||
|
System.out.println("=== Start search");
|
||||||
|
resCount = 0;
|
||||||
|
|
||||||
|
final List<SearchItem> searchItems = new ArrayList<>();
|
||||||
|
|
||||||
|
AmenitiesByNameSearch byNameSearch = new AmenitiesByNameSearch(obfsCollection);
|
||||||
|
AmenitiesByNameSearch.Criteria criteria = new AmenitiesByNameSearch.Criteria();
|
||||||
|
criteria.setName(keyword);
|
||||||
|
if (obfAreaFilter != null) {
|
||||||
|
criteria.setObfInfoAreaFilter(new NullableAreaI(new AreaI(obfAreaFilter)));
|
||||||
|
}
|
||||||
|
|
||||||
|
ISearch.INewResultEntryCallback newResultEntryCallback = new ISearch.INewResultEntryCallback() {
|
||||||
|
@Override
|
||||||
|
public void method(ISearch.Criteria criteria, ISearch.IResultEntry resultEntry) {
|
||||||
|
Amenity amenity = new ResultEntry(resultEntry).getAmenity();
|
||||||
|
searchItems.add(new AmenitySearchItem(amenity));
|
||||||
|
System.out.println("Poi found === " + amenity.getNativeName());
|
||||||
|
resCount++;
|
||||||
|
/*
|
||||||
|
QStringStringHash locNames = amenity.getLocalizedNames();
|
||||||
|
if (locNames.size() > 0) {
|
||||||
|
QStringList keys = locNames.keys();
|
||||||
|
StringBuilder sb = new StringBuilder("=== Localized names: ");
|
||||||
|
for (int i = 0; i < keys.size(); i++) {
|
||||||
|
String key = keys.get(i);
|
||||||
|
sb.append(key).append("=").append(locNames.get(key)).append(" | ");
|
||||||
|
}
|
||||||
|
System.out.println(sb.toString());
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
byNameSearch.performSearch(criteria, newResultEntryCallback.getBinding(), new IQueryController() {
|
||||||
|
@Override
|
||||||
|
public boolean isAborted() {
|
||||||
|
return resCount >= maxSearchResults || cancelled;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
System.out.println("=== Finish search");
|
||||||
|
|
||||||
|
return searchItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancel() {
|
||||||
|
cancelled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnFinishedCallback(Runnable onFinished) {
|
||||||
|
this.onFinished = onFinished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ResultEntry extends AmenitiesByNameSearch.ResultEntry {
|
||||||
|
protected ResultEntry(ISearch.IResultEntry resultEntry) {
|
||||||
|
super(ISearch.IResultEntry.getCPtr(resultEntry), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static abstract class SearchItem {
|
||||||
|
|
||||||
|
protected double latitude;
|
||||||
|
protected double longitude;
|
||||||
|
|
||||||
|
public SearchItem(double latitude, double longitude) {
|
||||||
|
this.latitude = latitude;
|
||||||
|
this.longitude = longitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SearchItem(PointI location31) {
|
||||||
|
LatLon latLon = Utilities.convert31ToLatLon(location31);
|
||||||
|
latitude = latLon.getLatitude();
|
||||||
|
longitude = latLon.getLongitude();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract String getNativeName();
|
||||||
|
|
||||||
|
public abstract String getLocalizedName();
|
||||||
|
|
||||||
|
public abstract String getTypeName();
|
||||||
|
|
||||||
|
public abstract String getSubTypeName();
|
||||||
|
|
||||||
|
public double getLatitude() {
|
||||||
|
return latitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLongitude() {
|
||||||
|
return longitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getNativeName() + " {lat:" + getLatitude() + " lon: " + getLongitude() + "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AmenitySearchItem extends SearchItem {
|
||||||
|
|
||||||
|
private String nativeName;
|
||||||
|
private String localizedName;
|
||||||
|
private String category;
|
||||||
|
private String subcategory;
|
||||||
|
|
||||||
|
public AmenitySearchItem(Amenity amenity) {
|
||||||
|
super(amenity.getPosition31());
|
||||||
|
|
||||||
|
nativeName = amenity.getNativeName();
|
||||||
|
QStringStringHash locNames = amenity.getLocalizedNames();
|
||||||
|
if (locNames.has_key(MapUtils.LANGUAGE)) {
|
||||||
|
localizedName = locNames.get(MapUtils.LANGUAGE);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
if (locNames.size() > 0) {
|
||||||
|
QStringList keys = locNames.keys();
|
||||||
|
for (int i = 0; i < keys.size(); i++) {
|
||||||
|
String key = keys.get(i);
|
||||||
|
localizedNamesMap.put(key, locNames.get(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
DecodedCategoryList catList = amenity.getDecodedCategories();
|
||||||
|
if (catList.size() > 0) {
|
||||||
|
DecodedCategory decodedCategory = catList.get(0);
|
||||||
|
category = decodedCategory.getCategory();
|
||||||
|
subcategory = decodedCategory.getSubcategory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNativeName() {
|
||||||
|
return nativeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLocalizedName() {
|
||||||
|
return localizedName != null ? localizedName : nativeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getTypeName() {
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSubTypeName() {
|
||||||
|
return subcategory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getLatitude() {
|
||||||
|
return latitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getLongitude() {
|
||||||
|
return longitude;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,139 @@
|
||||||
|
package net.osmand.core.samples.android.sample1;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import net.osmand.core.jni.Utilities;
|
||||||
|
import net.osmand.core.samples.android.sample1.SearchAPI.SearchItem;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
|
||||||
|
public class SearchUIHelper {
|
||||||
|
|
||||||
|
public static Drawable getIcon(Context ctx, SearchItem item) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SearchRow {
|
||||||
|
|
||||||
|
private SearchItem searchItem;
|
||||||
|
private double distance;
|
||||||
|
|
||||||
|
public SearchRow(SearchItem searchItem) {
|
||||||
|
this.searchItem = searchItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SearchItem getSearchItem() {
|
||||||
|
return searchItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLatitude() {
|
||||||
|
return searchItem.getLatitude();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLongitude() {
|
||||||
|
return searchItem.getLongitude();
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getDistance() {
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDistance(double distance) {
|
||||||
|
this.distance = distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SearchListAdapter extends ArrayAdapter<SearchRow> {
|
||||||
|
|
||||||
|
private Context ctx;
|
||||||
|
|
||||||
|
public SearchListAdapter(Context ctx) {
|
||||||
|
super(ctx, R.layout.search_list_item);
|
||||||
|
this.ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateDistance(double latitude, double longitude) {
|
||||||
|
for (int i = 0; i < getCount(); i++) {
|
||||||
|
SearchRow item = getItem(i);
|
||||||
|
item.setDistance(Utilities.distance(
|
||||||
|
longitude, latitude,
|
||||||
|
item.getLongitude(), item.getLatitude()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
SearchRow item = getItem(position);
|
||||||
|
|
||||||
|
LinearLayout view;
|
||||||
|
if (convertView == null) {
|
||||||
|
LayoutInflater inflater = (LayoutInflater) ctx
|
||||||
|
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
view = (LinearLayout) inflater.inflate(
|
||||||
|
R.layout.search_list_item, null);
|
||||||
|
} else {
|
||||||
|
view = (LinearLayout) convertView;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView title = (TextView) view.findViewById(R.id.title);
|
||||||
|
TextView subtitle = (TextView) view.findViewById(R.id.subtitle);
|
||||||
|
TextView distance = (TextView) view.findViewById(R.id.distance);
|
||||||
|
title.setText(item.searchItem.getLocalizedName());
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (!item.searchItem.getSubTypeName().isEmpty()) {
|
||||||
|
sb.append(getNiceString(item.searchItem.getSubTypeName()));
|
||||||
|
}
|
||||||
|
if (!item.searchItem.getTypeName().isEmpty()) {
|
||||||
|
if (sb.length() > 0) {
|
||||||
|
sb.append(" — ");
|
||||||
|
}
|
||||||
|
sb.append(getNiceString(item.searchItem.getTypeName()));
|
||||||
|
}
|
||||||
|
subtitle.setText(sb.toString());
|
||||||
|
if (item.getDistance() == 0) {
|
||||||
|
distance.setText("");
|
||||||
|
} else {
|
||||||
|
distance.setText(getFormattedDistance(item.getDistance()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//text1.setTextColor(ctx.getResources().getColor(R.color.listTextColor));
|
||||||
|
//view.setCompoundDrawablesWithIntrinsicBounds(getIcon(ctx, item), null, null, null);
|
||||||
|
//view.setCompoundDrawablePadding(ctx.getResources().getDimensionPixelSize(R.dimen.list_content_padding));
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String capitalizeFirstLetterAndLowercase(String s) {
|
||||||
|
if (s != null && s.length() > 1) {
|
||||||
|
// not very efficient algorithm
|
||||||
|
return Character.toUpperCase(s.charAt(0)) + s.substring(1).toLowerCase();
|
||||||
|
} else {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getNiceString(String s) {
|
||||||
|
return capitalizeFirstLetterAndLowercase(s.replaceAll("_", " "));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getFormattedDistance(double meters) {
|
||||||
|
double mainUnitInMeters = 1000;
|
||||||
|
String mainUnitStr = "km";
|
||||||
|
if (meters >= 100 * mainUnitInMeters) {
|
||||||
|
return (int) (meters / mainUnitInMeters + 0.5) + " " + mainUnitStr;
|
||||||
|
} else if (meters > 9.99f * mainUnitInMeters) {
|
||||||
|
return MessageFormat.format("{0,number,#.#} " + mainUnitStr, ((float) meters) / mainUnitInMeters).replace('\n', ' ');
|
||||||
|
} else if (meters > 0.999f * mainUnitInMeters) {
|
||||||
|
return MessageFormat.format("{0,number,#.##} " + mainUnitStr, ((float) meters) / mainUnitInMeters).replace('\n', ' ');
|
||||||
|
} else {
|
||||||
|
return ((int) (meters + 0.5)) + " m";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
include ':OsmAnd-java'
|
include ':OsmAnd-java', ':OsmAndCore-sample'
|
||||||
include ':OsmAnd'
|
include ':OsmAnd'
|
||||||
include ':plugins:OsmAnd-AddressPlugin'
|
include ':plugins:OsmAnd-AddressPlugin'
|
||||||
include ':plugins:Osmand-ParkingPlugin'
|
include ':plugins:Osmand-ParkingPlugin'
|
||||||
|
|